diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index 69b990b6a..6d63e11c6 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -54,7 +54,7 @@ jobs: if: steps.changed-files.outputs.all shell: bash working-directory: ${{ inputs.working-directory }} - run: poetry lock --check + run: poetry check --lock - name: Install dependencies if: steps.changed-files.outputs.all diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 3329da546..64dfacd51 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -39,6 +39,12 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_RO_TOKEN }} + - name: Check Lock + shell: bash + working-directory: ${{ inputs.working-directory }} + run: | + poetry check --lock + - name: Install dependencies shell: bash working-directory: ${{ inputs.working-directory }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ffc77649..9bed24785 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,7 @@ jobs: - 'libs/checkpoint-sqlite/**' - 'libs/checkpoint-postgres/**' - 'libs/scheduler-kafka/**' + - 'libs/prebuilt/**' sdk-js: - 'libs/sdk-js/**' @@ -56,6 +57,7 @@ jobs: "libs/checkpoint-sqlite", "libs/checkpoint-postgres", "libs/scheduler-kafka", + "libs/prebuilt", ] if: needs.changes.outputs.python == 'true' uses: ./.github/workflows/_lint.yml @@ -74,6 +76,7 @@ jobs: "libs/checkpoint", "libs/checkpoint-sqlite", "libs/checkpoint-postgres", + "libs/prebuilt", ] if: needs.changes.outputs.python == 'true' uses: ./.github/workflows/_test.yml @@ -111,6 +114,42 @@ jobs: - name: Run check_sdk_methods script run: python .github/scripts/check_sdk_methods.py + check-schema: + needs: changes + if: needs.changes.outputs.python == 'true' + name: "Check CLI schema hasn't changed #${{ matrix.python-version }}" + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - "3.11" + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }} + uses: "./.github/actions/poetry_setup" + with: + python-version: "3.11" + poetry-version: ${{ env.POETRY_VERSION }} + cache-key: schema-check-cli + - name: Install CLI dependencies + run: | + cd libs/cli + poetry install + - 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 + # 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." + diff schemas/schema.json schemas/schema.current.json + exit 1 + fi + echo "Schema check passed - no changes detected" + integration-test: needs: changes if: needs.changes.outputs.python == 'true' @@ -177,6 +216,8 @@ jobs: test, test-langgraph, test-scheduler-kafka, + check-sdk-methods, + check-schema, integration-test, test-js, ] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1d5b2aaf..c93db70a3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -195,7 +195,11 @@ jobs: "$PKG_NAME==$VERSION" \ ) - if [[ "$PKG_NAME" == *checkpoint* ]]; then + if [[ "$PKG_NAME" == *prebuilt* ]]; then + poetry run pip install langgraph + fi + + if [[ "$PKG_NAME" == *checkpoint* || "$PKG_NAME" == *prebuilt* ]]; then # since checkpoint packages are namespace packages, import them with . convention # i.e. import langgraph.checkpoint or langgraph.checkpoint.sqlite IMPORT_NAME="$(echo "$PKG_NAME" | sed s/-/./g)" diff --git a/README.md b/README.md index 01c1330cf..f656b962d 100644 --- a/README.md +++ b/README.md @@ -1,339 +1,81 @@ # 🦜🕸️LangGraph -![Version](https://img.shields.io/pypi/v/langgraph) +[![Version](https://img.shields.io/pypi/v/langgraph.svg)](https://pypi.org/project/langgraph/) [![Downloads](https://static.pepy.tech/badge/langgraph/month)](https://pepy.tech/project/langgraph) [![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/) -⚡ Building language agents as graphs ⚡ - > [!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/). -## Overview +LangGraph — used by Replit, Uber, LinkedIn, GitLab and more — is a low-level orchestration framework for building controllable agents. While langchain provides integrations and composable components to streamline LLM application development, the LangGraph library enables agent orchestration — offering customizable architectures, long-term memory, and human-in-the-loop to reliably handle complex tasks. -[LangGraph](https://langchain-ai.github.io/langgraph/) is a library for building -stateful, multi-actor applications with LLMs, used to create agent and multi-agent -workflows. Check out an introductory tutorial [here](https://langchain-ai.github.io/langgraph/tutorials/introduction/). - - -LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain. - -### Why use LangGraph? - -LangGraph powers [production-grade agents](https://www.langchain.com/built-with-langgraph), trusted by Linkedin, Uber, Klarna, GitLab, and many more. LangGraph provides fine-grained control over both the flow and state of your agent applications. It implements a central [persistence layer](https://langchain-ai.github.io/langgraph/concepts/persistence/), enabling features that are common to most agent architectures: - -- **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**: Because state is checkpointed, execution can be interrupted -and resumed, allowing for decisions, validation, and corrections at key stages via -human input. - -Standardizing these components allows individuals and teams to focus on the behavior -of their agent, instead of its supporting infrastructure. - -Through [LangGraph Platform](#langgraph-platform), LangGraph also provides tooling for -the development, deployment, debugging, and monitoring of your applications. - -LangGraph integrates seamlessly with -[LangChain](https://python.langchain.com/docs/introduction/) and -[LangSmith](https://docs.smith.langchain.com/) (but does not require them). - -To learn more about LangGraph, check out our first LangChain Academy -course, *Introduction to LangGraph*, available for free -[here](https://academy.langchain.com/courses/intro-to-langgraph). - -### LangGraph Platform - -[LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform) is infrastructure for deploying LangGraph agents. It is a commercial solution for deploying agentic applications to production, built on the open-source LangGraph framework. The LangGraph Platform consists of several components that work together to support the development, deployment, debugging, and monitoring of LangGraph applications: [LangGraph Server](https://langchain-ai.github.io/langgraph/concepts/langgraph_server) (APIs), [LangGraph SDKs](https://langchain-ai.github.io/langgraph/concepts/sdk) (clients for the APIs), [LangGraph CLI](https://langchain-ai.github.io/langgraph/concepts/langgraph_cli) (command line tool for building the server), and [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio) (UI/debugger). - -See deployment options [here](https://langchain-ai.github.io/langgraph/concepts/deployment_options/) -(includes a free tier). - -Here are some common issues that arise in complex deployments, which LangGraph Platform addresses: - -- **Streaming support**: LangGraph Server provides [multiple streaming modes](https://langchain-ai.github.io/langgraph/concepts/streaming) optimized for various application needs -- **Background runs**: Runs agents asynchronously in the background -- **Support for long running agents**: Infrastructure that can handle long running processes -- **[Double texting](https://langchain-ai.github.io/langgraph/concepts/double_texting)**: Handle the case where you get two messages from the user before the agent can respond -- **Handle burstiness**: Task queue for ensuring requests are handled consistently without loss, even under heavy loads - -## Installation - -```shell +```bash pip install -U langgraph ``` -## Example - -Let's build a tool-calling [ReAct-style](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-implementation) agent that uses a search tool! - -```shell -pip install langchain-anthropic -``` - -```shell -export ANTHROPIC_API_KEY=sk-... -``` - -Optionally, we can set up [LangSmith](https://docs.smith.langchain.com/) for best-in-class observability. - -```shell -export LANGSMITH_TRACING=true -export LANGSMITH_API_KEY=lsv2_sk_... -``` - -The simplest way to create a tool-calling agent in LangGraph is to use `create_react_agent`: - -
- High-level implementation +To learn more about how to use LangGraph, check out [the docs](https://langchain-ai.github.io/langgraph/). We show a simple example below of how to create a ReAct agent. ```python +from langchain_anthropic import ChatAnthropic from langgraph.prebuilt import create_react_agent -from langgraph.checkpoint.memory import MemorySaver -from langchain_anthropic import ChatAnthropic -from langchain_core.tools import tool -# Define the tools for the agent to use -@tool def search(query: str): """Call to surf the web.""" - # This is a placeholder, but don't tell the LLM that... if "sf" in query.lower() or "san francisco" in query.lower(): return "It's 60 degrees and foggy." return "It's 90 degrees and sunny." - +model = ChatAnthropic(model=“claude-3-7-sonnet-latest”) tools = [search] -model = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0) - -# Initialize memory to persist state between graph runs -checkpointer = MemorySaver() - -app = create_react_agent(model, tools, checkpointer=checkpointer) - -# Use the agent -final_state = app.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]}, - config={"configurable": {"thread_id": 42}} +agent = create_react_agent(model, tools) +agent.invoke( + {"messages": [{"role": "user", "content": "what is the weather in sf"}]} ) -final_state["messages"][-1].content -``` -``` -"Based on the search results, I can tell you that the current weather in San Francisco is:\n\nTemperature: 60 degrees Fahrenheit\nConditions: Foggy\n\nSan Francisco is known for its microclimates and frequent fog, especially during the summer months. The temperature of 60°F (about 15.5°C) is quite typical for the city, which tends to have mild temperatures year-round. The fog, often referred to as "Karl the Fog" by locals, is a characteristic feature of San Francisco\'s weather, particularly in the mornings and evenings.\n\nIs there anything else you\'d like to know about the weather in San Francisco or any other location?" ``` -Now when we pass the same "thread_id", the conversation context is retained via the saved state (i.e. stored list of messages) +## Why use LangGraph? -```python -final_state = app.invoke( - {"messages": [{"role": "user", "content": "what about ny"}]}, - config={"configurable": {"thread_id": 42}} -) -final_state["messages"][-1].content -``` +LangGraph is built for developers who want to build powerful, adaptable AI agents. Developers choose LangGraph for: -``` -"Based on the search results, I can tell you that the current weather in New York City is:\n\nTemperature: 90 degrees Fahrenheit (approximately 32.2 degrees Celsius)\nConditions: Sunny\n\nThis weather is quite different from what we just saw in San Francisco. New York is experiencing much warmer temperatures right now. Here are a few points to note:\n\n1. The temperature of 90°F is quite hot, typical of summer weather in New York City.\n2. The sunny conditions suggest clear skies, which is great for outdoor activities but also means it might feel even hotter due to direct sunlight.\n3. This kind of weather in New York often comes with high humidity, which can make it feel even warmer than the actual temperature suggests.\n\nIt's interesting to see the stark contrast between San Francisco's mild, foggy weather and New York's hot, sunny conditions. This difference illustrates how varied weather can be across different parts of the United States, even on the same day.\n\nIs there anything else you'd like to know about the weather in New York or any other location?" -``` -
+- **Reliability and controllability.** Steer agent actions with moderation checks and human-in-the-loop approvals. LangGraph persists context for long-running workflows, keeping your agents on course. +- **Low-level and extensible.** Build custom agents with fully descriptive, low-level primitives – free from rigid abstractions that limit customization. Design scalable multi-agent systems, with each agent serving a specific role tailored to your use case. +- **First-class streaming support.** With token-by-token streaming and streaming of intermediate steps, LangGraph gives users clear visibility into agent reasoning and actions as they unfold in real time. -> [!TIP] -> LangGraph is a **low-level** framework that allows you to implement any custom agent -architectures. Click on the low-level implementation below to see how to implement a -tool-calling agent from scratch. +LangGraph is trusted in production and powering agents for companies like: -
-Low-level implementation +- [Klarna](https://blog.langchain.dev/customers-klarna/): Customer support bot for 85 million active users +- [Elastic](https://www.elastic.co/blog/elastic-security-generative-ai-features): Security AI assistant for threat detection +- [Uber](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/): Automated unit test generation +- [Replit](https://www.langchain.com/breakoutagents/replit): Code generation +- And many more ([see list here](https://www.langchain.com/built-with-langgraph)) -```python -from typing import Literal +## LangGraph’s ecosystem -from langchain_anthropic import ChatAnthropic -from langchain_core.tools import tool -from langgraph.checkpoint.memory import MemorySaver -from langgraph.graph import END, START, StateGraph, MessagesState -from langgraph.prebuilt import ToolNode +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/). -# Define the tools for the agent to use -@tool -def search(query: str): - """Call to surf the web.""" - # This is a placeholder, but don't tell the LLM that... - if "sf" in query.lower() or "san francisco" in query.lower(): - return "It's 60 degrees and foggy." - return "It's 90 degrees and sunny." +## Pairing with LangGraph Platform +While LangGraph is our open-source agent orchestration framework, enterprises that need scalable agent deployment can benefit from [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/). -tools = [search] +LangGraph Platform can help engineering teams: -tool_node = ToolNode(tools) +- **Accelerate agent development**: Quickly create agent UXs with configurable templates and [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/) for visualizing and debugging agent interactions. +- **Deploy seamlessly**: We handle the complexity of deploying your agent. LangGraph Platform includes robust APIs for memory, threads, and cron jobs plus auto-scaling task queues & servers. +- **Centralize agent management & reusability**: Discover, reuse, and manage agents across the organization. Business users can also modify agents without coding. -model = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0).bind_tools(tools) +## Additional resources -# Define the function that determines whether to continue or not -def should_continue(state: MessagesState) -> Literal["tools", END]: - messages = state['messages'] - last_message = messages[-1] - # If the LLM makes a tool call, then we route to the "tools" node - if last_message.tool_calls: - return "tools" - # Otherwise, we stop (reply to the user) - return END +- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course. +- [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Simple walkthroughs with guided examples on getting started with LangGraph. +- [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted. +- [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.). +- [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components. +- [Built with LangGraph](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. +## Acknowledgements -# Define the function that calls the model -def call_model(state: MessagesState): - messages = state['messages'] - response = model.invoke(messages) - # We return a list, because this will get added to the existing list - return {"messages": [response]} - - -# Define a new graph -workflow = StateGraph(MessagesState) - -# Define the two nodes we will cycle between -workflow.add_node("agent", call_model) -workflow.add_node("tools", tool_node) - -# Set the entrypoint as `agent` -# This means that this node is the first one called -workflow.add_edge(START, "agent") - -# We now add a conditional edge -workflow.add_conditional_edges( - # First, we define the start node. We use `agent`. - # This means these are the edges taken after the `agent` node is called. - "agent", - # Next, we pass in the function that will determine which node is called next. - should_continue, -) - -# We now add a normal edge from `tools` to `agent`. -# This means that after `tools` is called, `agent` node is called next. -workflow.add_edge("tools", 'agent') - -# Initialize memory to persist state between graph runs -checkpointer = MemorySaver() - -# Finally, we compile it! -# This compiles it into a LangChain Runnable, -# meaning you can use it as you would any other runnable. -# Note that we're (optionally) passing the memory when compiling the graph -app = workflow.compile(checkpointer=checkpointer) - -# Use the agent -final_state = app.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]}, - config={"configurable": {"thread_id": 42}} -) -final_state["messages"][-1].content -``` - -Step-by-step Breakdown: - -
-Initialize the model and tools. - -
- -
-Initialize graph with state. - - -
- -
-Define graph nodes. - -There are two main nodes we need: - - -
- -
-Define entry point and graph edges. - -First, we need to set the entry point for graph execution - agent node. - -Then we define one normal and one conditional edge. Conditional edge means that the destination depends on the contents of the graph's state (MessagesState). In our case, the destination is not known until the agent (LLM) decides. - - -
- -
-Compile the graph. - - -
- -
-Execute the graph. - -
    -
  1. LangGraph adds the input message to the internal state, then passes the state to the entrypoint node, "agent".
  2. -
  3. The "agent" node executes, invoking the chat model.
  4. -
  5. The chat model returns an AIMessage. LangGraph adds this to the state.
  6. -
  7. Graph cycles the following steps until there are no more tool_calls on AIMessage: -
      -
    • If AIMessage has tool_calls, "tools" node executes
    • -
    • The "agent" node executes again and returns AIMessage
    • -
    -
  8. -
  9. Execution progresses to the special END value and outputs the final state. And as a result, we get a list of all our chat messages as output.
  10. -
-
- -
- -## Documentation - -* [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Learn to build with LangGraph through guided examples. -* [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Accomplish specific things within LangGraph, from streaming, to adding memory & persistence, to common design patterns (branching, subgraphs, etc.), these are the place to go if you want to copy and run a specific code snippet. -* [Conceptual Guides](https://langchain-ai.github.io/langgraph/concepts/high_level/): In-depth explanations of the key concepts and principles behind LangGraph, such as nodes, edges, state and more. -* [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Review important classes and methods, simple examples of how to use the graph and checkpointing APIs, higher-level prebuilt components and more. -* [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform): LangGraph Platform is a commercial solution for deploying agentic applications in production, built on the open-source LangGraph framework. - -## Resources - -* [Built with LangGraph](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. - -## Contributing - -For more information on how to contribute, see [here](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md). +LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain. \ No newline at end of file diff --git a/docs/_scripts/third_party_page/create_third_party_page.py b/docs/_scripts/third_party_page/create_third_party_page.py index fd3f784af..82d4e58b6 100755 --- a/docs/_scripts/third_party_page/create_third_party_page.py +++ b/docs/_scripts/third_party_page/create_third_party_page.py @@ -83,14 +83,18 @@ def generate_markdown(resolved_packages: List[ResolvedPackage], language: str) - resolved_packages, key=lambda p: p["weekly_downloads"] or 0, reverse=True ) rows = [ - "| Name | GitHub URL | Description | Weekly Downloads |", - "| --- | --- | --- | --- |", + "| Name | GitHub URL | Description | Weekly Downloads | Stars |", + "| --- | --- | --- | --- | --- |", ] for package in sorted_packages: name = f"**{package['name']}**" repo_url = f"[{package['repo']}](https://github.com/{package['repo']})" + stars_badge = ( + f"https://img.shields.io/github/stars/{package['repo']}?style=social" + ) + stars = f"![GitHub stars]({stars_badge})" downloads = package["weekly_downloads"] or "-" - row = f"| {name} | {repo_url} | {package['description']} | {downloads} |" + row = f"| {name} | {repo_url} | {package['description']} | {downloads} | {stars}" rows.append(row) markdown_content = MARKDOWN.format( library_list="\n".join(rows), langgraph_url=langgraph_url diff --git a/docs/_scripts/third_party_page/packages.yml b/docs/_scripts/third_party_page/packages.yml index 82ab8a147..5826b3454 100644 --- a/docs/_scripts/third_party_page/packages.yml +++ b/docs/_scripts/third_party_page/packages.yml @@ -2,13 +2,13 @@ packages: - name: "trustcall" repo: "hinthornw/trustcall" - description: "Tenacious tool calling built on LangGraph" + 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" + description: "A streamlined research system built inspired on STORM and built on LangGraph." - name: "langgraph-supervisor" - repo: "langchain-ai/langgraph-supervisor" - description: "Build supervisor multi-agent systems with LangGraph" + 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." @@ -18,3 +18,18 @@ packages: - 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: "langgraph-reflection" + repo: "langchain-ai/langgraph-reflection" + description: "LangGraph agent that runs a reflection step." \ No newline at end of file diff --git a/docs/docs/adopters.md b/docs/docs/adopters.md index 6f096538d..0f13c1baa 100644 --- a/docs/docs/adopters.md +++ b/docs/docs/adopters.md @@ -1,4 +1,4 @@ -# 🦜🕸️ LangGraph Adopters +# 🦜🕸️ Companies using LangGraph This list of companies using LangGraph and their success stories is compiled from public sources. If your company uses LangGraph, we'd love for you to share your story and add it to the list. You’re also welcome to contribute updates based on publicly available information from other companies, such as blog posts or press releases. @@ -9,6 +9,7 @@ This list of companies using LangGraph and their success stories is compiled fro | [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/) | | [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) | | [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) | | [GitLab](https://about.gitlab.com/) | Software & Technology | Code generation | [Duo workflow docs](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/duo_workflow/) | | [Infor](https://infor.com/) | Software & Technology | GenAI embedded product experiences; customer support; copilot | [Case study, 2025](https://blog.langchain.dev/customers-infor/) | diff --git a/docs/docs/cloud/deployment/semantic_search.md b/docs/docs/cloud/deployment/semantic_search.md index c9dc58633..fb2101925 100644 --- a/docs/docs/cloud/deployment/semantic_search.md +++ b/docs/docs/cloud/deployment/semantic_search.md @@ -17,7 +17,7 @@ This guide explains how to add semantic search to your LangGraph deployment's cr ... "store": { "index": { - "embed": "openai:text-embeddings-3-small", + "embed": "openai:text-embedding-3-small", "dims": 1536, "fields": ["$"] } @@ -27,7 +27,7 @@ This guide explains how to add semantic search to your LangGraph deployment's cr This configuration: -- Uses OpenAI's text-embeddings-3-small model for generating embeddings +- Uses OpenAI's text-embedding-3-small model for generating embeddings - Sets the embedding dimension to 1536 (matching the model's output) - Indexes all fields in your stored data (`["$"]` means index everything, or specify specific fields like `["text", "metadata.title"]`) diff --git a/docs/docs/cloud/deployment/setup.md b/docs/docs/cloud/deployment/setup.md index 42e956e70..ceb7834b0 100644 --- a/docs/docs/cloud/deployment/setup.md +++ b/docs/docs/cloud/deployment/setup.md @@ -36,21 +36,20 @@ Dependencies can optionally be specified in one of the following files: `pyproje The dependencies below will be included in the image, you can also use them in your code, as long as with a compatible version range: ``` -langgraph>=0.2.56,<0.3.0 -langgraph-checkpoint>=2.0.5,<3.0 +langgraph>=0.2.56,<0.4.0 +langgraph-sdk>=0.1.53 +langgraph-checkpoint>=2.0.15,<3.0 langchain-core>=0.2.38,<0.4.0 langsmith>=0.1.63 orjson>=3.9.7 httpx>=0.25.0 tenacity>=8.0.0 uvicorn>=0.26.0 -sse-starlette>=2.1.0 +sse-starlette>=2.1.0,<2.2.0 uvloop>=0.18.0 httptools>=0.5.0 -jsonschema-rs>=0.16.3 -croniter>=1.0.1 +jsonschema-rs>=0.20.0 structlog>=23.1.0 -redis>=5.0.0,<6.0.0 ``` Example `requirements.txt` file: diff --git a/docs/docs/cloud/deployment/setup_pyproject.md b/docs/docs/cloud/deployment/setup_pyproject.md index ccb02a79d..07c8ca30c 100644 --- a/docs/docs/cloud/deployment/setup_pyproject.md +++ b/docs/docs/cloud/deployment/setup_pyproject.md @@ -36,21 +36,20 @@ Dependencies can optionally be specified in one of the following files: `pyproje The dependencies below will be included in the image, you can also use them in your code, as long as with a compatible version range: ``` -langgraph>=0.2.56,<0.3.0 -langgraph-checkpoint>=2.0.5,<3.0 +langgraph>=0.2.56,<0.4.0 +langgraph-sdk>=0.1.53 +langgraph-checkpoint>=2.0.15,<3.0 langchain-core>=0.2.38,<0.4.0 langsmith>=0.1.63 orjson>=3.9.7 httpx>=0.25.0 tenacity>=8.0.0 uvicorn>=0.26.0 -sse-starlette>=2.1.0 +sse-starlette>=2.1.0,<2.2.0 uvloop>=0.18.0 httptools>=0.5.0 -jsonschema-rs>=0.16.3 -croniter>=1.0.1 +jsonschema-rs>=0.20.0 structlog>=23.1.0 -redis>=5.0.0,<6.0.0 ``` Example `pyproject.toml` file: diff --git a/docs/docs/cloud/how-tos/langgraph_to_langgraph_cloud.ipynb b/docs/docs/cloud/how-tos/langgraph_to_langgraph_cloud.ipynb deleted file mode 100644 index 30eb85f5d..000000000 --- a/docs/docs/cloud/how-tos/langgraph_to_langgraph_cloud.ipynb +++ /dev/null @@ -1,1016 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "3631f2b9-aa79-472e-a9d6-9125a90ee704", - "metadata": {}, - "source": [ - "# How to convert LangGraph calls to LangGraph Cloud calls" - ] - }, - { - "cell_type": "markdown", - "id": "2e9edff6-38a4-45b8-a612-fb594a226879", - "metadata": {}, - "source": [ - "So you're used to interacting with your graph locally, but now you've deployed it with LangGraph cloud. How do you change all the places in your codebase where you call LangGraph directly to call LangGraph Cloud? This notebook contains side-by-side comparisons so you can easily transition from calling LangGraph to calling LangGraph Cloud." - ] - }, - { - "cell_type": "markdown", - "id": "7c2f84f1-0751-4779-97d4-5cbb286093b7", - "metadata": {}, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "markdown", - "id": "323db423-b644-40bd-9c2d-976a53f602f7", - "metadata": {}, - "source": [ - "We'll be using a simple ReAct agent for this how-to guide. You will also need to set up a project with `agent.py` and `langgraph.json` files. See [quick start](https://langchain-ai.github.io/langgraph/cloud/quick_start/#develop) for setting this up." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "6b4285e4-7434-4971-bde0-aabceef8ee7e", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain-openai" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "f7f9f24a-e3d0-422b-8924-47950b2facd6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "OPENAI_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "ef5a3ec6-0cd0-4541-ab1b-d63ede22720e", - "metadata": {}, - "outputs": [], - "source": [ - "# this is all that's needed for the agent.py\n", - "from typing import Literal\n", - "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI\n", - "from langgraph.prebuilt import create_react_agent\n", - "\n", - "\n", - "@tool\n", - "def get_weather(city: Literal[\"nyc\", \"sf\"]):\n", - " \"\"\"Use this to get weather information.\"\"\"\n", - " if city == \"nyc\":\n", - " return \"It might be cloudy in nyc\"\n", - " elif city == \"sf\":\n", - " return \"It's always sunny in sf\"\n", - " else:\n", - " raise AssertionError(\"Unknown city\")\n", - "\n", - "\n", - "tools = [get_weather]\n", - "\n", - "model = ChatOpenAI(model_name=\"gpt-4o\", temperature=0)\n", - "graph = create_react_agent(model, tools)" - ] - }, - { - "cell_type": "markdown", - "id": "eb9e138e-cb0e-480a-a32a-d63019720262", - "metadata": {}, - "source": [ - "Now we'll set up the langgraph client. The client assumes the LangGraph Cloud server is running on `localhost:8123`" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "3ab06b39-7bd1-4611-a37e-9b94e25643d2", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph_sdk import get_client\n", - "\n", - "client = get_client()" - ] - }, - { - "cell_type": "markdown", - "id": "ee4e8d83-e68d-40b8-a128-5c85e0aafc85", - "metadata": {}, - "source": [ - "## Invoking the graph" - ] - }, - { - "cell_type": "markdown", - "id": "ed935900-1ecc-4f39-9dc9-70a92f179d00", - "metadata": {}, - "source": [ - "Below examples show how to mirror `.invoke() / .ainvoke()` methods of LangGraph's `CompiledGraph` runnable, i.e. create a blocking graph execution" - ] - }, - { - "cell_type": "markdown", - "id": "a3e5c63f-d33b-4d27-b90c-205ee30f1197", - "metadata": {}, - "source": [ - "### With LangGraph" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a11bd693-662e-42ad-aa8f-99531f0d091e", - "metadata": {}, - "outputs": [], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's the weather in sf\")]}\n", - "invoke_output = await graph.ainvoke(inputs)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "9f649fcc-81f0-4c94-9ee9-b2db31bfc5d4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_weather (call_GOKlsBY2XKm7pZnmAzJweYDU)\n", - " Call ID: call_GOKlsBY2XKm7pZnmAzJweYDU\n", - " Args:\n", - " city: sf\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's always sunny in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in San Francisco is currently sunny.\n" - ] - } - ], - "source": [ - "for m in invoke_output[\"messages\"]:\n", - " m.pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "ec78ae0f-c474-472e-8273-658bb56f1476", - "metadata": {}, - "source": [ - "### With LangGraph Cloud" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "72bd6ac6-ace3-43b4-99b8-559b3d2a614f", - "metadata": {}, - "outputs": [], - "source": [ - "# NOTE: We're not specifying the thread here -- this allows us to create a thread just for this run\n", - "wait_output = await client.runs.wait(None, \"agent\", input=inputs)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "0d81c783-2c7b-421a-a0f9-752e22039472", - "metadata": {}, - "outputs": [], - "source": [ - "# we'll use this for pretty message formatting\n", - "from langchain_core.messages import convert_to_messages" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "da0f4d54-662c-42b0-ba35-c52f30a2fb1e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_weather (call_pQJsT9uLG3nVppN8Dt2OhnFx)\n", - " Call ID: call_pQJsT9uLG3nVppN8Dt2OhnFx\n", - " Args:\n", - " city: sf\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's always sunny in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in San Francisco is currently sunny.\n" - ] - } - ], - "source": [ - "for m in convert_to_messages(wait_output[\"messages\"]):\n", - " m.pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "129853ea-83e2-4adf-b5e4-60f70c0ccb73", - "metadata": {}, - "source": [ - "## Streaming" - ] - }, - { - "cell_type": "markdown", - "id": "1468248f-f50b-43f3-b566-48ae4a1b643b", - "metadata": {}, - "source": [ - "Below examples show how to mirror `.stream() / .astream()` methods for streaming partial graph execution results. \n", - "Note: LangGraph's `stream_mode=values/updates/debug` behave nearly identically in LangGraph Cloud (with the exception of additional streamed chunks with `metadata` / `end` events types)" - ] - }, - { - "cell_type": "markdown", - "id": "3ed2aae5-d137-4a5b-868b-ed4d551aefaa", - "metadata": {}, - "source": [ - "### With LangGraph" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "e9e9ffb0-2cd5-466f-b70b-b6ed51b852d1", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_weather (call_302y9671bqMkMcpLZOWLNAnq)\n", - " Call ID: call_302y9671bqMkMcpLZOWLNAnq\n", - " Args:\n", - " city: sf\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's always sunny in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in San Francisco is currently sunny.\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's the weather in sf\")]}\n", - "async for chunk in graph.astream(inputs, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "5da024a7-1d7e-4212-9251-aaadaba6acbd", - "metadata": {}, - "source": [ - "### With LangGraph Cloud" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "a3c02bf7-af0c-47b9-8339-1e303571220e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_weather (call_NYVNSiBeF0oTAYnaDrlEAG7a)\n", - " Call ID: call_NYVNSiBeF0oTAYnaDrlEAG7a\n", - " Args:\n", - " city: sf\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's always sunny in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in San Francisco is currently sunny.\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's the weather in sf\")]}\n", - "async for chunk in client.runs.stream(\n", - " None, \"agent\", input=inputs, stream_mode=\"values\"\n", - "):\n", - " if chunk.event == \"values\":\n", - " messages = convert_to_messages(chunk.data[\"messages\"])\n", - " messages[-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "d693e1b8-bb65-439f-bbbe-b6a12cc26f1a", - "metadata": {}, - "source": [ - "## Persistence" - ] - }, - { - "cell_type": "markdown", - "id": "bcd1a770-8f4a-4c5e-9e54-9851a6acb985", - "metadata": {}, - "source": [ - "In LangGraph, you need to provide a `checkpointer` object when compiling your graph to persist state across interactions with your graph (i.e. threads). In LangGraph Cloud, you don't need to create a checkpointer -- the server already implements one for you. You can also directly manage the threads from a client." - ] - }, - { - "cell_type": "markdown", - "id": "3afcc9e4-e650-497c-be05-1d6a6ad06af3", - "metadata": {}, - "source": [ - "### With LangGraph" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "ac145136-410c-41fe-a936-00c8f6d9116f", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.checkpoint.memory import MemorySaver" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "5fc8fb7d-989d-42a4-88eb-f037cf64f8d3", - "metadata": {}, - "outputs": [], - "source": [ - "checkpointer = MemorySaver()\n", - "graph_with_memory = create_react_agent(model, tools, checkpointer=checkpointer)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "a93f76d3-3d97-435f-8718-bacd56002872", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in NYC might be cloudy.\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's the weather in nyc\")]}\n", - "invoke_output = await graph_with_memory.ainvoke(\n", - " inputs, config={\"configurable\": {\"thread_id\": \"1\"}}\n", - ")\n", - "invoke_output[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "ba3a2d61-ecdd-4a6e-b275-e7cb5f465def", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "New York City (NYC) is known for a variety of iconic landmarks, cultural institutions, and vibrant neighborhoods. Some of the most notable things NYC is known for include:\n", - "\n", - "1. **Statue of Liberty**: A symbol of freedom and democracy.\n", - "2. **Times Square**: Famous for its bright lights, Broadway theaters, and bustling atmosphere.\n", - "3. **Central Park**: A large urban park offering a green oasis in the middle of the city.\n", - "4. **Empire State Building**: An iconic skyscraper with an observation deck offering panoramic views of the city.\n", - "5. **Broadway**: Renowned for its world-class theater productions.\n", - "6. **Wall Street**: The financial hub of the United States.\n", - "7. **Museums**: Including the Metropolitan Museum of Art, the Museum of Modern Art (MoMA), and the American Museum of Natural History.\n", - "8. **Diverse Cuisine**: A melting pot of culinary experiences from around the world.\n", - "9. **Cultural Diversity**: A rich tapestry of cultures, languages, and traditions.\n", - "10. **Fashion**: A global fashion capital, home to numerous designers and fashion events.\n", - "\n", - "These are just a few highlights, but NYC offers countless other attractions and experiences.\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's it known for?\")]}\n", - "invoke_output = await graph_with_memory.ainvoke(\n", - " inputs, config={\"configurable\": {\"thread_id\": \"1\"}}\n", - ")\n", - "invoke_output[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "990a9557-894f-4b1d-a9dd-8d089cf6e06b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Could you please specify what \"it\" refers to? Are you asking about a specific city, person, object, or something else?\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's it known for?\")]}\n", - "invoke_output = await graph_with_memory.ainvoke(\n", - " inputs, config={\"configurable\": {\"thread_id\": \"2\"}}\n", - ")\n", - "invoke_output[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "98a998ac-1ff2-4eb7-8ff6-5a513c098807", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'v': 1,\n", - " 'ts': '2024-06-22T02:31:49.722569+00:00',\n", - " 'id': '1ef303f9-4149-6b56-8001-a80d1e3c9dc6',\n", - " 'channel_values': {'messages': [HumanMessage(content=\"what's it known for?\", id='ea0d1672-05e9-4d77-9dff-b33bd5c824e7'),\n", - " AIMessage(content='Could you please specify what \"it\" refers to? Are you asking about a specific city, person, object, or something else?', response_metadata={'token_usage': {'completion_tokens': 28, 'prompt_tokens': 57, 'total_tokens': 85}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_3e7d703517', 'finish_reason': 'stop', 'logprobs': None}, id='run-f0381dc0-d891-4203-8f77-3155ba17998c-0', usage_metadata={'input_tokens': 57, 'output_tokens': 28, 'total_tokens': 85})],\n", - " 'agent': 'agent'},\n", - " 'channel_versions': {'__start__': 2,\n", - " 'messages': 3,\n", - " 'start:agent': 3,\n", - " 'agent': 3},\n", - " 'versions_seen': {'__start__': {'__start__': 1},\n", - " 'agent': {'start:agent': 2},\n", - " 'tools': {}},\n", - " 'pending_sends': []}" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# get the state of the thread\n", - "checkpointer.get({\"configurable\": {\"thread_id\": \"2\"}})" - ] - }, - { - "cell_type": "markdown", - "id": "bd07ea78-12e9-475a-84e9-0d34f99c6024", - "metadata": {}, - "source": [ - "### With LangGraph Cloud\n", - "\n", - "Let's now reproduce the same using LangGraph Cloud. Note that instead of using a checkpointer we just create a new thread on the backend and pass the ID to the API" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "90b312d3-4b51-4953-8c78-8263a90b397a", - "metadata": {}, - "outputs": [], - "source": [ - "thread = await client.threads.create()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "3e523086-29ab-4b21-b762-21136d32e6fa", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in NYC might be cloudy.\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's the weather in nyc\")]}\n", - "wait_output = await client.runs.wait(thread[\"thread_id\"], \"agent\", input=inputs)\n", - "convert_to_messages(wait_output[\"messages\"])[-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "f430c8ec-782c-4003-9e30-0736cbdd37ce", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "New York City (NYC) is known for a variety of iconic landmarks, cultural institutions, and vibrant neighborhoods. Some of the most notable things NYC is known for include:\n", - "\n", - "1. **Statue of Liberty**: A symbol of freedom and democracy, located on Liberty Island.\n", - "2. **Times Square**: Known for its bright lights, Broadway theaters, and bustling atmosphere.\n", - "3. **Central Park**: A large urban park offering a green oasis in the middle of the city.\n", - "4. **Empire State Building**: An iconic skyscraper with an observation deck offering panoramic views of the city.\n", - "5. **Broadway**: Famous for its world-class theater productions and musicals.\n", - "6. **Wall Street**: The financial hub of the United States, home to the New York Stock Exchange.\n", - "7. **Museums**: Including the Metropolitan Museum of Art, the Museum of Modern Art (MoMA), and the American Museum of Natural History.\n", - "8. **Diverse Cuisine**: A melting pot of culinary experiences, from street food to Michelin-starred restaurants.\n", - "9. **Cultural Diversity**: A rich tapestry of cultures and communities from around the world.\n", - "10. **Skyscrapers**: A skyline filled with iconic buildings and modern architecture.\n", - "\n", - "NYC is also known for its influence in fashion, media, and entertainment, making it one of the most dynamic and influential cities in the world.\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's it known for?\")]}\n", - "wait_output = await client.runs.wait(thread[\"thread_id\"], \"agent\", input=inputs)\n", - "convert_to_messages(wait_output[\"messages\"])[-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "cb34efef-805d-455c-be3e-e2234d97b7cf", - "metadata": {}, - "outputs": [], - "source": [ - "thread = await client.threads.create()" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "7628e108-338b-4eaf-9d57-defc2c7e2b46", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Could you please specify what \"it\" refers to? Are you asking about a specific city, person, object, or something else?\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's it known for?\")]}\n", - "wait_output = await client.runs.wait(thread[\"thread_id\"], \"agent\", input=inputs)\n", - "convert_to_messages(wait_output[\"messages\"])[-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "22a3f9e6-a550-4074-95eb-be3866b77718", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'values': {'messages': [{'content': \"what's it known for?\",\n", - " 'additional_kwargs': {},\n", - " 'response_metadata': {},\n", - " 'type': 'human',\n", - " 'name': None,\n", - " 'id': '381cd144-b360-4c7d-8177-e2634446993c',\n", - " 'example': False},\n", - " {'content': 'Could you please specify what \"it\" refers to? Are you asking about a specific city, person, object, or something else?',\n", - " 'additional_kwargs': {'refusal': None},\n", - " 'response_metadata': {'token_usage': {'completion_tokens': 28,\n", - " 'prompt_tokens': 57,\n", - " 'total_tokens': 85,\n", - " 'completion_tokens_details': {'reasoning_tokens': 0}},\n", - " 'model_name': 'gpt-4o-2024-05-13',\n", - " 'system_fingerprint': 'fp_3537616b13',\n", - " 'finish_reason': 'stop',\n", - " 'logprobs': None},\n", - " 'type': 'ai',\n", - " 'name': None,\n", - " 'id': 'run-b23c6a05-d6c7-46fd-8b09-443a334feb6b-0',\n", - " 'example': False,\n", - " 'tool_calls': [],\n", - " 'invalid_tool_calls': [],\n", - " 'usage_metadata': {'input_tokens': 57,\n", - " 'output_tokens': 28,\n", - " 'total_tokens': 85}}]},\n", - " 'next': [],\n", - " 'tasks': [],\n", - " 'metadata': {'step': 1,\n", - " 'run_id': '1ef78309-0a79-6667-a00b-1a04034cabff',\n", - " 'source': 'loop',\n", - " 'writes': {'agent': {'messages': [{'id': 'run-b23c6a05-d6c7-46fd-8b09-443a334feb6b-0',\n", - " 'name': None,\n", - " 'type': 'ai',\n", - " 'content': 'Could you please specify what \"it\" refers to? Are you asking about a specific city, person, object, or something else?',\n", - " 'example': False,\n", - " 'tool_calls': [],\n", - " 'usage_metadata': {'input_tokens': 57,\n", - " 'total_tokens': 85,\n", - " 'output_tokens': 28},\n", - " 'additional_kwargs': {'refusal': None},\n", - " 'response_metadata': {'logprobs': None,\n", - " 'model_name': 'gpt-4o-2024-05-13',\n", - " 'token_usage': {'total_tokens': 85,\n", - " 'prompt_tokens': 57,\n", - " 'completion_tokens': 28,\n", - " 'completion_tokens_details': {'reasoning_tokens': 0}},\n", - " 'finish_reason': 'stop',\n", - " 'system_fingerprint': 'fp_3537616b13'},\n", - " 'invalid_tool_calls': []}]}},\n", - " 'parents': {},\n", - " 'user_id': '',\n", - " 'graph_id': 'agent',\n", - " 'thread_id': '14162c42-ab85-404f-a2f9-e7207493f74b',\n", - " 'created_by': 'system',\n", - " 'run_attempt': 1,\n", - " 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'},\n", - " 'created_at': '2024-09-21T15:45:46.150887+00:00',\n", - " 'checkpoint_id': '1ef78309-131f-673f-8001-55ea44389e6a',\n", - " 'parent_checkpoint_id': '1ef78309-0aab-6271-8000-caaf708a2185'}" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# get the state of the thread\n", - "await client.threads.get_state(thread[\"thread_id\"])" - ] - }, - { - "cell_type": "markdown", - "id": "6b0d8ec5-316f-48e5-bebf-8d66c8dbd450", - "metadata": {}, - "source": [ - "## Breakpoints\n", - "\n", - "### With LangGraph" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "b3722e75-b9f2-4a55-aae3-f6829a7a929e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_weather (call_cYp3BijeW2JNQ9RqJRdkrbMu)\n", - " Call ID: call_cYp3BijeW2JNQ9RqJRdkrbMu\n", - " Args:\n", - " city: sf\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's the weather in sf\")]}\n", - "async for chunk in graph_with_memory.astream(\n", - " inputs,\n", - " stream_mode=\"values\",\n", - " interrupt_before=[\"tools\"],\n", - " config={\"configurable\": {\"thread_id\": \"3\"}},\n", - "):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "6a58a513-7adc-4523-9145-6777f20521e4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's always sunny in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in San Francisco is sunny!\n" - ] - } - ], - "source": [ - "async for chunk in graph_with_memory.astream(\n", - " None,\n", - " stream_mode=\"values\",\n", - " interrupt_before=[\"tools\"],\n", - " config={\"configurable\": {\"thread_id\": \"3\"}},\n", - "):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "a84f11dd-e6db-4fc7-bde6-67db5bc01d0f", - "metadata": {}, - "source": [ - "### With LangGraph Cloud" - ] - }, - { - "cell_type": "markdown", - "id": "addd1bf8-d0da-40c2-9913-e145deed6b6d", - "metadata": {}, - "source": [ - "Similar to the persistence example, we need to create a thread so we can persist state and continue from the breakpoint." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "96591cf8-98fc-4fa0-a03a-29e18e672126", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_weather (call_MVQEJtPYAj1nJ7J6YaCeLX8a)\n", - " Call ID: call_MVQEJtPYAj1nJ7J6YaCeLX8a\n", - " Args:\n", - " city: sf\n" - ] - } - ], - "source": [ - "thread = await client.threads.create()\n", - "\n", - "async for chunk in client.runs.stream(\n", - " thread[\"thread_id\"],\n", - " \"agent\",\n", - " input=inputs,\n", - " stream_mode=\"values\",\n", - " interrupt_before=[\"tools\"],\n", - "):\n", - " if chunk.event == \"values\":\n", - " messages = convert_to_messages(chunk.data[\"messages\"])\n", - " messages[-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "bb7f74bd-7ce1-4cd3-9203-2a8aed7b8620", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's always sunny in sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in San Francisco is currently sunny.\n" - ] - } - ], - "source": [ - "async for chunk in client.runs.stream(\n", - " thread[\"thread_id\"],\n", - " \"agent\",\n", - " input=None,\n", - " stream_mode=\"values\",\n", - " interrupt_before=[\"tools\"],\n", - "):\n", - " if chunk.event == \"values\":\n", - " messages = convert_to_messages(chunk.data[\"messages\"])\n", - " messages[-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "6af293ee-7866-4326-ba17-e3ffbb0c96c7", - "metadata": {}, - "source": [ - "## Steaming events" - ] - }, - { - "cell_type": "markdown", - "id": "cb4072c9-775e-4bf5-8a1a-fb822e6de9d7", - "metadata": {}, - "source": [ - "For streaming events, in LangGraph you need to use `.astream` method on the `CompiledGraph`. In LangGraph Cloud this is done via passing `stream_mode=\"events\"`" - ] - }, - { - "cell_type": "markdown", - "id": "4a158573-240a-44a3-b0ef-0cf9334042f2", - "metadata": {}, - "source": [ - "### With LangGraph" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "fc692060", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[{'name': 'get_weather', 'args': {}, 'id': 'call_G6boP6Hj21glqPTqtFdTllUd', 'type': 'tool_call'}]\n", - "[{'name': 'get_weather', 'args': {}, 'id': 'call_G6boP6Hj21glqPTqtFdTllUd', 'type': 'tool_call'}]\n", - "[{'name': 'get_weather', 'args': {}, 'id': 'call_G6boP6Hj21glqPTqtFdTllUd', 'type': 'tool_call'}]\n", - "[{'name': 'get_weather', 'args': {'city': ''}, 'id': 'call_G6boP6Hj21glqPTqtFdTllUd', 'type': 'tool_call'}]\n", - "[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_G6boP6Hj21glqPTqtFdTllUd', 'type': 'tool_call'}]\n", - "[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_G6boP6Hj21glqPTqtFdTllUd', 'type': 'tool_call'}]\n", - "It's always sunny in sf|The| weather| in| San| Francisco| is| currently| sunny|.|" - ] - } - ], - "source": [ - "from langchain_core.messages import AIMessageChunk\n", - "\n", - "inputs = {\"messages\": [(\"human\", \"what's the weather in sf\")]}\n", - "first = True\n", - "async for msg, metadata in graph.astream(inputs, stream_mode=\"messages\"):\n", - " if msg.content:\n", - " print(msg.content, end=\"|\", flush=True)\n", - "\n", - " if isinstance(msg, AIMessageChunk):\n", - " if first:\n", - " gathered = msg\n", - " first = False\n", - " else:\n", - " gathered = gathered + msg\n", - "\n", - " if msg.tool_call_chunks:\n", - " print(gathered.tool_calls)" - ] - }, - { - "cell_type": "markdown", - "id": "08996d90-a3ff-4655-9763-1dd4971344d4", - "metadata": {}, - "source": [ - "### With LangGraph Cloud" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "547bfcd2-01fe-4e7c-8734-0d02beb2c36e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': 'call_JYWaAecaAV92cOlZwRHi9B7M', 'function': {'arguments': '', 'name': 'get_weather'}, 'type': 'function'}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': 'get_weather', 'args': '', 'id': 'call_JYWaAecaAV92cOlZwRHi9B7M', 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': 'get_weather', 'args': '', 'id': 'call_JYWaAecaAV92cOlZwRHi9B7M', 'index': 0}]}\n", - "{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '{\"', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [{'name': '', 'args': {}, 'id': None}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '{\"', 'id': None, 'index': 0}]}\n", - "{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': 'city', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': 'city', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': 'city', 'id': None, 'index': 0}]}\n", - "{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '\":\"', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': '\":\"', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '\":\"', 'id': None, 'index': 0}]}\n", - "{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': 'sf', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': 'sf', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': 'sf', 'id': None, 'index': 0}]}\n", - "{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '\"}', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': '\"}', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '\"}', 'id': None, 'index': 0}]}\n", - "{'content': '', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'tool_calls'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': '', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': 'The', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' weather', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' in', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' San', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' Francisco', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' is', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' currently', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' sunny', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': '.', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' Enjoy', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' the', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': ' sunshine', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': '!', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n", - "{'content': '', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}\n" - ] - } - ], - "source": [ - "inputs = {\"messages\": [(\"human\", \"what's the weather in sf\")]}\n", - "async for chunk in client.runs.stream(\n", - " None, \"agent\", input=inputs, stream_mode=\"events\"\n", - "):\n", - " if chunk.event == \"events\" and chunk.data[\"event\"] == \"on_chat_model_stream\":\n", - " print(chunk.data[\"data\"][\"chunk\"])" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/cloud/how-tos/test_deployment.md b/docs/docs/cloud/how-tos/test_deployment.md index 127e1e25e..b35bf5e13 100644 --- a/docs/docs/cloud/how-tos/test_deployment.md +++ b/docs/docs/cloud/how-tos/test_deployment.md @@ -1,10 +1,10 @@ -# Test Cloud Deployment +# Test LangGraph Platform Deployment -The LangGraph Studio UI connects directly to LangGraph Cloud deployments. +The LangGraph Studio UI connects directly to LangGraph Platform deployments. Starting from the LangSmith UI... -1. In the left-hand navigation panel, select `LangGraph Cloud`. The `LangGraph Cloud` view contains a list of existing LangGraph Cloud deployments. +1. In the left-hand navigation panel, select `LangGraph Platform`. The `LangGraph Platform` view contains a list of existing LangGraph Platform deployments. 1. Select an existing deployment to test with LangGraph Studio. 1. In the top-right corner, select `Open LangGraph Studio`. 1. [Invoke an assistant](./invoke_studio.md) or [view an existing thread](./threads_studio.md). diff --git a/docs/docs/cloud/reference/cli.md b/docs/docs/cloud/reference/cli.md index 958fa2557..d087793de 100644 --- a/docs/docs/cloud/reference/cli.md +++ b/docs/docs/cloud/reference/cli.md @@ -1,6 +1,6 @@ # LangGraph CLI -The LangGraph command line interface includes commands to build and run a LangGraph Cloud API server locally in [Docker](https://www.docker.com/). For development and testing, you can use the CLI to deploy a local API server as an alternative to the [Studio desktop app](../../concepts/langgraph_studio.md). +The LangGraph command line interface includes commands to build and run a LangGraph Cloud API server locally in [Docker](https://www.docker.com/). For development and testing, you can use the CLI to deploy a local API server. ## Installation diff --git a/docs/docs/cloud/reference/env_var.md b/docs/docs/cloud/reference/env_var.md index 009b3a64f..9d1cd273c 100644 --- a/docs/docs/cloud/reference/env_var.md +++ b/docs/docs/cloud/reference/env_var.md @@ -2,6 +2,12 @@ The LangGraph Cloud Server supports specific environment variables for configuring a deployment. +## `DD_API_KEY` + +Specify `DD_API_KEY` (your [Datadog API Key](https://docs.datadoghq.com/account_management/api-app-keys/)) to automatically enable Datadog tracing for the deployment. Specify other [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) to configure the tracing instrumentation. + +If `DD_API_KEY` is specified, the application process is wrapped in the [`ddtrace-run` command](https://ddtrace.readthedocs.io/en/stable/installation_quickstart.html). Other `DD_*` environment variables (e.g. `DD_SITE`, `DD_ENV`, `DD_SERVICE`, `DD_TRACE_ENABLED`) are typically needed to properly configure the tracing instrumentation. See [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) for more details. + ## `LANGCHAIN_TRACING_SAMPLING_RATE` Sampling rate for traces sent to LangSmith. Valid values: Any float between `0` and `1`. diff --git a/docs/docs/concepts/faq.md b/docs/docs/concepts/faq.md index a626e8133..e8f4ee950 100644 --- a/docs/docs/concepts/faq.md +++ b/docs/docs/concepts/faq.md @@ -36,7 +36,7 @@ LangGraph is a stateful, orchestration framework that brings added control to ag | 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 | +| IDE integration | LangGraph Studio | LangGraph Studio | ## What are my deployment options for LangGraph Platform? @@ -62,3 +62,9 @@ Yes! You can use LangGraph with any LLMs. The main reason we use LLMs that suppo ## Does LangGraph work with OSS LLMs? Yes! LangGraph is totally ambivalent to what LLMs are used under the hood. The main reason we use closed LLMs in most of the tutorials is that they seamlessly support tool calling, while OSS LLMs often don't. But tool calling is not necessary (see [this section](#does-langgraph-work-with-llms-that-dont-support-tool-calling)) so you can totally use LangGraph with OSS LLMs. + +## Can I use LangGraph Studio without logging to LangSmith + +Yes! You can use the [development version of LangGraph Server](../tutorials/langgraph-platform/local-server.md) to run the backend locally. +This will connect to the studio frontend hosted as part of LangSmith. +If you set an environment variable of `LANGSMITH_TRACING=false` then no traces will be sent to LangSmith. \ No newline at end of file diff --git a/docs/docs/concepts/langgraph_cli.md b/docs/docs/concepts/langgraph_cli.md index 9eec86ffb..2c69c0193 100644 --- a/docs/docs/concepts/langgraph_cli.md +++ b/docs/docs/concepts/langgraph_cli.md @@ -4,7 +4,7 @@ - [LangGraph Platform](./langgraph_platform.md) - [LangGraph Server](./langgraph_server.md) -The LangGraph CLI is a multi-platform command-line tool for building and running the [LangGraph API server](./langgraph_server.md) locally. This offers an alternative to the [LangGraph Studio desktop app](./langgraph_studio.md) for developing and testing agents across all major operating systems (Linux, Windows, MacOS). The resulting server includes all API endpoints for your graph's runs, threads, assistants, etc. as well as the other services required to run your agent, including a managed database for checkpointing and storage. +The LangGraph CLI is a multi-platform command-line tool for building and running the [LangGraph API server](./langgraph_server.md) locally. The resulting server includes all API endpoints for your graph's runs, threads, assistants, etc. as well as the other services required to run your agent, including a managed database for checkpointing and storage. ## Installation diff --git a/docs/docs/concepts/langgraph_studio.md b/docs/docs/concepts/langgraph_studio.md index bf0d31fb0..7b00235bd 100644 --- a/docs/docs/concepts/langgraph_studio.md +++ b/docs/docs/concepts/langgraph_studio.md @@ -7,7 +7,7 @@ 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. +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. ![](img/lg_studio.png) @@ -15,7 +15,7 @@ With visual graphs and the ability to edit state, you can better understand agen The key features of LangGraph Studio are: -- Visualizes your graph +- Visualize your graphs - Test your graph by running it from the UI - Debug your agent by [modifying its state and rerunning](human_in_the_loop.md) - Create and manage [assistants](assistants.md) @@ -23,86 +23,54 @@ The key features of LangGraph Studio are: - View and manage [long term memory](memory.md) - Add node input/outputs to [LangSmith](https://smith.langchain.com/) datasets for testing -## Types +## Getting started -### Development server with web UI +There are two ways to connect your LangGraph app with the studio: -You can [run a local in-memory development server](../tutorials/langgraph-platform/local-server.md) that can be used to connect a local LangGraph app with a web version of the studio. -For example, if you start the local server with `langgraph dev` (running at `http://127.0.0.1:2024` by default), you can connect to the studio by navigating to: +### Deployed Application + +If you have deployed your LangGraph application on LangGraph Platform, you can access the studio as part of that deployment. To do so, navigate to the deployment in LangGraph Platform within the LangSmith UI and click the "LangGraph Studio" button. + +### Local Development Server + +If you have a LangGraph application that is [running locally in-memory](../tutorials/langgraph-platform/local-server.md), you can connect it to LangGraph Studio in the browser within LangSmith. + +By default, starting the local server with `langgraph dev` will run the server at `http://127.0.0.1:2024` and automatically open Studio in your browser. However, you can also manually connect to Studio by either: + +1. In LangGraph Platform, clicking the "LangGraph Studio" button and entering the server URL in the dialog that appears. + + or + +2. Navigating to the URL in your browser: ``` https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 ``` -See [instructions here](../cloud/reference/cli.md#dev) for more information. +## Related -The web UI version of the studio will connect to your locally running server — your agent is still running locally and never leaves your device. +For more information please see the following: -### Cloud studio +- [LangGraph Studio how-to guides](../how-tos/index.md#langgraph-studio) +- [LangGraph CLI Documentation](../cloud/reference/cli.md) -If you have deployed your LangGraph application on LangGraph Platform (Cloud), you can access the studio as part of that - -### Desktop app - -LangGraph Studio is available as a [desktop app](https://studio.langchain.com/) for MacOS users. - -While in Beta, LangGraph Studio is available for free to all [LangSmith](https://smith.langchain.com/) users on any plan tier. - -## Studio FAQs +## LangGraph Studio FAQs ### Why is my project failing to start? -There are a few reasons that your project might fail to start, here are some of the most common ones. - -#### Docker issues (desktop only) - -LangGraph Studio (desktop) requires Docker Desktop version 4.24 or higher. Please make sure you have a version of Docker installed that satisfies that requirement and also make sure you have the Docker Desktop app up and running before trying to use LangGraph Studio. In addition, make sure you have docker-compose updated to version 2.22.0 or higher. - -#### Configuration or environment issues - -Another reason your project might fail to start is because your configuration file is defined incorrectly, or you are missing required environment variables. - -!!! Important "Note (desktop only)" - - LangGraph Studio Desktop automatically populates `LANGCHAIN_*` environment variables for license verification and tracing, regardless of the contents of the `.env` file. All other environment variables defined in `.env` will be read as normal. - -#### Incorrect data region (desktop only) - -If you receive a license verification error when attempting to start the LangGraph Server, you may be logged into the incorrect LangSmith data region. Ensure that you're logged into the correct LangSmith data region and ensure that the LangSmith account has access to LangGraph platform. - -1. In the top right-hand corner, click the user icon and select `Logout`. -1. At the login screen, click the `Data Region` dropdown menu and select the appropriate data region. Then click `Login to LangSmith`. +A project may fail to start if the configuration file is defined incorrectly, or if required environment variables are missing. See [here](../cloud/reference/cli.md#configuration-file) for how your configuration file should be defined. ### How does interrupt work? When you select the `Interrupts` dropdown and select a node to interrupt the graph will pause execution before and after (unless the node goes straight to `END`) that node has run. This means that you will be able to both edit the state before the node is ran and the state after the node has ran. This is intended to allow developers more fine-grained control over the behavior of a node and make it easier to observe how the node is behaving. You will not be able to edit the state after the node has ran if the node is the final node in the graph. -### How do I reload the app? (desktop only) +For more information on interrupts and human in the loop, see [here](./human_in_the_loop.md). -If you would like to reload the app, don't use Command+R as you might normally do. Instead, close and reopen the app for a full refresh. - -### How does automatic rebuilding work? (desktop only) - -One of the key features of LangGraph Studio is that it automatically rebuilds your image when you change the source code. This allows for a super fast development and testing cycle which makes it easy to iterate on your graph. There are two different ways that LangGraph rebuilds your image: either by editing the image or completely rebuilding it. - -#### Rebuilds from source code changes - -If you modified the source code only (no configuration or dependency changes!) then the image does not require a full rebuild, and LangGraph Studio will only update the relevant parts. The UI status in the bottom left will switch from `Online` to `Stopping` temporarily while the image gets edited. The logs will be shown as this process is happening, and after the image has been edited the status will change back to `Online` and you will be able to run your graph with the modified code! - - -#### Rebuilds from configuration or dependency changes - -If you edit your graph configuration file (`langgraph.json`) or the dependencies (either `pyproject.toml` or `requirements.txt`) then the entire image will be rebuilt. This will cause the UI to switch away from the graph view and start showing the logs of the new image building process. This can take a minute or two, and once it is done your updated image will be ready to use! - -### Why is my graph taking so long to startup? (desktop only) - -The LangGraph Studio interacts with a local LangGraph API server. To stay aligned with ongoing updates, the LangGraph API requires regular rebuilding. As a result, you may occasionally experience slight delays when starting up your project. - -## Why are extra edges showing up in my graph? +### Why are extra edges showing up in my graph? If you don't define your conditional edges carefully, you might notice extra edges appearing in your graph. This is because without proper definition, LangGraph Studio assumes the conditional edge could access all other nodes. In order for this to not be the case, you need to be explicit about how you define the nodes the conditional edge routes to. There are two ways you can do this: -### Solution 1: Include a path map +#### Solution 1: Include a path map The first way to solve this is to add path maps to your conditional edges. A path map is just a dictionary or array that maps the possible outputs of your router function with the names of the nodes that each output corresponds to. The path map is passed as the third argument to the `add_conditional_edges` function like so: @@ -120,7 +88,7 @@ The first way to solve this is to add path maps to your conditional edges. A pat In this case, the routing function returns either True or False, which map to `node_b` and `node_c` respectively. -### Solution 2: Update the typing of the router (Python only) +#### Solution 2: Update the typing of the router (Python only) Instead of passing a path map, you can also be explicit about the typing of your routing function by specifying the nodes it can map to using the `Literal` python definition. Here is an example of how to define a routing function in that way: @@ -132,9 +100,48 @@ def routing_function(state: GraphState) -> Literal["node_b","node_c"]: return "node_c" ``` +### Studio Desktop FAQs -## Related +!!! warning "Deprecation Warning" + In order to support a wider range of platforms and users, we now recommend following the above instructions to connect to LangGraph Studio using the development server instead of the desktop app. -For more information please see the following: +The LangGraph Studio Desktop App is a standalone application that allows you to connect to your LangGraph application and visualize and interact with your graph. It is available for MacOS only and requires Docker to be installed. -* [LangGraph Studio how-to guides](../how-tos/index.md#langgraph-studio) \ No newline at end of file +#### Why is my project failing to start? + +In addition to the reasons listed above, for the desktop app there are a few more reasons that your project might fail to start: + +!!! Important "Note " + + LangGraph Studio Desktop automatically populates `LANGCHAIN_*` environment variables for license verification and tracing, regardless of the contents of the `.env` file. All other environment variables defined in `.env` will be read as normal. + +##### Docker issues + +LangGraph Studio (desktop) requires Docker Desktop version 4.24 or higher. Please make sure you have a version of Docker installed that satisfies that requirement and also make sure you have the Docker Desktop app up and running before trying to use LangGraph Studio. In addition, make sure you have docker-compose updated to version 2.22.0 or higher. + +##### Incorrect data region + +If you receive a license verification error when attempting to start the LangGraph Server, you may be logged into the incorrect LangSmith data region. Ensure that you're logged into the correct LangSmith data region and ensure that the LangSmith account has access to LangGraph platform. + +1. In the top right-hand corner, click the user icon and select `Logout`. +1. At the login screen, click the `Data Region` dropdown menu and select the appropriate data region. Then click `Login to LangSmith`. + +### How do I reload the app? + +If you would like to reload the app, don't use Command+R as you might normally do. Instead, close and reopen the app for a full refresh. + +### How does automatic rebuilding work? + +One of the key features of LangGraph Studio is that it automatically rebuilds your image when you change the source code. This allows for a super fast development and testing cycle which makes it easy to iterate on your graph. There are two different ways that LangGraph rebuilds your image: either by editing the image or completely rebuilding it. + +#### Rebuilds from source code changes + +If you modified the source code only (no configuration or dependency changes!) then the image does not require a full rebuild, and LangGraph Studio will only update the relevant parts. The UI status in the bottom left will switch from `Online` to `Stopping` temporarily while the image gets edited. The logs will be shown as this process is happening, and after the image has been edited the status will change back to `Online` and you will be able to run your graph with the modified code! + +#### Rebuilds from configuration or dependency changes + +If you edit your graph configuration file (`langgraph.json`) or the dependencies (either `pyproject.toml` or `requirements.txt`) then the entire image will be rebuilt. This will cause the UI to switch away from the graph view and start showing the logs of the new image building process. This can take a minute or two, and once it is done your updated image will be ready to use! + +### Why is my graph taking so long to startup? + +The LangGraph Studio interacts with a local LangGraph API server. To stay aligned with ongoing updates, the LangGraph API requires regular rebuilding. As a result, you may occasionally experience slight delays when starting up your project. diff --git a/docs/docs/concepts/low_level.md b/docs/docs/concepts/low_level.md index 82eda47a5..7810195d5 100644 --- a/docs/docs/concepts/low_level.md +++ b/docs/docs/concepts/low_level.md @@ -310,7 +310,7 @@ graph.add_conditional_edges(START, routing_function, {True: "node_b", False: "no ## `Send` -By default, `Nodes` and `Edges` are defined ahead of time and operate on the same shared state. However, there can be cases where the exact edges are not known ahead of time and/or you may want different versions of `State` to exist at the same time. A common example of this is with `map-reduce` design patterns. In this design pattern, a first node may generate a list of objects, and you may want to apply some other node to all those objects. The number of objects may be unknown ahead of time (meaning the number of edges may not be known) and the input `State` to the downstream `Node` should be different (one for each generated object). +By default, `Nodes` and `Edges` are defined ahead of time and operate on the same shared state. However, there can be cases where the exact edges are not known ahead of time and/or you may want different versions of `State` to exist at the same time. A common example of this is with [map-reduce](https://langchain-ai.github.io/langgraph/how-tos/map-reduce/) design patterns. In this design pattern, a first node may generate a list of objects, and you may want to apply some other node to all those objects. The number of objects may be unknown ahead of time (meaning the number of edges may not be known) and the input `State` to the downstream `Node` should be different (one for each generated object). To support this design pattern, LangGraph supports returning [`Send`][langgraph.types.Send] objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node. diff --git a/docs/docs/concepts/persistence.md b/docs/docs/concepts/persistence.md index 7f4519e3f..a7684cc2a 100644 --- a/docs/docs/concepts/persistence.md +++ b/docs/docs/concepts/persistence.md @@ -32,7 +32,7 @@ from typing_extensions import TypedDict from operator import add class State(TypedDict): - foo: int + foo: str bar: Annotated[list[str], add] def node_a(state: State): diff --git a/docs/docs/how-tos/create-react-agent-memory.ipynb b/docs/docs/how-tos/create-react-agent-memory.ipynb index c783eb774..b109db3a0 100644 --- a/docs/docs/how-tos/create-react-agent-memory.ipynb +++ b/docs/docs/how-tos/create-react-agent-memory.ipynb @@ -220,7 +220,7 @@ "id": "838a043f-90ad-4e69-9d1d-6e22db2c346c", "metadata": {}, "source": [ - "Notice that when we pass the same the same thread ID, the chat history is preserved" + "Notice that when we pass the same thread ID, the chat history is preserved." ] }, { diff --git a/docs/docs/how-tos/index.md b/docs/docs/how-tos/index.md index 31b9755e4..11acef33c 100644 --- a/docs/docs/how-tos/index.md +++ b/docs/docs/how-tos/index.md @@ -59,12 +59,10 @@ LangGraph makes it easy to manage conversation [memory](../concepts/memory.md) i [Human-in-the-loop](../concepts/human_in_the_loop.md) functionality allows you to involve humans in the decision-making process of your graph. These how-to guides show how to implement human-in-the-loop workflows in your graph. - Key workflows: - [How to wait for user input](human_in_the_loop/wait-user-input.ipynb): A basic example that shows how to implement a human-in-the-loop workflow in your graph using the `interrupt` function. - [How to review tool calls](human_in_the_loop/review-tool-calls.ipynb): Incorporate human-in-the-loop for reviewing/editing/accepting tool call requests before they executed using the `interrupt` function. - Other methods: @@ -290,10 +288,9 @@ Graph execution can take a while, and sometimes users may change their mind abou LangGraph Studio is a built-in UI for visualizing, testing, and debugging your agents. -- [How to connect to a LangGraph Cloud deployment](../cloud/how-tos/test_deployment.md) +- [How to connect to a LangGraph Platform deployment](../cloud/how-tos/test_deployment.md) - [How to connect to a local dev server](../how-tos/local-studio.md) - [How to connect to a local deployment (Docker)](../cloud/how-tos/test_local_deployment.md) -- [How to test your graph in LangGraph Studio (MacOS only)](../cloud/how-tos/invoke_studio.md) - [How to interact with threads in LangGraph Studio](../cloud/how-tos/threads_studio.md) - [How to add nodes as dataset examples in LangGraph Studio](../cloud/how-tos/datasets_studio.md) - [How to engineer prompts in LangGraph Studio](../cloud/how-tos/iterate_graph_studio.md) @@ -312,4 +309,4 @@ These are the guides for resolving common errors you may find while building wit These guides provide troubleshooting information for errors that are specific to the LangGraph Platform. -- [INVALID_LICENSE](../troubleshooting/errors/INVALID_LICENSE.md) \ No newline at end of file +- [INVALID_LICENSE](../troubleshooting/errors/INVALID_LICENSE.md) diff --git a/docs/docs/how-tos/local-studio.md b/docs/docs/how-tos/local-studio.md index 3a892386a..2f83f4c23 100644 --- a/docs/docs/how-tos/local-studio.md +++ b/docs/docs/how-tos/local-studio.md @@ -1,15 +1,6 @@ # How to connect a local agent to LangGraph Studio -This guide shows you how to connect your local agent to [LangGraph Studio](../concepts/langgraph_studio.md) for visualization, interaction, and debugging. - -## Connection Options - -There are two ways to connect your local agent to LangGraph Studio: - -- [Development Server](../concepts/langgraph_studio.md#development-server-with-web-ui): Python package, all platforms, no Docker -- [LangGraph Desktop](../concepts/langgraph_studio.md#desktop-app): Application, Mac only, requires Docker - -In this guide we will cover how to use the development server as that is generally an easier and better experience. +This guide shows you how to connect your local agent to [LangGraph Studio](../concepts/langgraph_studio.md) for visualization, interaction, and debugging using the development server. ## Setup your application @@ -24,9 +15,8 @@ You will need to make sure to install the `inmem` extras. ???+ note "Minimum version" - The minimum version to use the `inmem` extra with `langgraph-cli` is `0.1.55`. - Python 3.11 or higher is required. - +The minimum version to use the `inmem` extra with `langgraph-cli` is `0.1.55`. +Python 3.11 or higher is required. ```shell pip install -U "langgraph-cli[inmem]" @@ -41,7 +31,7 @@ pip install -U "langgraph-cli[inmem]" langgraph dev ``` -This will look for the `langgraph.json` file in your current directory. +This will look for the `langgraph.json` file in your current directory. In there, it will find the paths to the graph(s), and start those up. It will then automatically connect to the cloud-hosted studio. @@ -89,4 +79,4 @@ Then attach your preferred debugger: 2. Click + and select "Python Debug Server" 3. Set IDE host name: `localhost` 4. Set port: `5678` (or the port number you chose in the previous step) - 5. Click "OK" and start debugging \ No newline at end of file + 5. Click "OK" and start debugging diff --git a/docs/docs/how-tos/memory/add-summary-conversation-history.ipynb b/docs/docs/how-tos/memory/add-summary-conversation-history.ipynb index 9fb7af8de..26a1ce61e 100644 --- a/docs/docs/how-tos/memory/add-summary-conversation-history.ipynb +++ b/docs/docs/how-tos/memory/add-summary-conversation-history.ipynb @@ -10,6 +10,7 @@ "One of the most common use cases for persistence is to use it to keep track of conversation history. This is great - it makes it easy to continue conversations. As conversations get longer and longer, however, this conversation history can build up and take up more and more of the context window. This can often be undesirable as it leads to more expensive and longer calls to the LLM, and potentially ones that error. One way to work around that is to create a summary of the conversation to date, and use that with the past N messages. This guide will go through an example of how to do that.\n", "\n", "This will involve a few steps:\n", + "\n", "- Check if the conversation is too long (can be done by checking number of messages or length of messages)\n", "- If yes, the create summary (will need a prompt for this)\n", "- Then remove all except the last N messages\n", diff --git a/docs/docs/llms.txt b/docs/docs/llms.txt new file mode 100644 index 000000000..b47911bf4 --- /dev/null +++ b/docs/docs/llms.txt @@ -0,0 +1,191 @@ +# LangGraph + +## Quickstart + +These guides are designed to help you get started with LangGraph. + +- [LangGraph Quickstart](https://langchain-ai.github.io/langgraph/tutorials/introduction/): Build a chatbot that can use tools and keep track of conversation history. Add human-in-the-loop capabilities and explore how time-travel works. +- [Common Workflows](https://langchain-ai.github.io/langgraph/tutorials/workflows/): Overview of the most common workflows using LLMs implemented with LangGraph. +- [LangGraph Server Quickstart](https://langchain-ai.github.io/langgraph/tutorials/langgraph-platform/local-server/): Launch a LangGraph server locally and interact with it using REST API and LangGraph Studio Web UI. +- [Deploy with LangGraph Cloud Quickstart](https://langchain-ai.github.io/langgraph/cloud/quick_start/): Deploy a LangGraph app using LangGraph Cloud. + +## Concepts + +These guides provide explanations of the key concepts behind the LangGraph framework. + +- [Why LangGraph?](https://langchain-ai.github.io/langgraph/concepts/high_level/): Motivation for LangGraph, a library for building agentic applications with LLMs. +- [LangGraph Glossary](https://langchain-ai.github.io/langgraph/concepts/low_level/): LangGraph workflows are designed as graphs, with nodes representing different components and edges representing the flow of information between them. This guide provides an overview of the key concepts associated with LangGraph graph primitives. +- [Common Agentic Patterns](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/): An agent uses an LLM to pick its own control flow to solve more complex problems! Agents are a key building block in many LLM applications. This guide explains the different types of agent architectures and how they can be used to control the flow of an application. +- [Multi-Agent Systems](https://langchain-ai.github.io/langgraph/concepts/multi_agent/): Complex LLM applications can often be broken down into multiple agents, each responsible for a different part of the application. This guide explains common patterns for building multi-agent systems. +- [Breakpoints](https://langchain-ai.github.io/langgraph/concepts/breakpoints/): Breakpoints allow pausing the execution of a graph at specific points. Breakpoints allow stepping through graph execution for debugging purposes. +- [Human-in-the-Loop](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/): Explains different ways of integrating human feedback into a LangGraph application. +- [Time Travel](https://langchain-ai.github.io/langgraph/concepts/time-travel/): Time travel allows you to replay past actions in your LangGraph application to explore alternative paths and debug issues. +- [Persistence](https://langchain-ai.github.io/langgraph/concepts/persistence/): LangGraph has a built-in persistence layer, implemented through checkpointers. This persistence layer helps to support powerful capabilities like human-in-the-loop, memory, time travel, and fault-tolerance. +- [Memory](https://langchain-ai.github.io/langgraph/concepts/memory/): Memory in AI applications refers to the ability to process, store, and effectively recall information from past interactions. With memory, your agents can learn from feedback and adapt to users' preferences. +- [Streaming](https://langchain-ai.github.io/langgraph/concepts/streaming/): Streaming is crucial for enhancing the responsiveness of applications built on LLMs. By displaying output progressively, even before a complete response is ready, streaming significantly improves user experience (UX), particularly when dealing with the latency of LLMs. +- [Functional API](https://langchain-ai.github.io/langgraph/concepts/functional_api/): `@entrypoint` and `@task` decorators that allow you to add LangGraph functionality to an existing codebase. +- [Durable Execution](https://langchain-ai.github.io/langgraph/concepts/durable_execution/): LangGraph's built-in [persistence](https://langchain-ai.github.io/langgraph/concepts/persistence/) layer provides durable execution for workflows, ensuring that the state of each execution step is saved to a durable store. +- [Pregel](https://langchain-ai.github.io/langgraph/concepts/pregel/): Pregel is LangGraph's runtime, which is responsible for managing the execution of LangGraph applications. +- [FAQ](https://langchain-ai.github.io/langgraph/concepts/faq/): Frequently asked questions about LangGraph. + +## How-tos + +Here you’ll find answers to “How do I...?” types of questions. + +These guides are **goal-oriented** and concrete. + +They're meant to help you complete a specific task. + +### Graph API Basics + +- [How to update graph state from nodes](https://langchain-ai.github.io/langgraph/how-tos/state-reducers/) +- [How to create a sequence of steps](https://langchain-ai.github.io/langgraph/how-tos/sequence/) +- [How to create branches for parallel execution](https://langchain-ai.github.io/langgraph/how-tos/branching/) +- [How to create and control loops with recursion limits](https://langchain-ai.github.io/langgraph/how-tos/recursion-limit/) +- [How to visualize your graph](https://langchain-ai.github.io/langgraph/how-tos/visualization/) + +### Fine-grained Control + +These guides demonstrate LangGraph features that grant fine-grained control over the execution of your graph. + +- [How to create map-reduce branches for parallel execution](https://langchain-ai.github.io/langgraph/how-tos/map-reduce/) +- [How to update state and jump to nodes in graphs and subgraphs](https://langchain-ai.github.io/langgraph/how-tos/command/) +- [How to add runtime configuration to your graph](https://langchain-ai.github.io/langgraph/how-tos/configuration/) +- [How to add node retries](https://langchain-ai.github.io/langgraph/how-tos/node-retries/) +- [How to return state before hitting recursion limit](https://langchain-ai.github.io/langgraph/how-tos/return-when-recursion-limit-hits/) + +### Persistence + +Persistence makes it easy to persist state across graph runs (per-thread persistence) and across threads (cross-thread persistence). + +These how-to guides show how to add persistence to your graph. + +- [How to add thread-level persistence to your graph](https://langchain-ai.github.io/langgraph/how-tos/persistence/) +- [How to add thread-level persistence to a subgraph](https://langchain-ai.github.io/langgraph/how-tos/subgraph-persistence/) +- [How to add cross-thread persistence to your graph](https://langchain-ai.github.io/langgraph/how-tos/cross-thread-persistence/) +- [How to use Postgres checkpointer for persistence](https://langchain-ai.github.io/langgraph/how-tos/persistence_postgres/) +- [How to use MongoDB checkpointer for persistence](https://langchain-ai.github.io/langgraph/how-tos/persistence_mongodb/) +- [How to create a custom checkpointer using Redis](https://langchain-ai.github.io/langgraph/how-tos/persistence_redis/) + +See the below guides for how-to add persistence to your workflow using the [Functional API](https://langchain-ai.github.io/langgraph/concepts/functional_api/): + +- [How to add thread-level persistence (functional API)](https://langchain-ai.github.io/langgraph/how-tos/persistence-functional/) +- [How to add cross-thread persistence (functional API)](https://langchain-ai.github.io/langgraph/how-tos/cross-thread-persistence-functional/) + +### Memory + +LangGraph makes it easy to manage conversation memory in your graph. These how-to guides show how to implement different strategies for that. + +- [How to manage conversation history](https://langchain-ai.github.io/langgraph/how-tos/memory/manage-conversation-history/) +- [How to delete messages](https://langchain-ai.github.io/langgraph/how-tos/memory/delete-messages/) +- [How to add summary conversation memory](https://langchain-ai.github.io/langgraph/how-tos/memory/add-summary-conversation-history/) +- [How to add long-term memory (cross-thread)](https://langchain-ai.github.io/langgraph/how-tos/memory/cross-thread-persistence/) +- [How to use semantic search for long-term memory](https://langchain-ai.github.io/langgraph/how-tos/memory/semantic-search/) + +### Human-in-the-loop + +Human-in-the-loop functionality allows you to involve humans in the decision-making process of your graph. + +These how-to guides show how to implement human-in-the-loop workflows in your graph. + +- [How to wait for user input](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/wait-user-input/): A basic example that shows how to implement a human-in-the-loop workflow in your graph using the `interrupt` function. +- [How to review tool calls](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/review-tool-calls/): Incorporate human-in-the-loop for reviewing/editing/accepting tool call requests before they executed using the `interrupt` function. +- [How to add static breakpoints](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/breakpoints/): Use for debugging purposes. For human-in-the-loop workflows, we recommend the [`interrupt` function](https://langchain-ai.github.io/langgraph/reference/types/#langgraph.types.interrupt) instead. +- [How to edit graph state](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/edit-graph-state/): Edit graph state using `graph.update_state` method. Use this if implementing a **human-in-the-loop** workflow via **static breakpoints**. + +See the below guides for how-to implement human-in-the-loop workflows with the Functional API. + +- [How to wait for user input (Functional API)](https://langchain-ai.github.io/langgraph/how-tos/wait-user-input-functional/) +- [How to review tool calls (Functional API)](https://langchain-ai.github.io/langgraph/how-tos/review-tool-calls-functional/) + +### Time Travel + +[Time travel](https://langchain-ai.github.io/langgraph/concepts/time-travel/) allows you to replay past actions in your LangGraph application to explore alternative paths and debug issues. These how-to guides show how to use time travel in your graph. + +- [How to view and update past graph state](https://langchain-ai.github.io/langgraph/how-tos/time-travel/) + +### Streaming + +[Streaming](https://langchain-ai.github.io/langgraph/concepts/streaming/) is crucial for enhancing the responsiveness of applications built on LLMs. By displaying output progressively, even before a complete response is ready, streaming significantly improves user experience (UX), particularly when dealing with the latency of LLMs. + +- [How to stream](https://langchain-ai.github.io/langgraph/how-tos/streaming/) +- [How to stream LLM tokens](https://langchain-ai.github.io/langgraph/how-tos/streaming-tokens/) +- [How to stream LLM tokens from specific nodes](https://langchain-ai.github.io/langgraph/how-tos/streaming-specific-nodes/) +- [How to stream data from within a tool](https://langchain-ai.github.io/langgraph/how-tos/streaming-events-from-within-tools/) +- [How to stream from subgraphs](https://langchain-ai.github.io/langgraph/how-tos/streaming-subgraphs/) +- [How to disable streaming for models that don't support it](https://langchain-ai.github.io/langgraph/how-tos/disable-streaming/) + +### Tool calling + +[Tool calling](https://python.langchain.com/docs/concepts/tool_calling/) is a type of [chat model](https://python.langchain.com/docs/concepts/chat_models/) API. + +It accepts tool schemas, along with messages, as input and returns invocations of those tools as part of the output message. + +These how-to guides show common patterns for tool calling with LangGraph: + +- [How to call tools using ToolNode](https://langchain-ai.github.io/langgraph/how-tos/tool-calling/) +- [How to handle tool calling errors](https://langchain-ai.github.io/langgraph/how-tos/tool-calling-errors/) +- [How to pass runtime values to tools](https://langchain-ai.github.io/langgraph/how-tos/pass-run-time-values-to-tools/) +- [How to pass config to tools](https://langchain-ai.github.io/langgraph/how-tos/pass-config-to-tools/) +- [How to update graph state from tools](https://langchain-ai.github.io/langgraph/how-tos/update-state-from-tools/) +- [How to handle large numbers of tools](https://langchain-ai.github.io/langgraph/how-tos/many-tools/) + +### Subgraphs + +Subgraphs allow you to reuse an existing graph from another graph. + +These how-to guides show how to use subgraphs: + +- [How to use subgraphs](https://langchain-ai.github.io/langgraph/how-tos/subgraph/) +- [How to view and update state in subgraphs](https://langchain-ai.github.io/langgraph/how-tos/subgraphs-manage-state/) +- [How to transform inputs and outputs of a subgraph](https://langchain-ai.github.io/langgraph/how-tos/subgraph-transform-state/) + +### Multi-agent + +Multi-agent systems are useful to break down complex LLM applications into multiple agents, each responsible for a different part of the application. + +These how-to guides show how to implement multi-agent systems in LangGraph: + +- [How to implement handoffs between agents](https://langchain-ai.github.io/langgraph/how-tos/agent-handoffs/) +- [How to build a multi-agent network](https://langchain-ai.github.io/langgraph/how-tos/multi-agent-network/) +- [How to add multi-turn conversation in a multi-agent application](https://langchain-ai.github.io/langgraph/how-tos/multi-agent-multi-turn-convo/) + +### State Management + +- [How to use Pydantic model as graph state](https://langchain-ai.github.io/langgraph/how-tos/state-model/) +- [How to define input/output schema for your graph](https://langchain-ai.github.io/langgraph/how-tos/input_output_schema/) +- [How to pass private state between nodes inside the graph](https://langchain-ai.github.io/langgraph/how-tos/pass_private_state/) + +### Other + +- [How to run graph asynchronously](https://langchain-ai.github.io/langgraph/how-tos/async/) +- [How to force tool-calling agent to structure output](https://langchain-ai.github.io/langgraph/how-tos/react-agent-structured-output/) +- [How to pass custom LangSmith run ID for graph runs](https://langchain-ai.github.io/langgraph/how-tos/run-id-langsmith/) +- [How to integrate LangGraph with AutoGen, CrewAI, and other frameworks](https://langchain-ai.github.io/langgraph/how-tos/autogen-integration/) + +## Use cases + +Explore practical implementations tailored for specific scenarios: + +### Chatbots + +- [Customer Support](https://langchain-ai.github.io/langgraph/tutorials/customer-support/customer-support/): Build a multi-functional support bot for flights, hotels, and car rentals. +- [Prompt Generation from User Requirements](https://langchain-ai.github.io/langgraph/tutorials/chatbots/information-gather-prompting/): Build an information gathering chatbot. +- [Code Assistant](https://langchain-ai.github.io/langgraph/tutorials/code_assistant/langgraph_code_assistant/): Build a code analysis and generation assistant. + +### RAG + +- [Agentic RAG](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_agentic_rag/): Use an agent to figure out how to retrieve the most relevant information before using the retrieved information to answer the user's question. +- [Adaptive RAG](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_adaptive_rag/): Adaptive RAG is a strategy for RAG that unites (1) query analysis with (2) active / self-corrective RAG. Implementation of: https://arxiv.org/abs/2403.14403 + - For a version that uses a local LLM: [Adaptive RAG using local LLMs](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_adaptive_rag_local/) +- [Corrective RAG](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_crag/): Uses an LLM to grade the quality of the retrieved information from the given source, and if the quality is low, it will try to retrieve the information from another source. Implementation of: https://arxiv.org/pdf/2401.15884.pdf + - For a version that uses a local LLM: [Corrective RAG using local LLMs](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_crag_local/) +- [Self-RAG](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_self_rag/): Self-RAG is a strategy for RAG that incorporates self-reflection / self-grading on retrieved documents and generations. Implementation of https://arxiv.org/abs/2310.11511. + - For a version that uses a local LLM: [Self-RAG using local LLMs](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_self_rag_local/) +- [SQL Agent](https://langchain-ai.github.io/langgraph/tutorials/sql-agent/): Build a SQL agent that can answer questions about a SQL database. + +### Multi-Agent Systems + +- [Network](https://langchain-ai.github.io/langgraph/tutorials/multi_agent/multi-agent-collaboration/): Enable two or more agents to collaborate on a task +- [Supervisor](https://langchain-ai.github.io/langgraph/tutorials/multi_agent/agent_supervisor/): Use an LLM to orchestrate and delegate to individual agents +- [Hierarchical Teams](https://langchain-ai.github.io/langgraph/tutorials/multi_agent/hierarchical_agent_teams/): Orchestrate nested teams of agents to solve problems diff --git a/docs/docs/tutorials/workflows/index.md b/docs/docs/tutorials/workflows/index.md index 491af59c2..d3c61eee3 100644 --- a/docs/docs/tutorials/workflows/index.md +++ b/docs/docs/tutorials/workflows/index.md @@ -184,7 +184,7 @@ As noted in the [Anthropic blog](https://www.anthropic.com/research/building-eff See our lesson on Prompt Chaining [here](https://github.com/langchain-ai/langchain-academy/blob/main/module-1/chain.ipynb). -=== "Functional API (beta)" +=== "Functional API" ```python from langgraph.func import entrypoint, task @@ -335,7 +335,7 @@ With parallelization, LLMs work simultaneously on a task: See our lesson on parallelization [here](https://github.com/langchain-ai/langchain-academy/blob/main/module-1/simple-graph.ipynb). -=== "Functional API (beta)" +=== "Functional API" ```python @task @@ -524,7 +524,7 @@ Routing classifies an input and directs it to a followup task. As noted in the [ [Here](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_adaptive_rag_local/) is RAG workflow that routes questions. See our video [here](https://www.youtube.com/watch?v=bq1Plo2RhYI). -=== "Functional API (beta)" +=== "Functional API" ```python from typing_extensions import Literal @@ -761,7 +761,7 @@ With orchestrator-worker, an orchestrator breaks down a task and delegates each [Here](https://github.com/langchain-ai/report-mAIstro) is a project that uses orchestrator-worker for report planning and writing. See our video [here](https://www.youtube.com/watch?v=wSxZ7yFbbas). -=== "Functional API (beta)" +=== "Functional API" ```python from typing import List @@ -952,7 +952,7 @@ In the evaluator-optimizer workflow, one LLM call generates a response while ano [Here](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_adaptive_rag_local/) is a RAG workflow that grades answers for hallucinations or errors. See our video [here](https://www.youtube.com/watch?v=bq1Plo2RhYI). -=== "Functional API (beta)" +=== "Functional API" ```python # Schema for structured output to use in evaluation @@ -1161,7 +1161,7 @@ llm_with_tools = llm.bind_tools(tools) [Here](https://github.com/langchain-ai/memory-agent) is a project that uses a tool calling agent to create / store long-term memories. -=== "Functional API (beta)" +=== "Functional API" ```python from langgraph.graph import add_messages @@ -1270,4 +1270,4 @@ LangGraph provides several ways to stream workflow / agent outputs or intermedia ### Deployment -LangGraph provides an easy on-ramp for deployment, observability, and evaluation. See [module 6](https://github.com/langchain-ai/langchain-academy/tree/main/module-6) of LangChain Academy. \ No newline at end of file +LangGraph provides an easy on-ramp for deployment, observability, and evaluation. See [module 6](https://github.com/langchain-ai/langchain-academy/tree/main/module-6) of LangChain Academy. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 68b2d1a83..6672888e1 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -359,7 +359,7 @@ nav: - Resources: # NOTE: prebuilt.md is auto-generated by `make build-prebuilt` - Prebuilt Agents: prebuilt.md - - Adopters: adopters.md + - Companies using LangGraph: adopters.md - FAQ: concepts/faq.md - Troubleshooting: - Troubleshooting: troubleshooting/errors/index.md diff --git a/docs/poetry.lock b/docs/poetry.lock index 46f77bb2b..31b7289d7 100644 --- a/docs/poetry.lock +++ b/docs/poetry.lock @@ -169,15 +169,15 @@ files = [ [[package]] name = "anthropic" -version = "0.45.2" +version = "0.47.2" description = "The official Python library for the anthropic API" optional = false python-versions = ">=3.8" groups = ["test"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "anthropic-0.45.2-py3-none-any.whl", hash = "sha256:ecd746f7274451dfcb7e1180571ead624c7e1195d1d46cb7c70143d2aedb4d35"}, - {file = "anthropic-0.45.2.tar.gz", hash = "sha256:32a18b9ecd12c91b2be4cae6ca2ab46a06937b5aa01b21308d97a6d29794fb5e"}, + {file = "anthropic-0.47.2-py3-none-any.whl", hash = "sha256:61b712a56308fce69f04d92ba0230ab2bc187b5bce17811d400843a8976bb67f"}, + {file = "anthropic-0.47.2.tar.gz", hash = "sha256:452f4ca0c56ffab8b6ce9928bf8470650f88106a7001b250895eb65c54cfa44c"}, ] [package.dependencies] @@ -1299,7 +1299,7 @@ version = "0.7.1" description = "XML bomb protection for Python stdlib modules" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["docs", "test"] +groups = ["docs"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, @@ -3288,21 +3288,20 @@ together = ["langchain-together"] [[package]] name = "langchain-anthropic" -version = "0.2.4" +version = "0.3.8" description = "An integration package connecting AnthropicMessages and LangChain" optional = false python-versions = "<4.0,>=3.9" groups = ["test"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "langchain_anthropic-0.2.4-py3-none-any.whl", hash = "sha256:bcb6c2d0df4a67aff52816621079d6e743b260911caccf313a72b33b7edece6f"}, - {file = "langchain_anthropic-0.2.4.tar.gz", hash = "sha256:0382d4c7b5236839b703f7b72b3e06de4bb5be99104b193f719adbe34c49562b"}, + {file = "langchain_anthropic-0.3.8-py3-none-any.whl", hash = "sha256:05a70f51500d3c4e0f3e463730e193a25b6244e06b3bda3d7b2ec21d83d081ae"}, + {file = "langchain_anthropic-0.3.8.tar.gz", hash = "sha256:1932977b8105744739ffdcb39861b041b73ae93846d0896a775fcea9a29e4b2b"}, ] [package.dependencies] -anthropic = ">=0.30.0,<1" -defusedxml = ">=0.7.1,<0.8.0" -langchain-core = ">=0.3.15,<0.4.0" +anthropic = ">=0.47.0,<1" +langchain-core = ">=0.3.39,<1.0.0" pydantic = ">=2.7.4,<3.0.0" [[package]] @@ -3357,15 +3356,15 @@ tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10" [[package]] name = "langchain-core" -version = "0.3.34" +version = "0.3.40" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" groups = ["docs", "test"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "langchain_core-0.3.34-py3-none-any.whl", hash = "sha256:a057ebeddd2158d3be14bde341b25640ddf958b6989bd6e47160396f5a8202ae"}, - {file = "langchain_core-0.3.34.tar.gz", hash = "sha256:26504cf1e8e6c310adad907b890d4e3c147581cfa7434114f6dc1134fe4bc6d3"}, + {file = "langchain_core-0.3.40-py3-none-any.whl", hash = "sha256:9f31358741f10a13db8531e8288b8a5ae91904018c5c2e6f739d6645a98fca03"}, + {file = "langchain_core-0.3.40.tar.gz", hash = "sha256:893a238b38491967c804662c1ec7c3e6ebaf223d1125331249c3cf3862ff2746"}, ] [package.dependencies] @@ -3474,19 +3473,19 @@ ollama = ">=0.4.4,<1" [[package]] name = "langchain-openai" -version = "0.3.4" +version = "0.3.7" description = "An integration package connecting OpenAI and LangChain" optional = false python-versions = "<4.0,>=3.9" groups = ["test"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "langchain_openai-0.3.4-py3-none-any.whl", hash = "sha256:58d0c014620eb92f4f46ff9daf584c2a7794896b1379eb85ad7be8d9f3493b61"}, - {file = "langchain_openai-0.3.4.tar.gz", hash = "sha256:c6645745a1d1bf19f21ea6fa473a746bd464053ff57ce563215e6165a0c4b9f1"}, + {file = "langchain_openai-0.3.7-py3-none-any.whl", hash = "sha256:0aefc7bdf8e7398d41e09c4313cace816df6438f2aa93d34f79523487310f0da"}, + {file = "langchain_openai-0.3.7.tar.gz", hash = "sha256:b8b51a3aaa1cc3bda060651ea41145f7728219e8a7150b5404fb1e8446de9cef"}, ] [package.dependencies] -langchain-core = ">=0.3.34,<1.0.0" +langchain-core = ">=0.3.39,<1.0.0" openai = ">=1.58.1,<2.0.0" tiktoken = ">=0.7,<1" @@ -3508,17 +3507,17 @@ langchain-core = ">=0.3.34,<1.0.0" [[package]] name = "langgraph" -version = "0.2.71" +version = "0.3.0" description = "Building stateful, multi-actor applications with LLMs" optional = false python-versions = ">=3.9.0,<4.0" -groups = ["docs", "test"] +groups = ["docs"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [] develop = true [package.dependencies] -langchain-core = ">=0.2.43,<0.4.0,!=0.3.0,!=0.3.1,!=0.3.2,!=0.3.3,!=0.3.4,!=0.3.5,!=0.3.6,!=0.3.7,!=0.3.8,!=0.3.9,!=0.3.10,!=0.3.11,!=0.3.12,!=0.3.13,!=0.3.14,!=0.3.15,!=0.3.16,!=0.3.17,!=0.3.18,!=0.3.19,!=0.3.20,!=0.3.21,!=0.3.22" +langchain-core = ">=0.1,<0.4" langgraph-checkpoint = "^2.0.10" langgraph-sdk = "^0.1.42" @@ -3528,7 +3527,7 @@ url = "../libs/langgraph" [[package]] name = "langgraph-checkpoint" -version = "2.0.13" +version = "2.0.16" description = "Library with base interfaces for LangGraph checkpoint savers." optional = false python-versions = "^3.9.0,<4.0" @@ -3547,26 +3546,25 @@ url = "../libs/checkpoint" [[package]] name = "langgraph-checkpoint-mongodb" -version = "0.1.0" +version = "0.1.1" description = "Library with a MongoDB implementation of LangGraph checkpoint saver." optional = false -python-versions = "<4.0.0,>=3.9.0" +python-versions = ">=3.9" groups = ["test"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "langgraph_checkpoint_mongodb-0.1.0-py3-none-any.whl", hash = "sha256:52f20956b36e0275ff805a1eea1db4c1a7e5e0ffe0a1ade65969004fa1654703"}, - {file = "langgraph_checkpoint_mongodb-0.1.0.tar.gz", hash = "sha256:3165c134ad5c82a3fe02fef04c81dcd48a3f5d031e07a9d1cb84457241f76793"}, + {file = "langgraph_checkpoint_mongodb-0.1.1-py3-none-any.whl", hash = "sha256:1ff2c3cb2a9139c38ea9cf398659b8b32d6bbfcc4999713b62014431477c5ac5"}, + {file = "langgraph_checkpoint_mongodb-0.1.1.tar.gz", hash = "sha256:350d347b0458fb7977231ac1295095bef512458ee0debe09fd394d913b8d89d3"}, ] [package.dependencies] -langgraph = ">=0.2.38,<0.3.0" -langgraph-checkpoint = ">=2.0.0,<3.0.0" +langgraph-checkpoint = ">=2.0.0" motor = ">3.5.0" -pymongo = ">=4.9.0,<4.10.0" +pymongo = ">=4.9,<4.12" [[package]] name = "langgraph-checkpoint-postgres" -version = "2.0.14" +version = "2.0.15" description = "Library with a Postgres implementation of LangGraph checkpoint saver." optional = false python-versions = "^3.9.0,<4.0" @@ -3576,7 +3574,7 @@ files = [] develop = true [package.dependencies] -langgraph-checkpoint = "^2.0.10" +langgraph-checkpoint = "^2.0.15" orjson = ">=3.10.1" psycopg = "^3.2.0" psycopg-pool = "^3.2.0" @@ -3587,7 +3585,7 @@ url = "../libs/checkpoint-postgres" [[package]] name = "langgraph-checkpoint-sqlite" -version = "2.0.4" +version = "2.0.5" description = "Library with a SQLite implementation of LangGraph checkpoint saver." optional = false python-versions = "^3.9.0" @@ -3597,20 +3595,40 @@ files = [] develop = true [package.dependencies] -aiosqlite = "^0.20.0" -langgraph-checkpoint = "^2.0.10" +aiosqlite = ">=0.20,<0.22" +langgraph-checkpoint = "^2.0.15" [package.source] type = "directory" url = "../libs/checkpoint-sqlite" +[[package]] +name = "langgraph-prebuilt" +version = "1.0.0" +description = "Library with high-level APIs for creating and executing LangGraph agents and tools." +optional = false +python-versions = "^3.9.0,<4.0" +groups = ["docs"] +markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" +files = [] +develop = true + +[package.dependencies] +langchain-core = ">=0.2.43,<0.4.0,!=0.3.0,!=0.3.1,!=0.3.2,!=0.3.3,!=0.3.4,!=0.3.5,!=0.3.6,!=0.3.7,!=0.3.8,!=0.3.9,!=0.3.10,!=0.3.11,!=0.3.12,!=0.3.13,!=0.3.14,!=0.3.15,!=0.3.16,!=0.3.17,!=0.3.18,!=0.3.19,!=0.3.20,!=0.3.21,!=0.3.22" +langgraph = ">=0.3,<0.4" +langgraph-checkpoint = "^2.0.10" + +[package.source] +type = "directory" +url = "../libs/prebuilt" + [[package]] name = "langgraph-sdk" -version = "0.1.51" +version = "0.1.53" description = "SDK for interacting with LangGraph API" optional = false python-versions = "^3.9.0,<4.0" -groups = ["docs", "test"] +groups = ["docs"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [] develop = true @@ -5939,7 +5957,6 @@ python-versions = ">=3.8" groups = ["test"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, ] @@ -5952,7 +5969,6 @@ python-versions = ">=3.8" groups = ["test"] markers = "python_version <= \"3.11\" or python_version >= \"3.12\"" files = [ - {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, ] @@ -8634,4 +8650,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "06debb82135affdb2baf1fdcc028c062c236121508d787588cd0de1db2da11e4" +content-hash = "ac9af57c6abaddd1f181551a7bb8194ef3e4491391a0f2dc71417d68e85cb5b3" diff --git a/docs/pyproject.toml b/docs/pyproject.toml index b916ed75a..d5994bc00 100644 --- a/docs/pyproject.toml +++ b/docs/pyproject.toml @@ -13,6 +13,7 @@ hub = "^3.0.1" [tool.poetry.group.docs.dependencies] langgraph = { path = "../libs/langgraph/", develop = true } +langgraph-prebuilt = {path = "../libs/prebuilt", develop = true} langgraph-checkpoint = { path = "../libs/checkpoint/", develop = true } langgraph-checkpoint-sqlite = { path = "../libs/checkpoint-sqlite", develop = true } langgraph-checkpoint-postgres = { path = "../libs/checkpoint-postgres", develop = true } @@ -40,8 +41,8 @@ langchain-cohere = "^0.4.2" [tool.poetry.group.test.dependencies] langchain = "^0.3.8" -langchain-openai = "^0.3.0" -langchain-anthropic = "^0.2.1" +langchain-openai = "^0.3.7" +langchain-anthropic = "^0.3.8" langchain-nomic = "^0.1.3" langchain-fireworks = "^0.2.0" langchain-community = "^0.3.0" diff --git a/libs/checkpoint-postgres/langgraph/store/postgres/aio.py b/libs/checkpoint-postgres/langgraph/store/postgres/aio.py index a8d434360..0615f0ec7 100644 --- a/libs/checkpoint-postgres/langgraph/store/postgres/aio.py +++ b/libs/checkpoint-postgres/langgraph/store/postgres/aio.py @@ -20,7 +20,7 @@ from langgraph.store.base import ( ) from langgraph.store.base.batch import AsyncBatchedBaseStore from langgraph.store.postgres.base import ( - _PLACEHOLDER, + PLACEHOLDER, BasePostgresStore, PoolConfig, PostgresIndexConfig, @@ -360,7 +360,7 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con for (idx, _), vector in zip(embedding_requests, vectors): _paramslist = queries[idx][1] for i in range(len(_paramslist)): - if _paramslist[i] is _PLACEHOLDER: + if _paramslist[i] is PLACEHOLDER: _paramslist[i] = vector for (idx, _), (query, params) in zip(search_ops, queries): diff --git a/libs/checkpoint-postgres/langgraph/store/postgres/base.py b/libs/checkpoint-postgres/langgraph/store/postgres/base.py index a3acc4744..c8445dd42 100644 --- a/libs/checkpoint-postgres/langgraph/store/postgres/base.py +++ b/libs/checkpoint-postgres/langgraph/store/postgres/base.py @@ -39,6 +39,7 @@ from langgraph.store.base import ( Result, SearchItem, SearchOp, + TTLConfig, ensure_embeddings, get_text_at_path, tokenize_path, @@ -370,7 +371,7 @@ class BasePostgresStore(Generic[C]): if op.query and self.index_config: embedding_requests.append((idx, op.query)) - score_operator, post_operator = _get_distance_operator(self) + score_operator, post_operator = get_distance_operator(self) vector_type = ( cast(PostgresIndexConfig, self.index_config) .get("ann_index_config", {}) @@ -430,10 +431,10 @@ class BasePostgresStore(Generic[C]): OFFSET %s """ params = [ - _PLACEHOLDER, # Vector placeholder + PLACEHOLDER, # Vector placeholder *ns_args, *filter_params, - _PLACEHOLDER, + PLACEHOLDER, expanded_limit, op.limit, op.offset, @@ -622,6 +623,7 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]): Callable[[Union[bytes, orjson.Fragment]], dict[str, Any]] ] = None, index: Optional[PostgresIndexConfig] = None, + ttl: Optional[TTLConfig] = None, ) -> None: super().__init__() self._deserializer = deserializer @@ -634,6 +636,7 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]): self.embeddings, self.index_config = _ensure_index_config(self.index_config) else: self.embeddings = None + self.ttl_config = ttl @classmethod @contextmanager @@ -828,7 +831,7 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]): for (idx, _), embedding in zip(embedding_requests, embeddings): _paramslist = queries[idx][1] for i in range(len(_paramslist)): - if _paramslist[i] is _PLACEHOLDER: + if _paramslist[i] is PLACEHOLDER: _paramslist[i] = embedding for (idx, _), (query, params) in zip(search_ops, queries): @@ -1055,7 +1058,7 @@ def _decode_ns_bytes(namespace: Union[str, bytes, list]) -> tuple[str, ...]: return tuple(namespace.split(".")) -def _get_distance_operator(store: Any) -> tuple[str, str]: +def get_distance_operator(store: Any) -> tuple[str, str]: """Get the distance operator and score expression based on config.""" # Note: Today, we are not using ANN indices due to restrictions # on PGVector's support for mixing vector and non-vector filters @@ -1121,4 +1124,4 @@ def _ensure_index_config( return embeddings, index_config -_PLACEHOLDER = object() +PLACEHOLDER = object() diff --git a/libs/checkpoint-postgres/poetry.lock b/libs/checkpoint-postgres/poetry.lock index 72b0b13f6..02f22bf76 100644 --- a/libs/checkpoint-postgres/poetry.lock +++ b/libs/checkpoint-postgres/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -6,7 +6,6 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -14,14 +13,13 @@ files = [ [[package]] name = "anyio" -version = "4.7.0" +version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ - {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, - {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, + {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, + {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, ] [package.dependencies] @@ -32,146 +30,209 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2024.8.30" +version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "charset-normalizer" -version = "3.4.0" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -groups = ["main", "dev"] +python-versions = ">=3.7" files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "codespell" -version = "2.3.0" -description = "Codespell" +version = "2.4.1" +description = "Fix common misspellings in text files" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ - {file = "codespell-2.3.0-py3-none-any.whl", hash = "sha256:a9c7cef2501c9cfede2110fd6d4e5e62296920efe9abfb84648df866e47f58d1"}, - {file = "codespell-2.3.0.tar.gz", hash = "sha256:360c7d10f75e65f67bad720af7007e1060a5d395670ec11a7ed1fed9dd17471f"}, + {file = "codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425"}, + {file = "codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5"}, ] [package.extras] @@ -186,8 +247,6 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] -markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -199,8 +258,6 @@ version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] -markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -215,7 +272,6 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -227,7 +283,6 @@ version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, @@ -245,14 +300,13 @@ trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" -version = "0.28.0" +version = "0.28.1" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ - {file = "httpx-0.28.0-py3-none-any.whl", hash = "sha256:dc0b419a0cfeb6e8b34e85167c0da2671206f5095f1baa9663d23bcfd6b535fc"}, - {file = "httpx-0.28.0.tar.gz", hash = "sha256:0858d3bab51ba7e386637f22a61d8ccddaeec5f3fe4209da3a6168dbb91573e0"}, + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, ] [package.dependencies] @@ -274,7 +328,6 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -289,7 +342,6 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -301,7 +353,6 @@ version = "1.33" description = "Apply JSON-Patches (RFC 6902)" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" -groups = ["main", "dev"] files = [ {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, @@ -316,7 +367,6 @@ version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, @@ -324,19 +374,18 @@ files = [ [[package]] name = "langchain-core" -version = "0.3.21" +version = "0.3.42" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" -groups = ["main", "dev"] files = [ - {file = "langchain_core-0.3.21-py3-none-any.whl", hash = "sha256:7e723dff80946a1198976c6876fea8326dc82566ef9bcb5f8d9188f738733665"}, - {file = "langchain_core-0.3.21.tar.gz", hash = "sha256:561b52b258ffa50a9fb11d7a1940ebfd915654d1ec95b35e81dfd5ee84143411"}, + {file = "langchain_core-0.3.42-py3-none-any.whl", hash = "sha256:5caadb508442e9794aa5dc5bbcc6ac21d2b1ecce856d98c0be82d36350abeefd"}, + {file = "langchain_core-0.3.42.tar.gz", hash = "sha256:3412bb9e9baa14d9c55c4da06eb9c55a4e2e94b856d030952396781f0d8bc736"}, ] [package.dependencies] jsonpatch = ">=1.33,<2.0" -langsmith = ">=0.1.125,<0.2.0" +langsmith = ">=0.1.125,<0.4" packaging = ">=23.2,<25" pydantic = [ {version = ">=2.5.2,<3.0.0", markers = "python_full_version < \"3.12.4\""}, @@ -348,11 +397,10 @@ typing-extensions = ">=4.7" [[package]] name = "langgraph-checkpoint" -version = "2.0.15" +version = "2.0.18" description = "Library with base interfaces for LangGraph checkpoint savers." optional = false python-versions = "^3.9.0,<4.0" -groups = ["main", "dev"] files = [] develop = true @@ -366,28 +414,30 @@ url = "../checkpoint" [[package]] name = "langsmith" -version = "0.1.147" +version = "0.3.13" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false -python-versions = "<4.0,>=3.8.1" -groups = ["main", "dev"] +python-versions = "<4.0,>=3.9" files = [ - {file = "langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15"}, - {file = "langsmith-0.1.147.tar.gz", hash = "sha256:2e933220318a4e73034657103b3b1a3a6109cc5db3566a7e8e03be8d6d7def7a"}, + {file = "langsmith-0.3.13-py3-none-any.whl", hash = "sha256:73aaf52bbc293b9415fff4f6dad68df40658081eb26c9cb2c7bd1ff57cedd695"}, + {file = "langsmith-0.3.13.tar.gz", hash = "sha256:14014058cff408772acb93344e03cb64174837292d5f1ae09b2c8c1d8df45e92"}, ] [package.dependencies] httpx = ">=0.23.0,<1" orjson = {version = ">=3.9.14,<4.0.0", markers = "platform_python_implementation != \"PyPy\""} +packaging = ">=23.2" pydantic = [ {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, ] requests = ">=2,<3" requests-toolbelt = ">=1.0.0,<2.0.0" +zstandard = ">=0.23.0,<0.24.0" [package.extras] langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"] +pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4,<14.0.0)"] [[package]] name = "msgpack" @@ -395,7 +445,6 @@ version = "1.1.0" description = "MessagePack serializer" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, @@ -465,50 +514,49 @@ files = [ [[package]] name = "mypy" -version = "1.13.0" +version = "1.15.0" description = "Optional static typing for Python" optional = false -python-versions = ">=3.8" -groups = ["dev"] +python-versions = ">=3.9" files = [ - {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, - {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, - {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, - {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, - {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, - {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, - {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, - {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, - {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, - {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, - {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, - {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, - {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, - {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, - {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, - {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, - {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, - {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, - {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, - {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, - {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, - {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, + {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"}, + {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"}, + {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"}, + {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"}, + {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"}, + {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"}, + {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"}, + {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"}, + {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"}, + {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"}, + {file = "mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078"}, + {file = "mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba"}, + {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5"}, + {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b"}, + {file = "mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2"}, + {file = "mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980"}, + {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"}, + {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"}, ] [package.dependencies] -mypy-extensions = ">=1.0.0" +mypy_extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.6.0" +typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] @@ -523,7 +571,6 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" -groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -531,87 +578,90 @@ files = [ [[package]] name = "orjson" -version = "3.10.12" +version = "3.10.15" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ - {file = "orjson-3.10.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ece01a7ec71d9940cc654c482907a6b65df27251255097629d0dea781f255c6d"}, - {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c34ec9aebc04f11f4b978dd6caf697a2df2dd9b47d35aa4cc606cabcb9df69d7"}, - {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd6ec8658da3480939c79b9e9e27e0db31dffcd4ba69c334e98c9976ac29140e"}, - {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17e6baf4cf01534c9de8a16c0c611f3d94925d1701bf5f4aff17003677d8ced"}, - {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6402ebb74a14ef96f94a868569f5dccf70d791de49feb73180eb3c6fda2ade56"}, - {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0000758ae7c7853e0a4a6063f534c61656ebff644391e1f81698c1b2d2fc8cd2"}, - {file = "orjson-3.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:888442dcee99fd1e5bd37a4abb94930915ca6af4db50e23e746cdf4d1e63db13"}, - {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c1f7a3ce79246aa0e92f5458d86c54f257fb5dfdc14a192651ba7ec2c00f8a05"}, - {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:802a3935f45605c66fb4a586488a38af63cb37aaad1c1d94c982c40dcc452e85"}, - {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1da1ef0113a2be19bb6c557fb0ec2d79c92ebd2fed4cfb1b26bab93f021fb885"}, - {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a3273e99f367f137d5b3fecb5e9f45bcdbfac2a8b2f32fbc72129bbd48789c2"}, - {file = "orjson-3.10.12-cp310-none-win32.whl", hash = "sha256:475661bf249fd7907d9b0a2a2421b4e684355a77ceef85b8352439a9163418c3"}, - {file = "orjson-3.10.12-cp310-none-win_amd64.whl", hash = "sha256:87251dc1fb2b9e5ab91ce65d8f4caf21910d99ba8fb24b49fd0c118b2362d509"}, - {file = "orjson-3.10.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a734c62efa42e7df94926d70fe7d37621c783dea9f707a98cdea796964d4cf74"}, - {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:750f8b27259d3409eda8350c2919a58b0cfcd2054ddc1bd317a643afc646ef23"}, - {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb52c22bfffe2857e7aa13b4622afd0dd9d16ea7cc65fd2bf318d3223b1b6252"}, - {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:440d9a337ac8c199ff8251e100c62e9488924c92852362cd27af0e67308c16ef"}, - {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e15c06491c69997dfa067369baab3bf094ecb74be9912bdc4339972323f252"}, - {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:362d204ad4b0b8724cf370d0cd917bb2dc913c394030da748a3bb632445ce7c4"}, - {file = "orjson-3.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b57cbb4031153db37b41622eac67329c7810e5f480fda4cfd30542186f006ae"}, - {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:165c89b53ef03ce0d7c59ca5c82fa65fe13ddf52eeb22e859e58c237d4e33b9b"}, - {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dee91b8dfd54557c1a1596eb90bcd47dbcd26b0baaed919e6861f076583e9da"}, - {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a4e1cfb72de6f905bdff061172adfb3caf7a4578ebf481d8f0530879476c07"}, - {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:038d42c7bc0606443459b8fe2d1f121db474c49067d8d14c6a075bbea8bf14dd"}, - {file = "orjson-3.10.12-cp311-none-win32.whl", hash = "sha256:03b553c02ab39bed249bedd4abe37b2118324d1674e639b33fab3d1dafdf4d79"}, - {file = "orjson-3.10.12-cp311-none-win_amd64.whl", hash = "sha256:8b8713b9e46a45b2af6b96f559bfb13b1e02006f4242c156cbadef27800a55a8"}, - {file = "orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d"}, - {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f"}, - {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70"}, - {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69"}, - {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9"}, - {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192"}, - {file = "orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559"}, - {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc"}, - {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f"}, - {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be"}, - {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c"}, - {file = "orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708"}, - {file = "orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb"}, - {file = "orjson-3.10.12-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47962841b2a8aa9a258b377f5188db31ba49af47d4003a32f55d6f8b19006543"}, - {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6334730e2532e77b6054e87ca84f3072bee308a45a452ea0bffbbbc40a67e296"}, - {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:accfe93f42713c899fdac2747e8d0d5c659592df2792888c6c5f829472e4f85e"}, - {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7974c490c014c48810d1dede6c754c3cc46598da758c25ca3b4001ac45b703f"}, - {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3f250ce7727b0b2682f834a3facff88e310f52f07a5dcfd852d99637d386e79e"}, - {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f31422ff9486ae484f10ffc51b5ab2a60359e92d0716fcce1b3593d7bb8a9af6"}, - {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5f29c5d282bb2d577c2a6bbde88d8fdcc4919c593f806aac50133f01b733846e"}, - {file = "orjson-3.10.12-cp313-none-win32.whl", hash = "sha256:f45653775f38f63dc0e6cd4f14323984c3149c05d6007b58cb154dd080ddc0dc"}, - {file = "orjson-3.10.12-cp313-none-win_amd64.whl", hash = "sha256:229994d0c376d5bdc91d92b3c9e6be2f1fbabd4cc1b59daae1443a46ee5e9825"}, - {file = "orjson-3.10.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7d69af5b54617a5fac5c8e5ed0859eb798e2ce8913262eb522590239db6c6763"}, - {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ed119ea7d2953365724a7059231a44830eb6bbb0cfead33fcbc562f5fd8f935"}, - {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5fc1238ef197e7cad5c91415f524aaa51e004be5a9b35a1b8a84ade196f73f"}, - {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43509843990439b05f848539d6f6198d4ac86ff01dd024b2f9a795c0daeeab60"}, - {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f72e27a62041cfb37a3de512247ece9f240a561e6c8662276beaf4d53d406db4"}, - {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a904f9572092bb6742ab7c16c623f0cdccbad9eeb2d14d4aa06284867bddd31"}, - {file = "orjson-3.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:855c0833999ed5dc62f64552db26f9be767434917d8348d77bacaab84f787d7b"}, - {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:897830244e2320f6184699f598df7fb9db9f5087d6f3f03666ae89d607e4f8ed"}, - {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:0b32652eaa4a7539f6f04abc6243619c56f8530c53bf9b023e1269df5f7816dd"}, - {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:36b4aa31e0f6a1aeeb6f8377769ca5d125db000f05c20e54163aef1d3fe8e833"}, - {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5535163054d6cbf2796f93e4f0dbc800f61914c0e3c4ed8499cf6ece22b4a3da"}, - {file = "orjson-3.10.12-cp38-none-win32.whl", hash = "sha256:90a5551f6f5a5fa07010bf3d0b4ca2de21adafbbc0af6cb700b63cd767266cb9"}, - {file = "orjson-3.10.12-cp38-none-win_amd64.whl", hash = "sha256:703a2fb35a06cdd45adf5d733cf613cbc0cb3ae57643472b16bc22d325b5fb6c"}, - {file = "orjson-3.10.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f29de3ef71a42a5822765def1febfb36e0859d33abf5c2ad240acad5c6a1b78d"}, - {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de365a42acc65d74953f05e4772c974dad6c51cfc13c3240899f534d611be967"}, - {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a5a0158648a67ff0004cb0df5df7dcc55bfc9ca154d9c01597a23ad54c8d0c"}, - {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c47ce6b8d90fe9646a25b6fb52284a14ff215c9595914af63a5933a49972ce36"}, - {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0eee4c2c5bfb5c1b47a5db80d2ac7aaa7e938956ae88089f098aff2c0f35d5d8"}, - {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d3081bbe8b86587eb5c98a73b97f13d8f9fea685cf91a579beddacc0d10566"}, - {file = "orjson-3.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c23a6e90383884068bc2dba83d5222c9fcc3b99a0ed2411d38150734236755"}, - {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5472be7dc3269b4b52acba1433dac239215366f89dc1d8d0e64029abac4e714e"}, - {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7319cda750fca96ae5973efb31b17d97a5c5225ae0bc79bf5bf84df9e1ec2ab6"}, - {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:74d5ca5a255bf20b8def6a2b96b1e18ad37b4a122d59b154c458ee9494377f80"}, - {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ff31d22ecc5fb85ef62c7d4afe8301d10c558d00dd24274d4bbe464380d3cd69"}, - {file = "orjson-3.10.12-cp39-none-win32.whl", hash = "sha256:c22c3ea6fba91d84fcb4cda30e64aff548fcf0c44c876e681f47d61d24b12e6b"}, - {file = "orjson-3.10.12-cp39-none-win_amd64.whl", hash = "sha256:be604f60d45ace6b0b33dd990a66b4526f1a7a186ac411c942674625456ca548"}, - {file = "orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff"}, + {file = "orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e"}, + {file = "orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab"}, + {file = "orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806"}, + {file = "orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c"}, + {file = "orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e"}, + {file = "orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e"}, + {file = "orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a"}, + {file = "orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665"}, + {file = "orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa"}, + {file = "orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825"}, + {file = "orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890"}, + {file = "orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf"}, + {file = "orjson-3.10.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e8afd6200e12771467a1a44e5ad780614b86abb4b11862ec54861a82d677746"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9a18c500f19273e9e104cca8c1f0b40a6470bcccfc33afcc088045d0bf5ea6"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb00b7bfbdf5d34a13180e4805d76b4567025da19a197645ca746fc2fb536586"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33aedc3d903378e257047fee506f11e0833146ca3e57a1a1fb0ddb789876c1e1"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd0099ae6aed5eb1fc84c9eb72b95505a3df4267e6962eb93cdd5af03be71c98"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c864a80a2d467d7786274fce0e4f93ef2a7ca4ff31f7fc5634225aaa4e9e98c"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c25774c9e88a3e0013d7d1a6c8056926b607a61edd423b50eb5c88fd7f2823ae"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e78c211d0074e783d824ce7bb85bf459f93a233eb67a5b5003498232ddfb0e8a"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:43e17289ffdbbac8f39243916c893d2ae41a2ea1a9cbb060a56a4d75286351ae"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:781d54657063f361e89714293c095f506c533582ee40a426cb6489c48a637b81"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6875210307d36c94873f553786a808af2788e362bd0cf4c8e66d976791e7b528"}, + {file = "orjson-3.10.15-cp38-cp38-win32.whl", hash = "sha256:305b38b2b8f8083cc3d618927d7f424349afce5975b316d33075ef0f73576b60"}, + {file = "orjson-3.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:5dd9ef1639878cc3efffed349543cbf9372bdbd79f478615a1c633fe4e4180d1"}, + {file = "orjson-3.10.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ffe19f3e8d68111e8644d4f4e267a069ca427926855582ff01fc012496d19969"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d433bf32a363823863a96561a555227c18a522a8217a6f9400f00ddc70139ae2"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da03392674f59a95d03fa5fb9fe3a160b0511ad84b7a3914699ea5a1b3a38da2"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a63bb41559b05360ded9132032239e47983a39b151af1201f07ec9370715c82"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3766ac4702f8f795ff3fa067968e806b4344af257011858cc3d6d8721588b53f"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1c73dcc8fadbd7c55802d9aa093b36878d34a3b3222c41052ce6b0fc65f8e8"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b299383825eafe642cbab34be762ccff9fd3408d72726a6b2a4506d410a71ab3"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:abc7abecdbf67a173ef1316036ebbf54ce400ef2300b4e26a7b843bd446c2480"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3614ea508d522a621384c1d6639016a5a2e4f027f3e4a1c93a51867615d28829"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:295c70f9dc154307777ba30fe29ff15c1bcc9dfc5c48632f37d20a607e9ba85a"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:63309e3ff924c62404923c80b9e2048c1f74ba4b615e7584584389ada50ed428"}, + {file = "orjson-3.10.15-cp39-cp39-win32.whl", hash = "sha256:a2f708c62d026fb5340788ba94a55c23df4e1869fec74be455e0b2f5363b8507"}, + {file = "orjson-3.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:efcf6c735c3d22ef60c4aa27a5238f1a477df85e9b15f2142f9d669beb2d13fd"}, + {file = "orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e"}, ] [[package]] @@ -620,7 +670,6 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -632,7 +681,6 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -644,134 +692,141 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "psycopg" -version = "3.2.3" +version = "3.2.5" description = "PostgreSQL database adapter for Python" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ - {file = "psycopg-3.2.3-py3-none-any.whl", hash = "sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907"}, - {file = "psycopg-3.2.3.tar.gz", hash = "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2"}, + {file = "psycopg-3.2.5-py3-none-any.whl", hash = "sha256:b782130983e5b3de30b4c529623d3687033b4dafa05bb661fc6bf45837ca5879"}, + {file = "psycopg-3.2.5.tar.gz", hash = "sha256:f5f750611c67cb200e85b408882f29265c66d1de7f813add4f8125978bfd70e8"}, ] [package.dependencies] -psycopg-binary = {version = "3.2.3", optional = true, markers = "implementation_name != \"pypy\" and extra == \"binary\""} +psycopg-binary = {version = "3.2.5", optional = true, markers = "implementation_name != \"pypy\" and extra == \"binary\""} typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""} tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] -binary = ["psycopg-binary (==3.2.3)"] -c = ["psycopg-c (==3.2.3)"] -dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.11)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] +binary = ["psycopg-binary (==3.2.5)"] +c = ["psycopg-c (==3.2.5)"] +dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "isort-psycopg", "isort[colors] (>=6.0)", "mypy (>=1.14)", "pre-commit (>=4.0.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] pool = ["psycopg-pool"] -test = ["anyio (>=4.0)", "mypy (>=1.11)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] +test = ["anyio (>=4.0)", "mypy (>=1.14)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] [[package]] name = "psycopg-binary" -version = "3.2.3" +version = "3.2.5" description = "PostgreSQL database adapter for Python -- C optimisation distribution" optional = false python-versions = ">=3.8" -groups = ["dev"] -markers = "implementation_name != \"pypy\"" files = [ - {file = "psycopg_binary-3.2.3-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:965455eac8547f32b3181d5ec9ad8b9be500c10fe06193543efaaebe3e4ce70c"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:71adcc8bc80a65b776510bc39992edf942ace35b153ed7a9c6c573a6849ce308"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f73adc05452fb85e7a12ed3f69c81540a8875960739082e6ea5e28c373a30774"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8630943143c6d6ca9aefc88bbe5e76c90553f4e1a3b2dc339e67dc34aa86f7e"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bffb61e198a91f712cc3d7f2d176a697cb05b284b2ad150fb8edb308eba9002"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc4fa2240c9fceddaa815a58f29212826fafe43ce80ff666d38c4a03fb036955"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:192a5f8496e6e1243fdd9ac20e117e667c0712f148c5f9343483b84435854c78"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64dc6e9ec64f592f19dc01a784e87267a64a743d34f68488924251253da3c818"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:79498df398970abcee3d326edd1d4655de7d77aa9aecd578154f8af35ce7bbd2"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:949551752930d5e478817e0b49956350d866b26578ced0042a61967e3fcccdea"}, - {file = "psycopg_binary-3.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:80a2337e2dfb26950894c8301358961430a0304f7bfe729d34cc036474e9c9b1"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:6d8f2144e0d5808c2e2aed40fbebe13869cd00c2ae745aca4b3b16a435edb056"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94253be2b57ef2fea7ffe08996067aabf56a1eb9648342c9e3bad9e10c46e045"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fda0162b0dbfa5eaed6cdc708179fa27e148cb8490c7d62e5cf30713909658ea"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c0419cdad8c70eaeb3116bb28e7b42d546f91baf5179d7556f230d40942dc78"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74fbf5dd3ef09beafd3557631e282f00f8af4e7a78fbfce8ab06d9cd5a789aae"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d784f614e4d53050cbe8abf2ae9d1aaacf8ed31ce57b42ce3bf2a48a66c3a5c"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4e76ce2475ed4885fe13b8254058be710ec0de74ebd8ef8224cf44a9a3358e5f"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5938b257b04c851c2d1e6cb2f8c18318f06017f35be9a5fe761ee1e2e344dfb7"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:257c4aea6f70a9aef39b2a77d0658a41bf05c243e2bf41895eb02220ac6306f3"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:06b5cc915e57621eebf2393f4173793ed7e3387295f07fed93ed3fb6a6ccf585"}, - {file = "psycopg_binary-3.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:09baa041856b35598d335b1a74e19a49da8500acedf78164600694c0ba8ce21b"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:48f8ca6ee8939bab760225b2ab82934d54330eec10afe4394a92d3f2a0c37dd6"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5361ea13c241d4f0ec3f95e0bf976c15e2e451e9cc7ef2e5ccfc9d170b197a40"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb987f14af7da7c24f803111dbc7392f5070fd350146af3345103f76ea82e339"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0463a11b1cace5a6aeffaf167920707b912b8986a9c7920341c75e3686277920"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b7be9a6c06518967b641fb15032b1ed682fd3b0443f64078899c61034a0bca6"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64a607e630d9f4b2797f641884e52b9f8e239d35943f51bef817a384ec1678fe"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fa33ead69ed133210d96af0c63448b1385df48b9c0247eda735c5896b9e6dbbf"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1f8b0d0e99d8e19923e6e07379fa00570be5182c201a8c0b5aaa9a4d4a4ea20b"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:709447bd7203b0b2debab1acec23123eb80b386f6c29e7604a5d4326a11e5bd6"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5e37d5027e297a627da3551a1e962316d0f88ee4ada74c768f6c9234e26346d9"}, - {file = "psycopg_binary-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:261f0031ee6074765096a19b27ed0f75498a8338c3dcd7f4f0d831e38adf12d1"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:41fdec0182efac66b27478ac15ef54c9ebcecf0e26ed467eb7d6f262a913318b"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:07d019a786eb020c0f984691aa1b994cb79430061065a694cf6f94056c603d26"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c57615791a337378fe5381143259a6c432cdcbb1d3e6428bfb7ce59fff3fb5c"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8eb9a4e394926b93ad919cad1b0a918e9b4c846609e8c1cfb6b743683f64da0"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5905729668ef1418bd36fbe876322dcb0f90b46811bba96d505af89e6fbdce2f"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd65774ed7d65101b314808b6893e1a75b7664f680c3ef18d2e5c84d570fa393"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:700679c02f9348a0d0a2adcd33a0275717cd0d0aee9d4482b47d935023629505"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96334bb64d054e36fed346c50c4190bad9d7c586376204f50bede21a913bf942"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9099e443d4cc24ac6872e6a05f93205ba1a231b1a8917317b07c9ef2b955f1f4"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1985ab05e9abebfbdf3163a16ebb37fbc5d49aff2bf5b3d7375ff0920bbb54cd"}, - {file = "psycopg_binary-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:e90352d7b610b4693fad0feea48549d4315d10f1eba5605421c92bb834e90170"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:69320f05de8cdf4077ecd7fefdec223890eea232af0d58f2530cbda2871244a0"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4926ea5c46da30bec4a85907aa3f7e4ea6313145b2aa9469fdb861798daf1502"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c64c4cd0d50d5b2288ab1bcb26c7126c772bbdebdfadcd77225a77df01c4a57e"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05a1bdce30356e70a05428928717765f4a9229999421013f41338d9680d03a63"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad357e426b0ea5c3043b8ec905546fa44b734bf11d33b3da3959f6e4447d350"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:967b47a0fd237aa17c2748fdb7425015c394a6fb57cdad1562e46a6eb070f96d"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:71db8896b942770ed7ab4efa59b22eee5203be2dfdee3c5258d60e57605d688c"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:2773f850a778575dd7158a6dd072f7925b67f3ba305e2003538e8831fec77a1d"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aeddf7b3b3f6e24ccf7d0edfe2d94094ea76b40e831c16eff5230e040ce3b76b"}, - {file = "psycopg_binary-3.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:824c867a38521d61d62b60aca7db7ca013a2b479e428a0db47d25d8ca5067410"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:9994f7db390c17fc2bd4c09dca722fd792ff8a49bb3bdace0c50a83f22f1767d"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1303bf8347d6be7ad26d1362af2c38b3a90b8293e8d56244296488ee8591058e"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:842da42a63ecb32612bb7f5b9e9f8617eab9bc23bd58679a441f4150fcc51c96"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2bb342a01c76f38a12432848e6013c57eb630103e7556cf79b705b53814c3949"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd40af959173ea0d087b6b232b855cfeaa6738f47cb2a0fd10a7f4fa8b74293f"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9b60b465773a52c7d4705b0a751f7f1cdccf81dd12aee3b921b31a6e76b07b0e"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fc6d87a1c44df8d493ef44988a3ded751e284e02cdf785f746c2d357e99782a6"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:f0b018e37608c3bfc6039a1dc4eb461e89334465a19916be0153c757a78ea426"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2a29f5294b0b6360bfda69653697eff70aaf2908f58d1073b0acd6f6ab5b5a4f"}, - {file = "psycopg_binary-3.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:e56b1fd529e5dde2d1452a7d72907b37ed1b4f07fdced5d8fb1e963acfff6749"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a82211a43372cba9b1555a110e84e679deec2dc9463ae4c736977dad99dca5ed"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e7d215a43343d91ba08301865f059d9518818d66a222a85fb425e4156716f5a6"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f893c0ed3d5c7b83b76b1f8f7d3ca5a03e38bcd3cab5d65b5c25a0d1064aca4"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d10ce4c39eb9631381a0c3792727946a4391e843625a7ee9579ac6bb11495a5"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a602d9fdb567cca090ca19ac3ebf10219065be2a4f8cf9eb8356cffb5a7ab1d"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c37eb3be7a6be93f4925ccf52bbfa60244da6c63201770a709dd81a3d2d08534"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7d5f1bfc848a94e0d63fe693adee4f88bd9e5c415ecb4c9c17d2d44eba6795a6"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b5e0acbc991472188c9df40eb56d8a97ad3ad00d4de560b8b74bdc2d94041a8f"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d4e0c1b1aa5283f6d9a384ffc7a8400d25386bb98fdb9bddae446e4ef4da7366"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c3c5fa3d4fa0a651cefab391b783f89bc5e331afa0a4e93c9b16141993fa05c8"}, + {file = "psycopg_binary-3.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:7efe6c732fd2d7e22d72dc4f7cf9b644020adacfff61b0a8a151343da8e661c0"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:393ab353196d364858b47317d27804ecc58ab56dbde32217bd67f0f2f2980662"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71d82dbc7c6c7f5746468e7992e5483aa45b12250d78d220a2431ab88795825c"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39e2cd10bf15442d95c3f48376b25dc33360418ea6c3c05884d8bf42407768c0"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7623659d44a6aa032be4a066c658ba45009d768c2481526fbef7c609702af116"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cd9ebf335262e864d740f9dad3f672f61162cc0d4825a5eb5cf50df334a688f"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc8bc40d82d1ee8dec136e10707c7f3147a6322fd8014e174a0f3446fb793649"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:11e3ed8b94c750d54fc3e4502dd930fb0fd041629845b6a7ce089873ac9756b0"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:48fcb12a0a72fdfe4102bdb1252a7366e8d73a2c89fe6ce5923be890de367c2f"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:51a96d9fe51f718912b4a0089784f1f32d800217499fd0f0095b888506aba4c5"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb8293d66c6a4ddc72fceb7ad0e111cb196cc394954ae0f9b63c251d97f1b00e"}, + {file = "psycopg_binary-3.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:5b81342e139ddccfa417832089cd213bd4beacd7a1462ca4019cafe71682d177"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a4321ee8180982d70458d3e8378e31448901bf0ee40fe0d410a87413578f4098"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2cc86657c05e09c701e97f87132cd58e0d55381dd568520081ac1fe7580a9bbb"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244bebaa9734a236b7157fb57c065b6c0f2344281916187bd73f951df1899e0"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21b839f9bfd77ed074f7f71464a43f453400c57d038a0ba0716329a28e335897"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7376b13504396da9678b646f5338462347da01286b2a688a0d8493ec764683a2"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:473f6827cf1faf3924eb77146d1e85126a1b5e48a88053b8d8b78dd29e971d78"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:28bd5cb2324567e5e70f07fe1d646398d6b0e210e28b49be0e69593590a59980"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:48f97936145cb7de18b95d85670b2d3e2c257277263272be05815b74fb0ef195"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e6f2bef5aed021fbdf46323d3cd8847bf960efb56394698644a8ee2306f8892"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d2e57a1d06f3968e49e948ba374f21a7d8dcf44f37d582a4aeddeb7c85ce239"}, + {file = "psycopg_binary-3.2.5-cp312-cp312-win_amd64.whl", hash = "sha256:2cbb8649cfdacbd14e17f5ab78edc52d33350013888518c73e90c5d17d7bea55"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2dbaf32c18c0d11c4480016b89c9c5cadb7b64c55de7f181d222b189bd13a558"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ca5e36a3e7480a5c09aed99ecdb8e6554b21485c3b064297fe77f7b1b5806106"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abe093a303e25ac58774a11241150e2fe2947358d1ca12521ad03c90b131060"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a91b0e096fdfeb52d86bb8f5ee25dc22483d6960af9b968e6b381a8ec5bfbf82"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3eb71cfc35116e4a8e336b7e785f1fe06ca23b4516a48ea91facd577d1a1fdf6"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98efaedf2bf79f4d563ca039a57a025b72847bd80568f54709cc39fc1404772c"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba4a610882171bdaae0779f14e0ff45f3ee271fd2dbf16cdadfc81bd67323232"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1494827c43265820d5dcdc6f8086521bc7dd04b9da8831310978a788cdcd2e62"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7a94020821723a6a210206ddb458001f3ed27e1e6a0555b9422bebf7ead8ff37"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:659f2c675d478b1bc01b95a8d3ded74fa939b370e71ffbecd496f617b215eb05"}, + {file = "psycopg_binary-3.2.5-cp313-cp313-win_amd64.whl", hash = "sha256:6b581da13126b8715c0c0585cd37ce934c9864d44b2a4019f5487c0b943275e6"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:02fb96091e2fb3ea1470b113fef08953baaedbca1d39a3f72d82cb615177846c"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9639289b72f9339721982e156527c296693236d6192ccc31412ab36fccd1683c"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee6d8f489a9b116ea8dc797664a50671585a4ca20573359f067858e1231cc217"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de576c49d7deab2b78088feb24e1f6ae3e16a0020e8496cdd3b8543f5e350e87"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93221d5a759bd39b1face1d7d887d2b9ede3e55aefaff8eacf1b663ccdcd204b"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:274e852f9e61252bc8e80a0a43d300ba352d40219e856733054023a3bb960eb4"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bc5bd9bf5f5894923b78a41c5becd52d6bced1e1e43744855bd85cb341376ca6"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:32b5673736f04c36ccbf8012800fe5bc01b46dac22c5d59e41b043bebaad9d3d"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:65162a9cc3f86d70b1d895dbda506e3c079f80d082eb41c54d3f6d33a00b3965"}, + {file = "psycopg_binary-3.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:5fd017d7ed71c58f19b0f614e7bfb8f01ec862bacb67ae584f494d090956102e"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d2253189aa4cca0a425e2ca896d1a29760cd3a2b10ab12194e4e827a566505c"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4914dc60f2fddf0884464985e31d775aa865b665471fa156ec2f56fa72a1a097"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efb878d08dd49d7d9d18512e791b418a1171d08f935475eec98305f0886b7c14"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62965045cc0fe3dc5dd55d39779620b225ef75962825c7b1b533033cb91810bd"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d22a15e45f43d36ed35aed4d5261f8ef6ab7d9b84ee075576ca56ae03b9e0aa"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375149006e21d58ed8aba640e0295d8e636043064c433af94eb58057f9b96877"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:60d0f36a42a822e43c4c7472df8a0c980c0f32e5d74ed871333c423a4e942f11"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:b6b5a4542aca4095ab35e184517cb0d18895ba4b6661c92865b431fa7b7974d8"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:605f70e267222d567fc40de7813ee3fb29f8145a1a20aa6fd3dc62baba9312f1"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2b053eae21dd3a6828b516a1171e1274d1af5f7c07d2d9a8f597f2e19c732168"}, + {file = "psycopg_binary-3.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:23a1dc61abb8f7cc702472ab29554167a9421842f976c201ceb3b722c0299769"}, ] [[package]] name = "psycopg-pool" -version = "3.2.4" +version = "3.2.6" description = "Connection Pool for Psycopg" optional = false python-versions = ">=3.8" -groups = ["main"] files = [ - {file = "psycopg_pool-3.2.4-py3-none-any.whl", hash = "sha256:f6a22cff0f21f06d72fb2f5cb48c618946777c49385358e0c88d062c59cbd224"}, - {file = "psycopg_pool-3.2.4.tar.gz", hash = "sha256:61774b5bbf23e8d22bedc7504707135aaf744679f8ef9b3fe29942920746a6ed"}, + {file = "psycopg_pool-3.2.6-py3-none-any.whl", hash = "sha256:5887318a9f6af906d041a0b1dc1c60f8f0dda8340c2572b74e10907b51ed5da7"}, + {file = "psycopg_pool-3.2.6.tar.gz", hash = "sha256:0f92a7817719517212fbfe2fd58b8c35c1850cdd2a80d36b581ba2085d9148e5"}, ] [package.dependencies] typing-extensions = ">=4.6" +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + [[package]] name = "pydantic" -version = "2.10.3" +version = "2.10.6" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ - {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, - {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.27.1" +pydantic-core = "2.27.2" typing-extensions = ">=4.12.2" [package.extras] @@ -780,112 +835,111 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.27.1" +version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ - {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, - {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, - {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, - {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, - {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, - {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, - {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, - {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, - {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, - {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, - {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, - {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, - {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, - {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, - {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, - {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, - {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, - {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, - {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, - {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, - {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, - {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, - {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, - {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, - {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, - {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, - {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, - {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, ] [package.dependencies] @@ -897,7 +951,6 @@ version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, @@ -920,7 +973,6 @@ version = "0.21.2" description = "Pytest support for asyncio" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b"}, {file = "pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45"}, @@ -939,7 +991,6 @@ version = "3.14.0" description = "Thin-wrapper around the mock package for easier use with pytest" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, @@ -957,7 +1008,6 @@ version = "0.4.3" description = "Automatically rerun your tests on file modifications" optional = false python-versions = "<4.0.0,>=3.7.0" -groups = ["dev"] files = [ {file = "pytest_watcher-0.4.3-py3-none-any.whl", hash = "sha256:d59b1e1396f33a65ea4949b713d6884637755d641646960056a90b267c3460f9"}, {file = "pytest_watcher-0.4.3.tar.gz", hash = "sha256:0cb0e4661648c8c0ff2b2d25efa5a8e421784b9e4c60fcecbf9b7c30b2d731b3"}, @@ -973,7 +1023,6 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -1036,7 +1085,6 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -1058,7 +1106,6 @@ version = "1.0.0" description = "A utility belt for advanced users of python-requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["main", "dev"] files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, @@ -1073,7 +1120,6 @@ version = "0.6.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, @@ -1101,7 +1147,6 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -1113,7 +1158,6 @@ version = "9.0.0" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, @@ -1129,8 +1173,6 @@ version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" -groups = ["dev"] -markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, @@ -1172,7 +1214,6 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -1180,27 +1221,24 @@ files = [ [[package]] name = "tzdata" -version = "2024.2" +version = "2025.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" -groups = ["main", "dev"] -markers = "sys_platform == \"win32\"" files = [ - {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, - {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, + {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, + {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, ] [[package]] name = "urllib3" -version = "2.2.3" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] +python-versions = ">=3.9" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] @@ -1215,7 +1253,6 @@ version = "6.0.0" description = "Filesystem events monitoring" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, @@ -1252,7 +1289,119 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "zstandard" +version = "0.23.0" +description = "Zstandard bindings for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9"}, + {file = "zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77da4c6bfa20dd5ea25cbf12c76f181a8e8cd7ea231c673828d0386b1740b8dc"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2170c7e0367dde86a2647ed5b6f57394ea7f53545746104c6b09fc1f4223573"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16842b846a8d2a145223f520b7e18b57c8f476924bda92aeee3a88d11cfc391"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:157e89ceb4054029a289fb504c98c6a9fe8010f1680de0201b3eb5dc20aa6d9e"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:203d236f4c94cd8379d1ea61db2fce20730b4c38d7f1c34506a31b34edc87bdd"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dc5d1a49d3f8262be192589a4b72f0d03b72dcf46c51ad5852a4fdc67be7b9e4"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:752bf8a74412b9892f4e5b58f2f890a039f57037f52c89a740757ebd807f33ea"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80080816b4f52a9d886e67f1f96912891074903238fe54f2de8b786f86baded2"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84433dddea68571a6d6bd4fbf8ff398236031149116a7fff6f777ff95cad3df9"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19a2d91963ed9e42b4e8d77cd847ae8381576585bad79dbd0a8837a9f6620a"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:59556bf80a7094d0cfb9f5e50bb2db27fefb75d5138bb16fb052b61b0e0eeeb0"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27d3ef2252d2e62476389ca8f9b0cf2bbafb082a3b6bfe9d90cbcbb5529ecf7c"}, + {file = "zstandard-0.23.0-cp310-cp310-win32.whl", hash = "sha256:5d41d5e025f1e0bccae4928981e71b2334c60f580bdc8345f824e7c0a4c2a813"}, + {file = "zstandard-0.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:519fbf169dfac1222a76ba8861ef4ac7f0530c35dd79ba5727014613f91613d4"}, + {file = "zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e"}, + {file = "zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80a539906390591dd39ebb8d773771dc4db82ace6372c4d41e2d293f8e32b8db"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:445e4cb5048b04e90ce96a79b4b63140e3f4ab5f662321975679b5f6360b90e2"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd30d9c67d13d891f2360b2a120186729c111238ac63b43dbd37a5a40670b8ca"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d20fd853fbb5807c8e84c136c278827b6167ded66c72ec6f9a14b863d809211c"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed1708dbf4d2e3a1c5c69110ba2b4eb6678262028afd6c6fbcc5a8dac9cda68e"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be9b5b8659dff1f913039c2feee1aca499cfbc19e98fa12bc85e037c17ec6ca5"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65308f4b4890aa12d9b6ad9f2844b7ee42c7f7a4fd3390425b242ffc57498f48"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98da17ce9cbf3bfe4617e836d561e433f871129e3a7ac16d6ef4c680f13a839c"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed7d27cb56b3e058d3cf684d7200703bcae623e1dcc06ed1e18ecda39fee003"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b69bb4f51daf461b15e7b3db033160937d3ff88303a7bc808c67bbc1eaf98c78"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:034b88913ecc1b097f528e42b539453fa82c3557e414b3de9d5632c80439a473"}, + {file = "zstandard-0.23.0-cp311-cp311-win32.whl", hash = "sha256:f2d4380bf5f62daabd7b751ea2339c1a21d1c9463f1feb7fc2bdcea2c29c3160"}, + {file = "zstandard-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:62136da96a973bd2557f06ddd4e8e807f9e13cbb0bfb9cc06cfe6d98ea90dfe0"}, + {file = "zstandard-0.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b4567955a6bc1b20e9c31612e615af6b53733491aeaa19a6b3b37f3b65477094"}, + {file = "zstandard-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e172f57cd78c20f13a3415cc8dfe24bf388614324d25539146594c16d78fcc8"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e166f698c5a3e914947388c162be2583e0c638a4703fc6a543e23a88dea3c1"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a289832e520c6bd4dcaad68e944b86da3bad0d339ef7989fb7e88f92e96072"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d50d31bfedd53a928fed6707b15a8dbeef011bb6366297cc435accc888b27c20"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72c68dda124a1a138340fb62fa21b9bf4848437d9ca60bd35db36f2d3345f373"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53dd9d5e3d29f95acd5de6802e909ada8d8d8cfa37a3ac64836f3bc4bc5512db"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6a41c120c3dbc0d81a8e8adc73312d668cd34acd7725f036992b1b72d22c1772"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:40b33d93c6eddf02d2c19f5773196068d875c41ca25730e8288e9b672897c105"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9206649ec587e6b02bd124fb7799b86cddec350f6f6c14bc82a2b70183e708ba"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76e79bc28a65f467e0409098fa2c4376931fd3207fbeb6b956c7c476d53746dd"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66b689c107857eceabf2cf3d3fc699c3c0fe8ccd18df2219d978c0283e4c508a"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9c236e635582742fee16603042553d276cca506e824fa2e6489db04039521e90"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35"}, + {file = "zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d"}, + {file = "zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b"}, + {file = "zstandard-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:576856e8594e6649aee06ddbfc738fec6a834f7c85bf7cadd1c53d4a58186ef9"}, + {file = "zstandard-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38302b78a850ff82656beaddeb0bb989a0322a8bbb1bf1ab10c17506681d772a"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2240ddc86b74966c34554c49d00eaafa8200a18d3a5b6ffbf7da63b11d74ee2"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ef230a8fd217a2015bc91b74f6b3b7d6522ba48be29ad4ea0ca3a3775bf7dd5"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:774d45b1fac1461f48698a9d4b5fa19a69d47ece02fa469825b442263f04021f"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f77fa49079891a4aab203d0b1744acc85577ed16d767b52fc089d83faf8d8ed"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac184f87ff521f4840e6ea0b10c0ec90c6b1dcd0bad2f1e4a9a1b4fa177982ea"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c363b53e257246a954ebc7c488304b5592b9c53fbe74d03bc1c64dda153fb847"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e7792606d606c8df5277c32ccb58f29b9b8603bf83b48639b7aedf6df4fe8171"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0817825b900fcd43ac5d05b8b3079937073d2b1ff9cf89427590718b70dd840"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9da6bc32faac9a293ddfdcb9108d4b20416219461e4ec64dfea8383cac186690"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd7699e8fd9969f455ef2926221e0233f81a2542921471382e77a9e2f2b57f4b"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d477ed829077cd945b01fc3115edd132c47e6540ddcd96ca169facff28173057"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ce8b52c5987b3e34d5674b0ab529a4602b632ebab0a93b07bfb4dfc8f8a33"}, + {file = "zstandard-0.23.0-cp313-cp313-win32.whl", hash = "sha256:a9b07268d0c3ca5c170a385a0ab9fb7fdd9f5fd866be004c4ea39e44edce47dd"}, + {file = "zstandard-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b"}, + {file = "zstandard-0.23.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ef3775758346d9ac6214123887d25c7061c92afe1f2b354f9388e9e4d48acfc"}, + {file = "zstandard-0.23.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4051e406288b8cdbb993798b9a45c59a4896b6ecee2f875424ec10276a895740"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2d1a054f8f0a191004675755448d12be47fa9bebbcffa3cdf01db19f2d30a54"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f83fa6cae3fff8e98691248c9320356971b59678a17f20656a9e59cd32cee6d8"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32ba3b5ccde2d581b1e6aa952c836a6291e8435d788f656fe5976445865ae045"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f146f50723defec2975fb7e388ae3a024eb7151542d1599527ec2aa9cacb152"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bfe8de1da6d104f15a60d4a8a768288f66aa953bbe00d027398b93fb9680b26"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:29a2bc7c1b09b0af938b7a8343174b987ae021705acabcbae560166567f5a8db"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61f89436cbfede4bc4e91b4397eaa3e2108ebe96d05e93d6ccc95ab5714be512"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53ea7cdc96c6eb56e76bb06894bcfb5dfa93b7adcf59d61c6b92674e24e2dd5e"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:a4ae99c57668ca1e78597d8b06d5af837f377f340f4cce993b551b2d7731778d"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:379b378ae694ba78cef921581ebd420c938936a153ded602c4fea612b7eaa90d"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:50a80baba0285386f97ea36239855f6020ce452456605f262b2d33ac35c7770b"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:61062387ad820c654b6a6b5f0b94484fa19515e0c5116faf29f41a6bc91ded6e"}, + {file = "zstandard-0.23.0-cp38-cp38-win32.whl", hash = "sha256:b8c0bd73aeac689beacd4e7667d48c299f61b959475cdbb91e7d3d88d27c56b9"}, + {file = "zstandard-0.23.0-cp38-cp38-win_amd64.whl", hash = "sha256:a05e6d6218461eb1b4771d973728f0133b2a4613a6779995df557f70794fd60f"}, + {file = "zstandard-0.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa014d55c3af933c1315eb4bb06dd0459661cc0b15cd61077afa6489bec63bb"}, + {file = "zstandard-0.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7f0804bb3799414af278e9ad51be25edf67f78f916e08afdb983e74161b916"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb2b1ecfef1e67897d336de3a0e3f52478182d6a47eda86cbd42504c5cbd009a"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:837bb6764be6919963ef41235fd56a6486b132ea64afe5fafb4cb279ac44f259"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1516c8c37d3a053b01c1c15b182f3b5f5eef19ced9b930b684a73bad121addf4"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48ef6a43b1846f6025dde6ed9fee0c24e1149c1c25f7fb0a0585572b2f3adc58"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11e3bf3c924853a2d5835b24f03eeba7fc9b07d8ca499e247e06ff5676461a15"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2fb4535137de7e244c230e24f9d1ec194f61721c86ebea04e1581d9d06ea1269"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c24f21fa2af4bb9f2c492a86fe0c34e6d2c63812a839590edaf177b7398f700"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8c86881813a78a6f4508ef9daf9d4995b8ac2d147dcb1a450448941398091c9"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe3b385d996ee0822fd46528d9f0443b880d4d05528fd26a9119a54ec3f91c69"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:82d17e94d735c99621bf8ebf9995f870a6b3e6d14543b99e201ae046dfe7de70"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c7c517d74bea1a6afd39aa612fa025e6b8011982a0897768a2f7c8ab4ebb78a2"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fd7e0f1cfb70eb2f95a19b472ee7ad6d9a0a992ec0ae53286870c104ca939e5"}, + {file = "zstandard-0.23.0-cp39-cp39-win32.whl", hash = "sha256:43da0f0092281bf501f9c5f6f3b4c975a8a0ea82de49ba3f7100e64d422a1274"}, + {file = "zstandard-0.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:f8346bfa098532bc1fb6c7ef06783e969d87a99dd1d2a5a18a892c1d7a643c58"}, + {file = "zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09"}, +] + +[package.dependencies] +cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""} + +[package.extras] +cffi = ["cffi (>=1.11)"] + [metadata] -lock-version = "2.1" +lock-version = "2.0" python-versions = "^3.9.0,<4.0" content-hash = "369bfffecb9489835b43b8255932e043176a11d2f639aad2d055ffd89263ca1e" diff --git a/libs/checkpoint-postgres/pyproject.toml b/libs/checkpoint-postgres/pyproject.toml index ba1af9821..307181d40 100644 --- a/libs/checkpoint-postgres/pyproject.toml +++ b/libs/checkpoint-postgres/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-checkpoint-postgres" -version = "2.0.15" +version = "2.0.16" description = "Library with a Postgres implementation of LangGraph checkpoint saver." authors = [] license = "MIT" diff --git a/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py b/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py index befa6cfbe..91097c9b8 100644 --- a/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py +++ b/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py @@ -530,6 +530,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]): for idx, (channel, value) in enumerate(writes) ], ) + await self.conn.commit() def get_next_version(self, current: Optional[str], channel: ChannelProtocol) -> str: """Generate the next version ID for a channel. diff --git a/libs/checkpoint-sqlite/poetry.lock b/libs/checkpoint-sqlite/poetry.lock index 123530da3..efe3659e6 100644 --- a/libs/checkpoint-sqlite/poetry.lock +++ b/libs/checkpoint-sqlite/poetry.lock @@ -1,23 +1,23 @@ -# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "aiosqlite" -version = "0.20.0" +version = "0.21.0" description = "asyncio bridge to the standard sqlite3 module" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiosqlite-0.20.0-py3-none-any.whl", hash = "sha256:36a1deaca0cac40ebe32aac9977a6e2bbc7f5189f23f4a54d5908986729e5bd6"}, - {file = "aiosqlite-0.20.0.tar.gz", hash = "sha256:6d35c8c256637f4672f843c31021464090805bf925385ac39473fb16eaaca3d7"}, + {file = "aiosqlite-0.21.0-py3-none-any.whl", hash = "sha256:2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0"}, + {file = "aiosqlite-0.21.0.tar.gz", hash = "sha256:131bb8056daa3bc875608c631c678cda73922a2d4ba8aec373b19f18c17e7aa3"}, ] [package.dependencies] typing_extensions = ">=4.0" [package.extras] -dev = ["attribution (==1.7.0)", "black (==24.2.0)", "coverage[toml] (==7.4.1)", "flake8 (==7.0.0)", "flake8-bugbear (==24.2.6)", "flit (==3.9.0)", "mypy (==1.8.0)", "ufmt (==2.3.0)", "usort (==1.0.8.post1)"] -docs = ["sphinx (==7.2.6)", "sphinx-mdinclude (==0.5.3)"] +dev = ["attribution (==1.7.1)", "black (==24.3.0)", "build (>=1.2)", "coverage[toml] (==7.6.10)", "flake8 (==7.0.0)", "flake8-bugbear (==24.12.12)", "flit (==3.10.1)", "mypy (==1.14.1)", "ufmt (==2.5.1)", "usort (==1.0.8.post1)"] +docs = ["sphinx (==8.1.3)", "sphinx-mdinclude (==0.6.1)"] [[package]] name = "annotated-types" @@ -1043,4 +1043,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.1" python-versions = "^3.9.0" -content-hash = "e6d3ca9bce723c05f4c5ae9dc4bee872f7581b7763680b34112f1d280f5a9b0a" +content-hash = "21896b8d3d283d95bc3988aa93f06faf5c47dadc2a8822e5a35672b9cb054693" diff --git a/libs/checkpoint-sqlite/pyproject.toml b/libs/checkpoint-sqlite/pyproject.toml index 21eb40cdc..de7f0702b 100644 --- a/libs/checkpoint-sqlite/pyproject.toml +++ b/libs/checkpoint-sqlite/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-checkpoint-sqlite" -version = "2.0.5" +version = "2.0.6" description = "Library with a SQLite implementation of LangGraph checkpoint saver." authors = [] license = "MIT" @@ -11,7 +11,7 @@ packages = [{ include = "langgraph" }] [tool.poetry.dependencies] python = "^3.9.0" langgraph-checkpoint = "^2.0.15" -aiosqlite = "^0.20.0" +aiosqlite = ">=0.20,<0.22" [tool.poetry.group.dev.dependencies] ruff = "^0.6.2" diff --git a/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py b/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py index 4bd0839c2..619fa2d63 100644 --- a/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py +++ b/libs/checkpoint/langgraph/checkpoint/serde/jsonplus.py @@ -487,7 +487,12 @@ def _msgpack_ext_hook(code: int, data: bytes) -> Any: except Exception: return cls.construct(**tup[2]) except Exception: - return + # for pydantic objects we can't find/reconstruct + # let's return the kwargs dict instead + try: + return tup[2] + except NameError: + return elif code == EXT_PYDANTIC_V2: try: tup = msgpack.unpackb( @@ -500,7 +505,12 @@ def _msgpack_ext_hook(code: int, data: bytes) -> Any: except Exception: return cls.model_construct(**tup[2]) except Exception: - return + # for pydantic objects we can't find/reconstruct + # let's return the kwargs dict instead + try: + return tup[2] + except NameError: + return def _msgpack_enc(data: Any) -> bytes: diff --git a/libs/checkpoint/langgraph/store/base/__init__.py b/libs/checkpoint/langgraph/store/base/__init__.py index 19fc62d8d..fff90cc56 100644 --- a/libs/checkpoint/langgraph/store/base/__init__.py +++ b/libs/checkpoint/langgraph/store/base/__init__.py @@ -11,9 +11,19 @@ Core types: from abc import ABC, abstractmethod from datetime import datetime -from typing import Any, Iterable, Literal, NamedTuple, Optional, TypedDict, Union, cast +from typing import ( + Any, + Iterable, + Literal, + NamedTuple, + Optional, + TypedDict, + Union, + cast, +) from langchain_core.embeddings import Embeddings +from typing_extensions import override from langgraph.store.base.embed import ( AEmbeddingsFunc, @@ -24,6 +34,20 @@ from langgraph.store.base.embed import ( ) +class NotProvided: + """Sentinel singleton.""" + + def __bool__(self) -> Literal[False]: + return False + + @override + def __repr__(self) -> str: + return "NOT_GIVEN" + + +NOT_PROVIDED = NotProvided() + + class Item: """Represents a stored item with metadata. @@ -59,7 +83,7 @@ class Item: else created_at ) self.updated_at = ( - datetime.fromisoformat(cast(str, created_at)) + datetime.fromisoformat(cast(str, updated_at)) if isinstance(updated_at, str) else updated_at ) @@ -166,6 +190,13 @@ class GetOp(NamedTuple): "doc456" # For a document ``` """ + refresh_ttl: bool = True + """Whether to refresh TTLs for the returned item. + + If no TTL was specified for the original item(s), + or if TTL support is not enabled for your adapter, + this argument is ignored. + """ class SearchOp(NamedTuple): @@ -260,6 +291,13 @@ class SearchOp(NamedTuple): - "technical documentation about REST APIs" - "machine learning papers from 2023" """ + refresh_ttl: bool = True + """Whether to refresh TTLs for the returned item. + + If no TTL was specified for the original item(s), + or if TTL support is not enabled for your adapter, + this argument is ignored. + """ # Type representing a namespace path that can include wildcards @@ -463,6 +501,15 @@ class PutOp(NamedTuple): ] ``` """ + ttl: Optional[float] = None + """Controls the TTL (time-to-live) for the item in minutes. + + If provided, and if the store you are using supports this feature, the item + will expire this many minutes after it was last accessed. The expiration timer + refreshes on both read operations (get/search) and write operations (put/update). + When the TTL expires, the item will be scheduled for deletion on a best-effort basis. + Defaults to None (no expiration). + """ Op = Union[GetOp, SearchOp, PutOp, ListNamespacesOp] @@ -473,6 +520,25 @@ class InvalidNamespaceError(ValueError): """Provided namespace is invalid.""" +class TTLConfig(TypedDict, total=False): + """Configuration for TTL (time-to-live) behavior in the store.""" + + refresh_on_read: bool + """Default behavior for refreshing TTLs on read operations (GET and SEARCH). + + If True, TTLs will be refreshed on read operations (get/search) by default. + This can be overridden per-operation by explicitly setting refresh_ttl. + Defaults to True if not configured. + """ + default_ttl: Optional[float] + """Default TTL (time-to-live) in minutes for new items. + + If provided, new items will expire after this many minutes after their last access. + The expiration timer refreshes on both read and write operations. + Defaults to None (no expiration). + """ + + class IndexConfig(TypedDict, total=False): """Configuration for indexing documents for semantic search in the store. @@ -612,8 +678,14 @@ class BaseStore(ABC): by providing an `index` configuration at creation time. Without this configuration, semantic search is disabled and any `index` arguments to storage operations will have no effect. + + Similarly, TTL (time-to-live) support is disabled by default. + Subclasses must explicitly set `supports_ttl = True` to enable this feature. """ + supports_ttl: bool = False + ttl_config: Optional[TTLConfig] = None + __slots__ = ("__weakref__",) @abstractmethod @@ -640,17 +712,28 @@ class BaseStore(ABC): The order of results matches the order of input operations. """ - def get(self, namespace: tuple[str, ...], key: str) -> Optional[Item]: + def get( + self, + namespace: tuple[str, ...], + key: str, + *, + refresh_ttl: Optional[bool] = None, + ) -> Optional[Item]: """Retrieve a single item. Args: namespace: Hierarchical path for the item. key: Unique identifier within the namespace. + refresh_ttl: Whether to refresh TTLs for the returned item. + If None (default), uses the store's default refresh_ttl setting. + If no TTL is specified, this argument is ignored. Returns: The retrieved item or None if not found. """ - return self.batch([GetOp(namespace, key)])[0] + return self.batch( + [GetOp(namespace, str(key), _ensure_refresh(self.ttl_config, refresh_ttl))] + )[0] def search( self, @@ -661,6 +744,7 @@ class BaseStore(ABC): filter: Optional[dict[str, Any]] = None, limit: int = 10, offset: int = 0, + refresh_ttl: Optional[bool] = None, ) -> list[SearchItem]: """Search for items within a namespace prefix. @@ -670,6 +754,8 @@ class BaseStore(ABC): filter: Key-value pairs to filter results. limit: Maximum number of items to return. offset: Number of items to skip before returning results. + refresh_ttl: Whether to refresh TTLs for the returned items. + If no TTL is specified, this argument is ignored. Returns: List of items matching the search criteria. @@ -707,7 +793,18 @@ class BaseStore(ABC): Note: Natural language search support depends on your store implementation and requires proper embedding configuration. """ - return self.batch([SearchOp(namespace_prefix, filter, limit, offset, query)])[0] + return self.batch( + [ + SearchOp( + namespace_prefix, + filter, + limit, + offset, + query, + _ensure_refresh(self.ttl_config, refresh_ttl), + ) + ] + )[0] def put( self, @@ -715,6 +812,8 @@ class BaseStore(ABC): key: str, value: dict[str, Any], index: Optional[Union[Literal[False], list[str]]] = None, + *, + ttl: Union[Optional[float], "NotProvided"] = NOT_PROVIDED, ) -> None: """Store or update an item in the store. @@ -735,12 +834,20 @@ class BaseStore(ABC): - Nested fields: "metadata.title" - Array access: "chapters[*].content" (each indexed separately) - Specific indices: "authors[0].name" + ttl: Time to live in minutes. Support for this argument depends on your store adapter. + If specified, the item will expire after this many minutes from when it was last accessed. + None means no expiration. Expired runs will be deleted opportunistically. + By default, the expiration timer refreshes on both read operations (get/search) + and write operations (put/update), whenever the item is included in the operation. Note: Indexing support depends on your store implementation. If you do not initialize the store with indexing capabilities, the `index` parameter will be ignored. + Similarly, TTL support depends on the specific store implementation. + Some implementations may not support expiration of items. + ???+ example "Examples" Store item. Indexing depends on how you configure the store. ```python @@ -759,7 +866,22 @@ class BaseStore(ABC): ``` """ _validate_namespace(namespace) - self.batch([PutOp(namespace, key, value, index=index)]) + if ttl not in (NOT_PROVIDED, None) and not self.supports_ttl: + raise NotImplementedError( + f"TTL is not supported by {self.__class__.__name__}. " + f"Use a store implementation that supports TTL or set ttl=None." + ) + self.batch( + [ + PutOp( + namespace, + str(key), + value, + index=index, + ttl=_ensure_ttl(self.ttl_config, ttl), + ) + ] + ) def delete(self, namespace: tuple[str, ...], key: str) -> None: """Delete an item. @@ -768,7 +890,7 @@ class BaseStore(ABC): namespace: Hierarchical path for the item. key: Unique identifier within the namespace. """ - self.batch([PutOp(namespace, key, None)]) + self.batch([PutOp(namespace, str(key), None, ttl=None)]) def list_namespaces( self, @@ -823,7 +945,13 @@ class BaseStore(ABC): ) return self.batch([op])[0] - async def aget(self, namespace: tuple[str, ...], key: str) -> Optional[Item]: + async def aget( + self, + namespace: tuple[str, ...], + key: str, + *, + refresh_ttl: Optional[bool] = None, + ) -> Optional[Item]: """Asynchronously retrieve a single item. Args: @@ -833,7 +961,17 @@ class BaseStore(ABC): Returns: The retrieved item or None if not found. """ - return (await self.abatch([GetOp(namespace, key)]))[0] + return ( + await self.abatch( + [ + GetOp( + namespace, + str(key), + _ensure_refresh(self.ttl_config, refresh_ttl), + ) + ] + ) + )[0] async def asearch( self, @@ -844,6 +982,7 @@ class BaseStore(ABC): filter: Optional[dict[str, Any]] = None, limit: int = 10, offset: int = 0, + refresh_ttl: Optional[bool] = None, ) -> list[SearchItem]: """Asynchronously search for items within a namespace prefix. @@ -853,6 +992,9 @@ class BaseStore(ABC): filter: Key-value pairs to filter results. limit: Maximum number of items to return. offset: Number of items to skip before returning results. + refresh_ttl: Whether to refresh TTLs for the returned items. + If None (default), uses the store's TTLConfig.refresh_default setting. + If TTLConfig is not provided or no TTL is specified, this argument is ignored. Returns: List of items matching the search criteria. @@ -892,7 +1034,16 @@ class BaseStore(ABC): """ return ( await self.abatch( - [SearchOp(namespace_prefix, filter, limit, offset, query)] + [ + SearchOp( + namespace_prefix, + filter, + limit, + offset, + query, + _ensure_refresh(self.ttl_config, refresh_ttl), + ) + ] ) )[0] @@ -902,6 +1053,8 @@ class BaseStore(ABC): key: str, value: dict[str, Any], index: Optional[Union[Literal[False], list[str]]] = None, + *, + ttl: Union[Optional[float], "NotProvided"] = NOT_PROVIDED, ) -> None: """Asynchronously store or update an item in the store. @@ -922,12 +1075,20 @@ class BaseStore(ABC): - Nested fields: "metadata.title" - Array access: "chapters[*].content" (each indexed separately) - Specific indices: "authors[0].name" + ttl: Time to live in minutes. Support for this argument depends on your store adapter. + If specified, the item will expire after this many minutes from when it was last accessed. + None means no expiration. Expired runs will be deleted opportunistically. + By default, the expiration timer refreshes on both read operations (get/search) + and write operations (put/update), whenever the item is included in the operation. Note: Indexing support depends on your store implementation. If you do not initialize the store with indexing capabilities, the `index` parameter will be ignored. + Similarly, TTL support depends on the specific store implementation. + Some implementations may not support expiration of items. + ???+ example "Examples" Store item. Indexing depends on how you configure the store. ```python @@ -954,7 +1115,22 @@ class BaseStore(ABC): ``` """ _validate_namespace(namespace) - await self.abatch([PutOp(namespace, key, value, index=index)]) + if ttl not in (NOT_PROVIDED, None) and not self.supports_ttl: + raise NotImplementedError( + f"TTL is not supported by {self.__class__.__name__}. " + f"Use a store implementation that supports TTL or set ttl=None." + ) + await self.abatch( + [ + PutOp( + namespace, + str(key), + value, + index=index, + ttl=_ensure_ttl(self.ttl_config, ttl), + ) + ] + ) async def adelete(self, namespace: tuple[str, ...], key: str) -> None: """Asynchronously delete an item. @@ -963,7 +1139,7 @@ class BaseStore(ABC): namespace: Hierarchical path for the item. key: Unique identifier within the namespace. """ - await self.abatch([PutOp(namespace, key, None)]) + await self.abatch([PutOp(namespace, str(key), None)]) async def alist_namespaces( self, @@ -1043,6 +1219,27 @@ def _validate_namespace(namespace: tuple[str, ...]) -> None: ) +def _ensure_refresh( + ttl_config: Optional[TTLConfig], refresh_ttl: Optional[bool] = None +) -> bool: + if refresh_ttl is not None: + return refresh_ttl + if ttl_config is not None: + return ttl_config.get("refresh_on_read", True) + return True + + +def _ensure_ttl( + ttl_config: Optional[TTLConfig], + ttl: Union[Optional[float], "NotProvided"] = NOT_PROVIDED, +) -> Optional[float]: + if ttl is NOT_PROVIDED: + if ttl_config: + return ttl_config.get("default_ttl") + return None + return ttl + + __all__ = [ "BaseStore", "Item", diff --git a/libs/checkpoint/langgraph/store/base/batch.py b/libs/checkpoint/langgraph/store/base/batch.py index debf187b3..4883a3282 100644 --- a/libs/checkpoint/langgraph/store/base/batch.py +++ b/libs/checkpoint/langgraph/store/base/batch.py @@ -5,17 +5,21 @@ from collections.abc import Iterable from typing import Any, Callable, Literal, Optional, TypeVar, Union from langgraph.store.base import ( + NOT_PROVIDED, BaseStore, GetOp, Item, ListNamespacesOp, MatchCondition, NamespacePath, + NotProvided, Op, PutOp, Result, SearchItem, SearchOp, + _ensure_refresh, + _ensure_ttl, _validate_namespace, ) @@ -68,10 +72,21 @@ class AsyncBatchedBaseStore(BaseStore): self, namespace: tuple[str, ...], key: str, + *, + refresh_ttl: Optional[bool] = None, ) -> Optional[Item]: assert not self._task.done() fut = self._loop.create_future() - self._aqueue.put_nowait((fut, GetOp(namespace, key))) + self._aqueue.put_nowait( + ( + fut, + GetOp( + namespace, + key, + refresh_ttl=_ensure_refresh(self.ttl_config, refresh_ttl), + ), + ) + ) return await fut async def asearch( @@ -83,11 +98,22 @@ class AsyncBatchedBaseStore(BaseStore): filter: Optional[dict[str, Any]] = None, limit: int = 10, offset: int = 0, + refresh_ttl: Optional[bool] = None, ) -> list[SearchItem]: assert not self._task.done() fut = self._loop.create_future() self._aqueue.put_nowait( - (fut, SearchOp(namespace_prefix, filter, limit, offset, query)) + ( + fut, + SearchOp( + namespace_prefix, + filter, + limit, + offset, + query, + refresh_ttl=_ensure_refresh(self.ttl_config, refresh_ttl), + ), + ) ) return await fut @@ -97,11 +123,20 @@ class AsyncBatchedBaseStore(BaseStore): key: str, value: dict[str, Any], index: Optional[Union[Literal[False], list[str]]] = None, + *, + ttl: Union[Optional[float], "NotProvided"] = NOT_PROVIDED, ) -> None: assert not self._task.done() _validate_namespace(namespace) fut = self._loop.create_future() - self._aqueue.put_nowait((fut, PutOp(namespace, key, value, index))) + self._aqueue.put_nowait( + ( + fut, + PutOp( + namespace, key, value, index, ttl=_ensure_ttl(self.ttl_config, ttl) + ), + ) + ) return await fut async def adelete( @@ -149,9 +184,11 @@ class AsyncBatchedBaseStore(BaseStore): self, namespace: tuple[str, ...], key: str, + *, + refresh_ttl: Optional[bool] = None, ) -> Optional[Item]: return asyncio.run_coroutine_threadsafe( - self.aget(namespace, key=key), self._loop + self.aget(namespace, key=key, refresh_ttl=refresh_ttl), self._loop ).result() @_check_loop @@ -164,10 +201,16 @@ class AsyncBatchedBaseStore(BaseStore): filter: Optional[dict[str, Any]] = None, limit: int = 10, offset: int = 0, + refresh_ttl: Optional[bool] = None, ) -> list[SearchItem]: return asyncio.run_coroutine_threadsafe( self.asearch( - namespace_prefix, query=query, filter=filter, limit=limit, offset=offset + namespace_prefix, + query=query, + filter=filter, + limit=limit, + offset=offset, + refresh_ttl=refresh_ttl, ), self._loop, ).result() @@ -179,10 +222,19 @@ class AsyncBatchedBaseStore(BaseStore): key: str, value: dict[str, Any], index: Optional[Union[Literal[False], list[str]]] = None, + *, + ttl: Union[Optional[float], "NotProvided"] = NOT_PROVIDED, ) -> None: _validate_namespace(namespace) asyncio.run_coroutine_threadsafe( - self.aput(namespace, key=key, value=value, index=index), self._loop + self.aput( + namespace, + key=key, + value=value, + index=index, + ttl=_ensure_ttl(self.ttl_config, ttl), + ), + self._loop, ).result() @_check_loop diff --git a/libs/checkpoint/pyproject.toml b/libs/checkpoint/pyproject.toml index 9610d8fc5..354205b2a 100644 --- a/libs/checkpoint/pyproject.toml +++ b/libs/checkpoint/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-checkpoint" -version = "2.0.16" +version = "2.0.19" description = "Library with base interfaces for LangGraph checkpoint savers." authors = [] license = "MIT" diff --git a/libs/checkpoint/tests/test_jsonplus.py b/libs/checkpoint/tests/test_jsonplus.py index 869e7732e..b75962308 100644 --- a/libs/checkpoint/tests/test_jsonplus.py +++ b/libs/checkpoint/tests/test_jsonplus.py @@ -130,7 +130,7 @@ def test_serde_jsonplus() -> None: key="my-key", namespace=("a", "name", " "), created_at=datetime(2024, 9, 24, 17, 29, 10, 128397), - updated_at=datetime(2024, 9, 24, 17, 29, 10, 128397), + updated_at=datetime(2024, 9, 24, 17, 29, 11, 128397), ), } diff --git a/libs/checkpoint/tests/test_store.py b/libs/checkpoint/tests/test_store.py index 053d9a981..9a306a086 100644 --- a/libs/checkpoint/tests/test_store.py +++ b/libs/checkpoint/tests/test_store.py @@ -148,8 +148,8 @@ async def test_async_batch_store(mocker: MockerFixture) -> None: assert abatch.call_count == 1 assert [tuple(c.args[0]) for c in abatch.call_args_list] == [ ( - GetOp(("a",), "b"), - GetOp(("c",), "d"), + GetOp(("a",), "b", refresh_ttl=True), + GetOp(("c",), "d", refresh_ttl=True), ), ] @@ -467,8 +467,8 @@ async def test_async_batch_store_deduplication(mocker: MockerFixture) -> None: assert len(abatch.call_args_list) == 1 ops = list(abatch.call_args_list[0].args[1]) assert len(ops) == 2 - assert GetOp(("test",), "same") in ops - assert GetOp(("test",), "different") in ops + assert GetOp(("test",), "same", refresh_ttl=True) in ops + assert GetOp(("test",), "different", refresh_ttl=True) in ops abatch.reset_mock() diff --git a/libs/cli/generate_schema.py b/libs/cli/generate_schema.py new file mode 100644 index 000000000..1d557035c --- /dev/null +++ b/libs/cli/generate_schema.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +""" +Script to generate a JSON schema for the langgraph-cli Config class. + +This script creates a schema.json file that can be referenced in langgraph.json files +to provide IDE autocompletion and validation. +""" + +import inspect +import json +import textwrap +from pathlib import Path + +import msgspec + +from langgraph_cli.config import ( + AuthConfig, + Config, + CorsConfig, + HttpConfig, + IndexConfig, + SecurityConfig, + StoreConfig, +) + + +def add_descriptions_to_schema(schema, cls): + """Add docstring descriptions to the schema properties.""" + if schema.get("description"): + schema["description"] = inspect.cleandoc(schema["description"]) + elif class_doc := inspect.getdoc(cls): + schema["description"] = inspect.cleandoc(class_doc) + # Get attribute docstrings from the class + attr_docs = {} + + # Also check class annotations for docstrings + source_lines = inspect.getsourcelines(cls)[0] + current_attr = None + docstring_lines = [] + + for line in source_lines: + line = line.strip() + + # Check for attribute definition (TypedDict style) + if ":" in line and not line.startswith("#") and not line.startswith('"""'): + parts = line.split(":", 1) + if len(parts) == 2 and parts[0].strip().isidentifier(): + # If we were collecting a docstring, save it for the previous attribute + if current_attr and docstring_lines: + attr_docs[current_attr] = "\n".join(docstring_lines).strip('"') + docstring_lines = [] + + current_attr = parts[0].strip() + + # Check for docstring after attribute + elif line.startswith('"""') and current_attr: + # Start or end of a docstring + if len(line) > 3 and line.endswith('"""'): + # Single line docstring + attr_docs[current_attr] = line.strip('"') + current_attr = None + elif docstring_lines: + # End of multi-line docstring + docstring_lines.append(line.rstrip('"')) + attr_docs[current_attr] = "\n".join(docstring_lines).strip('"') + docstring_lines = [] + current_attr = None + else: + # Start of multi-line docstring + docstring_lines.append(line.lstrip('"')) + + # Continue multi-line docstring + elif docstring_lines and current_attr: + docstring_lines.append(line.strip('"')) + + # Add the last docstring if there is one + if current_attr and docstring_lines: + attr_docs[current_attr] = "\n".join(docstring_lines).strip('"') + + # Add descriptions to properties + if "properties" in schema: + for prop_name, prop_schema in schema["properties"].items(): + # First try to get from attribute docstrings + if prop_name in attr_docs and "description" not in prop_schema: + prop_schema["description"] = textwrap.dedent(attr_docs[prop_name]) + # Fall back to class docstring parsing + elif class_doc: + for line in class_doc.split("\n"): + if line.strip().startswith( + f"{prop_name}:" + ) or line.strip().startswith(f'"{prop_name}"'): + description = line.split(":", 1)[1].strip() + if description and "description" not in prop_schema: + prop_schema["description"] = description + break + + # Recursively process nested definitions + if "$defs" in schema: + for def_name, def_schema in schema["$defs"].items(): + # Find the class that corresponds to this definition + for potential_cls in [ + Config, + StoreConfig, + IndexConfig, + AuthConfig, + SecurityConfig, + HttpConfig, + CorsConfig, + ]: + if potential_cls.__name__ == def_name: + add_descriptions_to_schema(def_schema, potential_cls) + break + + return schema + + +def generate_schema(): + """Generate a JSON schema for the Config class using msgspec.""" + # Generate the basic schema + schema = msgspec.json.schema(Config) + + # Add title and description + schema["title"] = "LangGraph CLI Configuration" + schema["description"] = "Configuration schema for langgraph-cli" + + # Add docstring descriptions + schema = add_descriptions_to_schema(schema, Config) + + # Add constraint that only one of python_version or node_version should be specified + config_schema = schema["$defs"]["Config"] + + # Create two subschemas: one with python_version and one with node_version + # Define properties specific to Python projects + python_specific_props = ["python_version", "pip_config_file"] + # Define properties specific to Node.js projects + node_specific_props = ["node_version"] + # Define properties common to both project types + common_props = [ + k + for k in config_schema["properties"] + if k not in python_specific_props and k not in node_specific_props + ] + + # Create Python schema with python_version and pip_config_file + python_schema = { + "type": "object", + "properties": { + # Include Python-specific properties + **{k: config_schema["properties"][k].copy() for k in python_specific_props}, + # Include common properties + **{k: config_schema["properties"][k].copy() for k in common_props}, + }, + "required": ["dependencies", "graphs"], + } + + # Add enum constraint for python_version + if "python_version" in python_schema["properties"]: + python_schema["properties"]["python_version"]["enum"] = ["3.11", "3.12"] + + # Create Node.js schema with node_version + node_schema = { + "type": "object", + "properties": { + # Include Node-specific properties + **{k: config_schema["properties"][k].copy() for k in node_specific_props}, + # Include common properties + **{k: config_schema["properties"][k].copy() for k in common_props}, + }, + "required": ["node_version", "graphs"], + } + + # Add enum constraint for node_version + if "node_version" in node_schema["properties"]: + node_schema["properties"]["node_version"]["anyOf"] = [ + {"type": "string", "enum": ["20"]}, + {"type": "null"}, + ] + + # Replace the Config schema with a oneOf constraint + config_schema["oneOf"] = [python_schema, node_schema] + + # Remove the properties field as it's now defined in the oneOf subschemas + if "properties" in config_schema: + del config_schema["properties"] + + return schema + + +def main(): + """Generate the schema and write it to a file.""" + schema = generate_schema() + + # Add versioning to the schema + import importlib.metadata + + try: + version = importlib.metadata.version("langgraph_cli").split(".") + schema_version = f"v{version[0]}" + except importlib.metadata.PackageNotFoundError: + schema_version = "v1" + + # Add version to schema + schema["version"] = schema_version + + config_dir = Path(__file__).parent / "schemas" + + # Create versioned schema file + versioned_path = config_dir / f"schema.{schema_version}.json" + with open(versioned_path, "w") as f: + json.dump(schema, f, indent=2) + + # Also create a latest version + latest_path = config_dir / "schema.json" + with open(latest_path, "w") as f: + json.dump(schema, f, indent=2) + + print(f"Schema written to {versioned_path} and {latest_path}") + print( + f"You can now add '$schema: https://raw.githubusercontent.com/langchain-ai/langgraph/refs/heads/main/libs/cli/schemas/schema.json'" + f" or '$schema: https://raw.githubusercontent.com/langchain-ai/langgraph/refs/heads/main/libs/cli/schemas/schema.{schema_version}.json'" + " to your langgraph.json files" + ) + + +if __name__ == "__main__": + main() diff --git a/libs/cli/langgraph_cli/config.py b/libs/cli/langgraph_cli/config.py index 7fbe57056..6200b1ad7 100644 --- a/libs/cli/langgraph_cli/config.py +++ b/libs/cli/langgraph_cli/config.py @@ -3,7 +3,7 @@ import os import pathlib import textwrap from collections import Counter -from typing import NamedTuple, Optional, TypedDict, Union +from typing import Any, NamedTuple, Optional, TypedDict, Union import click @@ -11,13 +11,37 @@ MIN_NODE_VERSION = "20" MIN_PYTHON_VERSION = "3.11" +class TTLConfig(TypedDict, total=False): + """Configuration for TTL (time-to-live) behavior in the store.""" + + refresh_on_read: bool + """Default behavior for refreshing TTLs on read operations (GET and SEARCH). + + If True, TTLs will be refreshed on read operations (get/search) by default. + This can be overridden per-operation by explicitly setting refresh_ttl. + Defaults to True if not configured. + """ + default_ttl: Optional[float] + """Optional. Default TTL (time-to-live) in minutes for new items. + + If provided, all new items will have this TTL unless explicitly overridden. + If omitted, items will have no TTL by default. + """ + + class IndexConfig(TypedDict, total=False): - """Configuration for indexing documents for semantic search in the store.""" + """Configuration for indexing documents for semantic search in the store. + + This governs how text is converted into embeddings and stored for vector-based lookups. + """ dims: int - """Number of dimensions in the embedding vectors. + """Required. Dimensionality of the embedding vectors you will store. - Common embedding models have the following dimensions: + Must match the output dimension of your selected embedding model or custom embed function. + If mismatched, you will likely encounter shape/size errors when inserting or querying vectors. + + Common embedding model output dimensions: - openai:text-embedding-3-large: 3072 - openai:text-embedding-3-small: 1536 - openai:text-embedding-ada-002: 1536 @@ -28,42 +52,130 @@ class IndexConfig(TypedDict, total=False): """ embed: str - """Optional model (string) to generate embeddings from text or path to model or function. + """Required. Identifier or reference to the embedding model or a custom embedding function. - Examples: + The format can vary: + - ":" for recognized providers (e.g., "openai:text-embedding-3-large") + - "path/to/module.py:function_name" for your own local embedding function + - "my_custom_embed" if it's a known alias in your system + + Examples: - "openai:text-embedding-3-large" - "cohere:embed-multilingual-v3.0" - - "src/app.py:embeddings + - "src/app.py:embeddings" + + Note: Must return embeddings of dimension `dims`. """ fields: Optional[list[str]] - """Fields to extract text from for embedding generation. + """Optional. List of JSON fields to extract before generating embeddings. - Defaults to the root ["$"], which embeds the json object as a whole. + Defaults to ["$"], which means the entire JSON object is embedded as one piece of text. + If you provide multiple fields (e.g. ["title", "content"]), each is extracted and embedded separately, + often saving token usage if you only care about certain parts of the data. + + Example: + fields=["title", "abstract", "author.biography"] """ class StoreConfig(TypedDict, total=False): - embed: Optional[IndexConfig] - """Configuration for vector embeddings in store.""" + """Configuration for the built-in long-term memory store. + + This store can optionally perform semantic search. If you omit `index`, + the store will just handle traditional (non-embedded) data without vector lookups. + """ + + index: Optional[IndexConfig] + """Optional. Defines the vector-based semantic search configuration. + + If provided, the store will: + - Generate embeddings according to `index.embed` + - Enforce the embedding dimension given by `index.dims` + - Embed only specified JSON fields (if any) from `index.fields` + + If omitted, no vector index is initialized. + """ + + ttl: Optional[TTLConfig] + """Optional. Defines the TTL (time-to-live) behavior configuration. + + If provided, the store will apply TTL settings according to the configuration. + If omitted, no TTL behavior is configured. + """ class SecurityConfig(TypedDict, total=False): - securitySchemes: dict - security: list + """Configuration for OpenAPI security definitions and requirements. + + Useful for specifying global or path-level authentication and authorization flows + (e.g., OAuth2, API key headers, etc.). + """ + + securitySchemes: dict[str, dict[str, Any]] + """Required. Dict describing each security scheme recognized by your OpenAPI spec. + + Keys are scheme names (e.g. "OAuth2", "ApiKeyAuth") and values are their definitions. + Example: + { + "OAuth2": { + "type": "oauth2", + "flows": { + "password": { + "tokenUrl": "/token", + "scopes": {"read": "Read data", "write": "Write data"} + } + } + } + } + """ + security: list[dict[str, list[str]]] + """Optional. Global security requirements across all endpoints. + + Each element in the list maps a security scheme (e.g. "OAuth2") to a list of scopes (e.g. ["read", "write"]). + Example: + [ + {"OAuth2": ["read", "write"]}, + {"ApiKeyAuth": []} + ] + """ # path => {method => security} - paths: dict[str, dict[str, list]] + paths: dict[str, dict[str, list[dict[str, list[str]]]]] + """Optional. Path-specific security overrides. + + Keys are path templates (e.g., "/items/{item_id}"), mapping to: + - Keys that are HTTP methods (e.g., "GET", "POST"), + - Values are lists of security definitions (just like `security`) for that method. + + Example: + { + "/private_data": { + "GET": [{"OAuth2": ["read"]}], + "POST": [{"OAuth2": ["write"]}] + } + } + """ class AuthConfig(TypedDict, total=False): - path: str - """Path to the authentication function in a Python file.""" - disable_studio_auth: bool - """Whether to disable auth when connecting from the LangSmith Studio.""" - openapi: SecurityConfig - """The schema to use for updating the openapi spec. + """Configuration for custom authentication logic and how it integrates into the OpenAPI spec.""" - Example: + path: str + """Required. Path to an instance of the Auth() class that implements custom authentication. + + Format: "path/to/file.py:my_auth" + """ + disable_studio_auth: bool + """Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio. + + Defaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header + value is a valid API key for the deployment's workspace. If True, all requests will go through your custom + authentication logic, regardless of origin of the request. + """ + openapi: SecurityConfig + """Required. Detailed security configuration that merges into your deployment's OpenAPI spec. + + Example (OAuth2): { "securitySchemes": { "OAuth2": { @@ -71,88 +183,185 @@ class AuthConfig(TypedDict, total=False): "flows": { "password": { "tokenUrl": "/token", - "scopes": { - "me": "Read information about the current user", - "items": "Access to create and manage items" - } + "scopes": {"me": "Read user info", "items": "Manage items"} } } } }, "security": [ - {"OAuth2": ["me"]} # Default security requirement for all endpoints + {"OAuth2": ["me"]} ] } """ class CorsConfig(TypedDict, total=False): + """Specifies Cross-Origin Resource Sharing (CORS) rules for your server. + + If omitted, defaults are typically very restrictive (often no cross-origin requests). + Configure carefully if you want to allow usage from browsers hosted on other domains. + """ + allow_origins: list[str] + """Optional. List of allowed origins (e.g., "https://example.com"). + + Default is often an empty list (no external origins). + Use "*" only if you trust all origins, as that bypasses most restrictions. + """ allow_methods: list[str] + """Optional. HTTP methods permitted for cross-origin requests (e.g. ["GET", "POST"]). + + Default might be ["GET", "POST", "OPTIONS"] depending on your server framework. + """ allow_headers: list[str] + """Optional. HTTP headers that can be used in cross-origin requests (e.g. ["Content-Type", "Authorization"]).""" allow_credentials: bool + """Optional. If True, cross-origin requests can include credentials (cookies, auth headers). + + Default False to avoid accidentally exposing secured endpoints to untrusted sites. + """ allow_origin_regex: str + """Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains. + + Example: "^https://.*\.mycompany\.com$" + """ expose_headers: list[str] + """Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts.""" max_age: int + """Optional. How many seconds the browser may cache preflight responses. + + Default might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations. + """ class HttpConfig(TypedDict, total=False): + """Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.""" + app: str - """Import path for a custom Starlette/FastAPI app to mount""" + """Optional. Import path to a custom Starlette/FastAPI application to mount. + + Format: "path/to/module.py:app_var" + If provided, it can override or extend the default routes. + """ disable_assistants: bool - """Disable /assistants routes""" + """Optional. If True, /assistants routes are removed from the server. + + Default is False (meaning /assistants is enabled). + """ disable_threads: bool - """Disable /threads routes""" + """Optional. If True, /threads routes are removed. + + Default is False. + """ disable_runs: bool - """Disable /runs routes""" + """Optional. If True, /runs routes are removed. + + Default is False. + """ disable_store: bool - """Disable /store routes""" + """Optional. If True, /store routes are removed, disabling direct store interactions via HTTP. + + Default is False. + """ disable_meta: bool - """Disable /ok, /info, /metrics, and /docs routes""" + """Optional. If True, all meta endpoints (/ok, /info, /metrics, /docs) are disabled. + + Default is False. + """ cors: Optional[CorsConfig] - """Cross-Origin Resource Sharing (CORS) configuration""" + """Optional. Defines CORS restrictions. If omitted, no special rules are set and + cross-origin behavior depends on default server settings. + """ class Config(TypedDict, total=False): - """Configuration for langgraph-cli.""" + """Top-level config for langgraph-cli or similar deployment tooling.""" python_version: str - """Python version to use.""" + """Optional. Python version in 'major.minor' format (e.g. '3.11'). + Must be at least 3.11 or greater for this deployment to function properly. + """ node_version: Optional[str] - """Node.js version to use.""" + """Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node. + Must be >= 20 if provided. + """ pip_config_file: Optional[str] - """Path to a pip configuration file.""" + """Optional. Path to a pip config file (e.g., "/etc/pip.conf" or "pip.ini") for controlling + package installation (custom indices, credentials, etc.). + + Only relevant if Python dependencies are installed via pip. If omitted, default pip settings are used. + """ dockerfile_lines: list[str] - """Additional lines to add to the Dockerfile.""" + """Optional. Additional Docker instructions that will be appended to your base Dockerfile. + + Useful for installing OS packages, setting environment variables, etc. + Example: + dockerfile_lines=[ + "RUN apt-get update && apt-get install -y libmagic-dev", + "ENV MY_CUSTOM_VAR=hello_world" + ] + """ dependencies: list[str] - """Additional Python dependencies to install.""" + """List of Python dependencies to install, either from PyPI or local paths. + + Examples: + - "." or "./src" if you have a local Python package + - str (aka "anthropic") for a PyPI package + - "git+https://github.com/org/repo.git@main" for a Git-based package + Defaults to an empty list, meaning no additional packages installed beyond your base environment. + """ graphs: dict[str, str] - """Mapping of graph names to their definitions.""" + """Optional. Named definitions of graphs, each pointing to a Python object. + + + Graphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context + managers that accept a single configuration argument (of type RunnableConfig) and return a pregel object + (instance of Stategraph, etc.). + + Keys are graph names, values are "path/to/file.py:object_name". + Example: + { + "mygraph": "graphs/my_graph.py:graph_definition", + "anothergraph": "graphs/another.py:get_graph" + } + """ env: Union[dict[str, str], str] - """Environment variables to set. - - If a dictionary is provided, the keys are environment variable names - and the values are the corresponding environment variable values. - - If a string is provided, it is interpreted as a path to a file containing - environment variables in the format KEY=VALUE, with one environment variable - per line. + """Optional. Environment variables to set for your deployment. + + - If given as a dict, keys are variable names and values are their values. + - If given as a string, it must be a path to a file containing lines in KEY=VALUE format. + + Example as a dict: + env={"API_TOKEN": "abc123", "DEBUG": "true"} + Example as a file path: + env=".env" """ store: Optional[StoreConfig] - """Configuration for vector embeddings in store.""" + """Optional. Configuration for the built-in long-term memory store, including semantic search indexing. + + If omitted, no vector index is set up (the object store will still be present, however). + """ auth: Optional[AuthConfig] - """Configuration for authentication.""" + """Optional. Custom authentication config, including the path to your Python auth logic and + the OpenAPI security definitions it uses. + """ http: Optional[HttpConfig] - """Configuration for HTTP server.""" + """Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed + and how cross-origin requests are handled. + """ + + ui: Optional[dict[str, str]] + """Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file. + """ def _parse_version(version_str: str) -> tuple[int, int]: @@ -189,6 +398,7 @@ def validate_config(config: Config) -> Config: "store": config.get("store"), "auth": config.get("auth"), "http": config.get("http"), + "ui": config.get("ui"), } if config.get("node_version") else { @@ -201,6 +411,7 @@ def validate_config(config: Config) -> Config: "store": config.get("store"), "auth": config.get("auth"), "http": config.get("http"), + "ui": config.get("ui"), } ) @@ -687,9 +898,11 @@ def python_config_to_docker( pip_pkgs_str = f"RUN {pip_install} {' '.join(pypi_deps)}" if pypi_deps else "" if local_deps.pip_reqs: pip_reqs_str = os.linesep.join( - f"COPY --from=__outer_{reqpath.name} requirements.txt {destpath}" - if reqpath.parent in local_deps.additional_contexts - else f"ADD {reqpath.relative_to(config_path.parent)} {destpath}" + ( + f"COPY --from=__outer_{reqpath.name} requirements.txt {destpath}" + if reqpath.parent in local_deps.additional_contexts + else f"ADD {reqpath.relative_to(config_path.parent)} {destpath}" + ) for reqpath, destpath in local_deps.pip_reqs ) pip_reqs_str += f'{os.linesep}RUN {pip_install} {" ".join("-r " + r for _,r in local_deps.pip_reqs)}' @@ -724,13 +937,15 @@ RUN set -ex && \\ ) local_pkgs_str = os.linesep.join( - f"""# -- Adding local package {relpath} -- + ( + f"""# -- Adding local package {relpath} -- COPY --from={name} . /deps/{name} # -- End of local package {relpath} --""" - if fullpath in local_deps.additional_contexts - else f"""# -- Adding local package {relpath} -- + if fullpath in local_deps.additional_contexts + else f"""# -- Adding local package {relpath} -- ADD {relpath} /deps/{name} # -- End of local package {relpath} --""" + ) for fullpath, (relpath, name) in local_deps.real_pkgs.items() ) @@ -845,6 +1060,7 @@ ADD . {faux_path} RUN cd {faux_path} && {install_cmd} {env_additional_config} ENV LANGSERVE_GRAPHS='{json.dumps(config["graphs"])}' +{f"ENV LANGGRAPH_UI='{json.dumps(config['ui'])}'" if config.get("ui") else ""} WORKDIR {faux_path} diff --git a/libs/cli/poetry.lock b/libs/cli/poetry.lock index 68a839881..e710fb217 100644 --- a/libs/cli/poetry.lock +++ b/libs/cli/poetry.lock @@ -446,54 +446,47 @@ files = [ [[package]] name = "jsonschema-rs" -version = "0.25.1" +version = "0.20.0" description = "A high-performance JSON Schema validator for Python" optional = true python-versions = ">=3.8" files = [ - {file = "jsonschema_rs-0.25.1-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0dc49a465a02f97a8c747e852bc82322dd56ff7d66b3058c9656e15b8a5e381c"}, - {file = "jsonschema_rs-0.25.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf196d06dea3af58a23e6a03e363140ee307fc80fc77d8c71068df3de1bca588"}, - {file = "jsonschema_rs-0.25.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f7bc2cac3891b75c301090effba458b6e7108d568aa2aeadb5695d7788991fa3"}, - {file = "jsonschema_rs-0.25.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bc130df50b530c57524c7edc29808700d51304f94477833fb0062e0f3df1dfb"}, - {file = "jsonschema_rs-0.25.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dace81a4652029493a19e24454bb5f821acdacf65da4f6472bbdc6751c45b79"}, - {file = "jsonschema_rs-0.25.1-cp310-none-win32.whl", hash = "sha256:dc9771bbe5672f89a974b7302f5e4421559a8d0903eab2c38510dd61bd526086"}, - {file = "jsonschema_rs-0.25.1-cp310-none-win_amd64.whl", hash = "sha256:7be237cc251c0fe9fe196adf4a7a8402339bbf58ef8710ab76b9e4b845fc94bd"}, - {file = "jsonschema_rs-0.25.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:df22e50adba344efc018322305386357bf30c4b6a9b48349f565ff410d1eb78e"}, - {file = "jsonschema_rs-0.25.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:db9fb2086a8a64e40e95e0f6bb0a91ea387419d0d239fc59d468586702286a89"}, - {file = "jsonschema_rs-0.25.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a168559e9f1fff42d9a2a78c46143fda7ee58a90b85a7d11140dfe16e609e92b"}, - {file = "jsonschema_rs-0.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e4f659487071009749077b4f5ee69300772fa321f92fa831e71fd4218839958"}, - {file = "jsonschema_rs-0.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b1e9f7c05c8c9656bb98ecc93a0b91408a6e73063956dea7452cd64277f3b9f"}, - {file = "jsonschema_rs-0.25.1-cp311-none-win32.whl", hash = "sha256:406a18dafac01b7799dd86b1b05bf14e8628d1f8bc0a1a9c187458f246c2f6cc"}, - {file = "jsonschema_rs-0.25.1-cp311-none-win_amd64.whl", hash = "sha256:3546274ae6e11fcc1b058cdd763803c4db24e49bac125076bc4fab0ab61d4786"}, - {file = "jsonschema_rs-0.25.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:cfaed89ef79cc972d11c50889fa02e8265aa5b6b6826c40749b956888712909d"}, - {file = "jsonschema_rs-0.25.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:87432343bcbd91475af28c765caa0bbde534bbfb6fac1245735a5a1dd6b522a4"}, - {file = "jsonschema_rs-0.25.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e69c9faed321b7cfbeb37e98e385a0392ad8d25896fd3def56afd080e56e294c"}, - {file = "jsonschema_rs-0.25.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f004018ffb7fbffc8f1dbeb1bda44f322c924e007bb6966ab3466bdffbc06e62"}, - {file = "jsonschema_rs-0.25.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b05e2f6bf86ced9d912d72329a19d39a86fcc49a85e31b923456d982733eaa7f"}, - {file = "jsonschema_rs-0.25.1-cp312-none-win32.whl", hash = "sha256:b3d2ea6217e3618ba587d374b89f4660de59293b0a2fa43278131bc2cb339f57"}, - {file = "jsonschema_rs-0.25.1-cp312-none-win_amd64.whl", hash = "sha256:6ceeaec97e77d14d6355aec9e55b2356d6376fdf94f6fed10c29cadc8e51fdf6"}, - {file = "jsonschema_rs-0.25.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4696a580f54855cda68c05bbd7c25328eadca34b6a31b36495961235c511148d"}, - {file = "jsonschema_rs-0.25.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a2d9844d70e5a481a1c363b8b02a3862cc1dbc3b14551a8060436e53243d5447"}, - {file = "jsonschema_rs-0.25.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd168893519bae7c09fb7226f4ac4b6e73bc1ce9397c3846870cf980135762e8"}, - {file = "jsonschema_rs-0.25.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e6627f4ecf1cb12765734f39a536bb4a062e35c9db756d52581b4d045489025"}, - {file = "jsonschema_rs-0.25.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4784b0c1a0596595e0ea482d6656ccd33d7f14fbf32456e76fead0a67c6a7ec5"}, - {file = "jsonschema_rs-0.25.1-cp313-none-win32.whl", hash = "sha256:7e6984721dbaaffc6a32ba15b4988df56e4069c9f867370a8a3c48a69a311ac3"}, - {file = "jsonschema_rs-0.25.1-cp313-none-win_amd64.whl", hash = "sha256:62234e768a1cc57690602711e37f2b936b0f081dcd34a9c2b3e20ba0dafcbceb"}, - {file = "jsonschema_rs-0.25.1-cp38-cp38-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:346a46f25d974b4ae1d36ac3c02677a699b46404b019a688ddabef40840019fc"}, - {file = "jsonschema_rs-0.25.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:32f4908bc5c958a0a94a25260f5be59fba0062a60a40b61f0faedf12eed82063"}, - {file = "jsonschema_rs-0.25.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ce090f2038f1a01836adf9f821f7e8c82073710c7a55b002a2e7a1625c3f3954"}, - {file = "jsonschema_rs-0.25.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4ef0f3b0760ab151c35f5c8e090cdb201fb81eae2cf5ea1771f4d827d0cfbb1"}, - {file = "jsonschema_rs-0.25.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c732bd71da96d6600ae550401e7997fb470f73f95af8defefe4fcbc5e4e9043"}, - {file = "jsonschema_rs-0.25.1-cp38-none-win32.whl", hash = "sha256:b9ea15dfa5c47b1658e77c3a04e7c38b66e6a617617e1b9f5dba53b67712da1e"}, - {file = "jsonschema_rs-0.25.1-cp38-none-win_amd64.whl", hash = "sha256:0d8438bea4c09994973ac60c645f4735808329908f4b9421f07d7f2ddf8ac860"}, - {file = "jsonschema_rs-0.25.1-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6c9ea0b69fab4a27e0c8c0edbee24db2da44d2a97657469ee30a2b980b0b445c"}, - {file = "jsonschema_rs-0.25.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:9de3946a1cd66daae805578ad5cbf21ff4d590d7206048f0eb2999aab056a78a"}, - {file = "jsonschema_rs-0.25.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3bd2ae54066e840cb5595d135b40c9458a0155e482998e00e922ea6b5ab57a24"}, - {file = "jsonschema_rs-0.25.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb7e2a6777e78a699d09e5c6e84318e97a8e80727939fcde3d0faff7f9da85f3"}, - {file = "jsonschema_rs-0.25.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a87babb64a93bad6bfbf2ddad0e33cab6c3f395e9572fe027387c7767e9741c"}, - {file = "jsonschema_rs-0.25.1-cp39-none-win32.whl", hash = "sha256:570dffc76f0b4e9fa93cf4678a6b07d6fa446f1e5557525703160a94c0ab7968"}, - {file = "jsonschema_rs-0.25.1-cp39-none-win_amd64.whl", hash = "sha256:9117e105f979f11f55ae940949a544e7e1a304b56ae65f535fa82cc8af4dc2e1"}, - {file = "jsonschema_rs-0.25.1.tar.gz", hash = "sha256:f2fe71253bb0315061a5025b9336fd49660bca4094b04948f53e3acfd4197a64"}, + {file = "jsonschema_rs-0.20.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d4b12f8aaec5037529fd11e5f71032cb53d44e8e2236bb7c3fb35e6efc7ce7f2"}, + {file = "jsonschema_rs-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:25d512c47c5c391020c9fc4223f270cf42fbdd39b2906dbc894fe0205168b8f8"}, + {file = "jsonschema_rs-0.20.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e4d449a8c2d67c774b8719964cf4dc8eb453a6c665ddf0815780dbcc46a31be"}, + {file = "jsonschema_rs-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60e14bd30306f300d194d6053a8b7dc3723bac20edc2c27db055e45bcc02687c"}, + {file = "jsonschema_rs-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ea9cd8058c6d8ace05fd60a4e11d5bd933f4c21d55c4cccb2bdb6faba9b0319"}, + {file = "jsonschema_rs-0.20.0-cp310-none-win32.whl", hash = "sha256:ef3198e43addd93619242a30ba40962521b384d68c05507fc680b549d95f7cc0"}, + {file = "jsonschema_rs-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:ab5a5c6b7282242c64bfc812c10d72dcbd9f5fe083cf81ae94de3cc2da7f0e1e"}, + {file = "jsonschema_rs-0.20.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2f76153d57c8c3778829e14867dd6479eaba17f56e2ba42da82494663200b37a"}, + {file = "jsonschema_rs-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:1a2b24871ade985580a3f10cfde2a52673823163813fe311abffb30e0aeb4181"}, + {file = "jsonschema_rs-0.20.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6bf5afaa6e80aa59fae06ca92efb1f8e29b2679f8f8884585272f7c100f04c69"}, + {file = "jsonschema_rs-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42d180b318653184eb69d9641dfded6b2d59c88db8fb82012d3d20e1582af5cd"}, + {file = "jsonschema_rs-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aa67bf6338fbce3a2a3f9f408413aad7a72593ed73c846bc2667a20b747327f"}, + {file = "jsonschema_rs-0.20.0-cp311-none-win32.whl", hash = "sha256:55c255ca6ee44177b7b5c773a8edb25af34be0d6a454e602be92cc183d6dcbe7"}, + {file = "jsonschema_rs-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:3b6effefdef590854522517b84081214b46a8fba9a5d60c538c6f1ff819609c5"}, + {file = "jsonschema_rs-0.20.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8b9d044ecdef9a15e350a35e950c9797c804f185b547bcb56bb91fef9bf31827"}, + {file = "jsonschema_rs-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d43b6a65c159f7aed82dca846f93a4c5ffd013ff0c87a5668a645a81792c8001"}, + {file = "jsonschema_rs-0.20.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9a6500934be21fe64bd65d9e75a67941b675091b8e2154df0a04f5b57073b8bf"}, + {file = "jsonschema_rs-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e42c80eed641a848ee38039291e6ca90e61de1a0b695e706894b175f45c741"}, + {file = "jsonschema_rs-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e0945cb1ff4d183e855ae975839d648df24604d71827951f57a8b7edabb8ca"}, + {file = "jsonschema_rs-0.20.0-cp312-none-win32.whl", hash = "sha256:00016bfdc132aa8c728fe012e9ed2b5c9d0d3dd5c37368990d58288e121a6d79"}, + {file = "jsonschema_rs-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:2c5abcf6185a4eea7185aadb132f92f6bc1d808d3debe775f0e4608baba8501e"}, + {file = "jsonschema_rs-0.20.0-cp38-cp38-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e51888f8c6c6434fc4037db71fe366c78d3bec8b8b200b6fc70d80266b932d77"}, + {file = "jsonschema_rs-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:7ff31a9bb78813e2d3331aa0e4b558d34d7aaa89ab518b2313ecd53c0b3fb4ef"}, + {file = "jsonschema_rs-0.20.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c7dfb51026ce11ca5b657022a149b7324c81bbe8ff43b57439421b0b57d623ce"}, + {file = "jsonschema_rs-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3278fd2f0a47a0e479b551f526778da76006798dd0fc3c19155223b402b110cf"}, + {file = "jsonschema_rs-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cc6b6935e6a8716b532b09f231d37e6dd39fa5bec3d87aad036a13206e601bd"}, + {file = "jsonschema_rs-0.20.0-cp38-none-win32.whl", hash = "sha256:8ae5f0a04dd4ed2a801df814e67436b6c2cafc127485003382e24a7831f46be3"}, + {file = "jsonschema_rs-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:ee28d48e8dd9f3da8d5dbe190ff769940a606792be16eeb1fe23a62ec0900297"}, + {file = "jsonschema_rs-0.20.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2a698ba8170dbb9fc32e1d0043c8f85903ffbcca56d7dc9ad8a9f169c72eae60"}, + {file = "jsonschema_rs-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4dcba330d2196f7af8229aca43178bdcacd8a393c76dee7b3763e7e2ac40457"}, + {file = "jsonschema_rs-0.20.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0afa2f4b2e4cd6688866a490f3d9d9bfa97a7f19aabd860cfc1c00b54f957a5e"}, + {file = "jsonschema_rs-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18acb318a367fdae7161126e36ecbc005b713684b7178ba853efdcac22d3f41f"}, + {file = "jsonschema_rs-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d0c7a497dbd59369018d6056f5ff54bf955ca385d186bfcf3529432323686f"}, + {file = "jsonschema_rs-0.20.0-cp39-none-win32.whl", hash = "sha256:16d670954877226b7ea66d777e7aba9ca0b6c70772630af67c836aa1e99ba143"}, + {file = "jsonschema_rs-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:12f62a745ee72a5ce109f7412d0f8c55f510158c7a69171d261f1da9bc8b4059"}, + {file = "jsonschema_rs-0.20.0.tar.gz", hash = "sha256:f76d52b7755d184844f1bfedc209c5107b5be3b6b2ae8531db4a0e563b8317ae"}, ] [package.extras] @@ -502,13 +495,13 @@ tests = ["flask (>=2.2.5)", "hypothesis (>=6.79.4)", "pytest (>=7.4.4)"] [[package]] name = "langchain-core" -version = "0.3.37" +version = "0.3.40" description = "Building applications with LLMs through composability" optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_core-0.3.37-py3-none-any.whl", hash = "sha256:8202fd6506ce139a3a1b1c4c3006216b1c7fffa40bdd1779f7d2c67f75eb5f79"}, - {file = "langchain_core-0.3.37.tar.gz", hash = "sha256:cda8786e616caa2f68f7cc9e811b9b50e3b63fb2094333318b348e5961a7ea01"}, + {file = "langchain_core-0.3.40-py3-none-any.whl", hash = "sha256:9f31358741f10a13db8531e8288b8a5ae91904018c5c2e6f739d6645a98fca03"}, + {file = "langchain_core-0.3.40.tar.gz", hash = "sha256:893a238b38491967c804662c1ec7c3e6ebaf223d1125331249c3cf3862ff2746"}, ] [package.dependencies] @@ -525,46 +518,47 @@ typing-extensions = ">=4.7" [[package]] name = "langgraph" -version = "0.2.74" +version = "0.3.1" description = "Building stateful, multi-actor applications with LLMs" optional = true python-versions = "<4.0,>=3.9.0" files = [ - {file = "langgraph-0.2.74-py3-none-any.whl", hash = "sha256:91a522df764e66068f1a6de09ea748cea0687912838f29218c1d1b92b1ca025f"}, - {file = "langgraph-0.2.74.tar.gz", hash = "sha256:db6e63e0771e2e8fb17dc0e040007b32f009e0f114e35d8348e336eb15f068e5"}, + {file = "langgraph-0.3.1-py3-none-any.whl", hash = "sha256:212e1220d6a2af27048109604c816ccfbceb53a9aa93721be874305d8e28b7f5"}, + {file = "langgraph-0.3.1.tar.gz", hash = "sha256:81cb89c381b089a20eac9a247f7ebcf3f41c922ac79e06dbcc4fc136c6f73dd5"}, ] [package.dependencies] -langchain-core = ">=0.2.43,<0.3.0 || >0.3.0,<0.3.1 || >0.3.1,<0.3.2 || >0.3.2,<0.3.3 || >0.3.3,<0.3.4 || >0.3.4,<0.3.5 || >0.3.5,<0.3.6 || >0.3.6,<0.3.7 || >0.3.7,<0.3.8 || >0.3.8,<0.3.9 || >0.3.9,<0.3.10 || >0.3.10,<0.3.11 || >0.3.11,<0.3.12 || >0.3.12,<0.3.13 || >0.3.13,<0.3.14 || >0.3.14,<0.3.15 || >0.3.15,<0.3.16 || >0.3.16,<0.3.17 || >0.3.17,<0.3.18 || >0.3.18,<0.3.19 || >0.3.19,<0.3.20 || >0.3.20,<0.3.21 || >0.3.21,<0.3.22 || >0.3.22,<0.4.0" +langchain-core = ">=0.1,<0.4" langgraph-checkpoint = ">=2.0.10,<3.0.0" +langgraph-prebuilt = ">=0.1.1,<0.2" langgraph-sdk = ">=0.1.42,<0.2.0" [[package]] name = "langgraph-api" -version = "0.0.26" +version = "0.0.27" description = "" optional = true python-versions = "<4.0,>=3.11.0" files = [ - {file = "langgraph_api-0.0.26-py3-none-any.whl", hash = "sha256:ecec9f0378f73dc0f0a30c43e1b920fe1f00821c82056efeb0de0ad81cdf4305"}, - {file = "langgraph_api-0.0.26.tar.gz", hash = "sha256:2a7606d6a8cf82774f4c5603d291835dec4fbb1dd93f3bba842cf5932c042da7"}, + {file = "langgraph_api-0.0.27-py3-none-any.whl", hash = "sha256:9b21742238b15b8db9c2d3fd760a670332c8897d0bcbbd9d82e43b6ac15a7937"}, + {file = "langgraph_api-0.0.27.tar.gz", hash = "sha256:c21eb2b7fe3b93998379f7b13ad7d23b3ef06ab821b008c6b12b954acfb587ec"}, ] [package.dependencies] cryptography = ">=43.0.3,<44.0.0" -httpx = ">=0.27.0" -jsonschema-rs = ">=0.25.0,<0.26.0" +httpx = ">=0.25.0" +jsonschema-rs = ">=0.20.0,<0.21.0" langchain-core = ">=0.2.38,<0.4.0" -langgraph = ">=0.2.56,<0.3.0" +langgraph = ">=0.2.56,<0.4.0" langgraph-checkpoint = ">=2.0.15,<3.0" langgraph-sdk = ">=0.1.53,<0.2.0" langsmith = ">=0.1.63,<0.4.0" -orjson = ">=3.10.1" +orjson = ">=3.9.7" pyjwt = ">=2.9.0,<3.0.0" sse-starlette = ">=2.1.0,<2.2.0" starlette = ">=0.38.6" -structlog = ">=24.4.0,<25.0.0" -tenacity = ">=8.3.0,<10" +structlog = ">=23.1.0,<24.0.0" +tenacity = ">=8.0.0" uvicorn = ">=0.26.0" watchfiles = ">=0.13" @@ -583,6 +577,21 @@ files = [ langchain-core = ">=0.2.38,<0.4" msgpack = ">=1.1.0,<2.0.0" +[[package]] +name = "langgraph-prebuilt" +version = "0.1.1" +description = "Library with high-level APIs for creating and executing LangGraph agents and tools." +optional = true +python-versions = "<4.0.0,>=3.9.0" +files = [ + {file = "langgraph_prebuilt-0.1.1-py3-none-any.whl", hash = "sha256:148a9558a36ec7e83cc6512f3521425c862b0463251ae0242ade52a448c54e78"}, + {file = "langgraph_prebuilt-0.1.1.tar.gz", hash = "sha256:420a748ff93842f2b1a345a0c1ca3939d2bc7a2d46c20e9a9a0d8f148152cc47"}, +] + +[package.dependencies] +langchain-core = ">=0.2.43,<0.3.0 || >0.3.0,<0.3.1 || >0.3.1,<0.3.2 || >0.3.2,<0.3.3 || >0.3.3,<0.3.4 || >0.3.4,<0.3.5 || >0.3.5,<0.3.6 || >0.3.6,<0.3.7 || >0.3.7,<0.3.8 || >0.3.8,<0.3.9 || >0.3.9,<0.3.10 || >0.3.10,<0.3.11 || >0.3.11,<0.3.12 || >0.3.12,<0.3.13 || >0.3.13,<0.3.14 || >0.3.14,<0.3.15 || >0.3.15,<0.3.16 || >0.3.16,<0.3.17 || >0.3.17,<0.3.18 || >0.3.18,<0.3.19 || >0.3.19,<0.3.20 || >0.3.20,<0.3.21 || >0.3.21,<0.3.22 || >0.3.22,<0.4.0" +langgraph-checkpoint = ">=2.0.10,<3.0.0" + [[package]] name = "langgraph-sdk" version = "0.1.53" @@ -600,18 +609,19 @@ orjson = ">=3.10.1" [[package]] name = "langsmith" -version = "0.3.8" +version = "0.3.11" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = true python-versions = "<4.0,>=3.9" files = [ - {file = "langsmith-0.3.8-py3-none-any.whl", hash = "sha256:fbb9dd97b0f090219447fca9362698d07abaeda1da85aa7cc6ec6517b36581b1"}, - {file = "langsmith-0.3.8.tar.gz", hash = "sha256:97f9bebe0b7cb0a4f278e6ff30ae7d5ededff3883b014442ec6d7d575b02a0f1"}, + {file = "langsmith-0.3.11-py3-none-any.whl", hash = "sha256:0cca22737ef07d3b038a437c141deda37e00add56022582680188b681bec095e"}, + {file = "langsmith-0.3.11.tar.gz", hash = "sha256:ddf29d24352e99de79c9618aaf95679214324e146c5d3d9475a7ddd2870018b1"}, ] [package.dependencies] httpx = ">=0.23.0,<1" orjson = {version = ">=3.9.14,<4.0.0", markers = "platform_python_implementation != \"PyPy\""} +packaging = ">=23.2" pydantic = [ {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, @@ -697,6 +707,58 @@ files = [ {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, ] +[[package]] +name = "msgspec" +version = "0.19.0" +description = "A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML." +optional = false +python-versions = ">=3.9" +files = [ + {file = "msgspec-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d8dd848ee7ca7c8153462557655570156c2be94e79acec3561cf379581343259"}, + {file = "msgspec-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0553bbc77662e5708fe66aa75e7bd3e4b0f209709c48b299afd791d711a93c36"}, + {file = "msgspec-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe2c4bf29bf4e89790b3117470dea2c20b59932772483082c468b990d45fb947"}, + {file = "msgspec-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e87ecfa9795ee5214861eab8326b0e75475c2e68a384002aa135ea2a27d909"}, + {file = "msgspec-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3c4ec642689da44618f68c90855a10edbc6ac3ff7c1d94395446c65a776e712a"}, + {file = "msgspec-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2719647625320b60e2d8af06b35f5b12d4f4d281db30a15a1df22adb2295f633"}, + {file = "msgspec-0.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:695b832d0091edd86eeb535cd39e45f3919f48d997685f7ac31acb15e0a2ed90"}, + {file = "msgspec-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa77046904db764b0462036bc63ef71f02b75b8f72e9c9dd4c447d6da1ed8f8e"}, + {file = "msgspec-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:047cfa8675eb3bad68722cfe95c60e7afabf84d1bd8938979dd2b92e9e4a9551"}, + {file = "msgspec-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e78f46ff39a427e10b4a61614a2777ad69559cc8d603a7c05681f5a595ea98f7"}, + {file = "msgspec-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c7adf191e4bd3be0e9231c3b6dc20cf1199ada2af523885efc2ed218eafd011"}, + {file = "msgspec-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f04cad4385e20be7c7176bb8ae3dca54a08e9756cfc97bcdb4f18560c3042063"}, + {file = "msgspec-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45c8fb410670b3b7eb884d44a75589377c341ec1392b778311acdbfa55187716"}, + {file = "msgspec-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:70eaef4934b87193a27d802534dc466778ad8d536e296ae2f9334e182ac27b6c"}, + {file = "msgspec-0.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f98bd8962ad549c27d63845b50af3f53ec468b6318400c9f1adfe8b092d7b62f"}, + {file = "msgspec-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:43bbb237feab761b815ed9df43b266114203f53596f9b6e6f00ebd79d178cdf2"}, + {file = "msgspec-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfc033c02c3e0aec52b71710d7f84cb3ca5eb407ab2ad23d75631153fdb1f12"}, + {file = "msgspec-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d911c442571605e17658ca2b416fd8579c5050ac9adc5e00c2cb3126c97f73bc"}, + {file = "msgspec-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:757b501fa57e24896cf40a831442b19a864f56d253679f34f260dcb002524a6c"}, + {file = "msgspec-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5f0f65f29b45e2816d8bded36e6b837a4bf5fb60ec4bc3c625fa2c6da4124537"}, + {file = "msgspec-0.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:067f0de1c33cfa0b6a8206562efdf6be5985b988b53dd244a8e06f993f27c8c0"}, + {file = "msgspec-0.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f12d30dd6266557aaaf0aa0f9580a9a8fbeadfa83699c487713e355ec5f0bd86"}, + {file = "msgspec-0.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82b2c42c1b9ebc89e822e7e13bbe9d17ede0c23c187469fdd9505afd5a481314"}, + {file = "msgspec-0.19.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19746b50be214a54239aab822964f2ac81e38b0055cca94808359d779338c10e"}, + {file = "msgspec-0.19.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ef4bdb0ec8e4ad62e5a1f95230c08efb1f64f32e6e8dd2ced685bcc73858b5"}, + {file = "msgspec-0.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac7f7c377c122b649f7545810c6cd1b47586e3aa3059126ce3516ac7ccc6a6a9"}, + {file = "msgspec-0.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5bc1472223a643f5ffb5bf46ccdede7f9795078194f14edd69e3aab7020d327"}, + {file = "msgspec-0.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:317050bc0f7739cb30d257ff09152ca309bf5a369854bbf1e57dffc310c1f20f"}, + {file = "msgspec-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15c1e86fff77184c20a2932cd9742bf33fe23125fa3fcf332df9ad2f7d483044"}, + {file = "msgspec-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3b5541b2b3294e5ffabe31a09d604e23a88533ace36ac288fa32a420aa38d229"}, + {file = "msgspec-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f5c043ace7962ef188746e83b99faaa9e3e699ab857ca3f367b309c8e2c6b12"}, + {file = "msgspec-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca06aa08e39bf57e39a258e1996474f84d0dd8130d486c00bec26d797b8c5446"}, + {file = "msgspec-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e695dad6897896e9384cf5e2687d9ae9feaef50e802f93602d35458e20d1fb19"}, + {file = "msgspec-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3be5c02e1fee57b54130316a08fe40cca53af92999a302a6054cd451700ea7db"}, + {file = "msgspec-0.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:0684573a821be3c749912acf5848cce78af4298345cb2d7a8b8948a0a5a27cfe"}, + {file = "msgspec-0.19.0.tar.gz", hash = "sha256:604037e7cd475345848116e89c553aa9a233259733ab51986ac924ab1b976f8e"}, +] + +[package.extras] +dev = ["attrs", "coverage", "eval-type-backport", "furo", "ipython", "msgpack", "mypy", "pre-commit", "pyright", "pytest", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "tomli", "tomli_w"] +doc = ["furo", "ipython", "sphinx", "sphinx-copybutton", "sphinx-design"] +test = ["attrs", "eval-type-backport", "msgpack", "pytest", "pyyaml", "tomli", "tomli_w"] +toml = ["tomli", "tomli_w"] +yaml = ["pyyaml"] + [[package]] name = "mypy" version = "1.15.0" @@ -1278,13 +1340,13 @@ examples = ["fastapi"] [[package]] name = "starlette" -version = "0.45.3" +version = "0.46.0" description = "The little ASGI library that shines." optional = true python-versions = ">=3.9" files = [ - {file = "starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d"}, - {file = "starlette-0.45.3.tar.gz", hash = "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f"}, + {file = "starlette-0.46.0-py3-none-any.whl", hash = "sha256:913f0798bd90ba90a9156383bcf1350a17d6259451d0d8ee27fc0cf2db609038"}, + {file = "starlette-0.46.0.tar.gz", hash = "sha256:b359e4567456b28d473d0193f34c0de0ed49710d75ef183a74a5ce0499324f50"}, ] [package.dependencies] @@ -1295,18 +1357,18 @@ full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart [[package]] name = "structlog" -version = "24.4.0" +version = "23.3.0" description = "Structured Logging for Python" optional = true python-versions = ">=3.8" files = [ - {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, - {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, + {file = "structlog-23.3.0-py3-none-any.whl", hash = "sha256:d6922a88ceabef5b13b9eda9c4043624924f60edbb00397f4d193bd754cde60a"}, + {file = "structlog-23.3.0.tar.gz", hash = "sha256:24b42b914ac6bc4a4e6f716e82ac70d7fb1e8c3b1035a765591953bfc37101a5"}, ] [package.extras] -dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +dev = ["structlog[tests,typing]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] @@ -1655,4 +1717,4 @@ inmem = ["langgraph-api", "python-dotenv"] [metadata] lock-version = "2.0" python-versions = "^3.9.0,<4.0" -content-hash = "48e374a559e6d8339c82b5271dea910f8ddfb6baf8436153ca54faefb8b2b220" +content-hash = "d0e2bdcb600ad031867413025fcc58bb162609209359d63ca99a77060cf8cbb4" diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index 125dcb861..1f7c38cb8 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-cli" -version = "0.1.73" +version = "0.1.76" description = "CLI for interacting with LangGraph API" authors = [] license = "MIT" @@ -14,7 +14,7 @@ langgraph = "langgraph_cli.cli:cli" [tool.poetry.dependencies] python = "^3.9.0,<4.0" click = "^8.1.7" -langgraph-api = { version = ">=0.0.26,<0.1.0", optional = true, python = ">=3.11,<4.0" } +langgraph-api = { version = ">=0.0.27,<0.1.0", optional = true, python = ">=3.11,<4.0" } python-dotenv = { version = ">=0.8.0", optional = true } [tool.poetry.group.dev.dependencies] @@ -25,6 +25,7 @@ pytest-asyncio = "^0.21.1" pytest-mock = "^3.11.1" pytest-watch = "^4.2.0" mypy = "^1.10.0" +msgspec = "^0.19.0" [tool.poetry.extras] inmem = ["langgraph-api", "python-dotenv"] diff --git a/libs/cli/schemas/schema.json b/libs/cli/schemas/schema.json new file mode 100644 index 000000000..72eeec475 --- /dev/null +++ b/libs/cli/schemas/schema.json @@ -0,0 +1,470 @@ +{ + "$ref": "#/$defs/Config", + "$defs": { + "Config": { + "title": "Config", + "description": "Top-level config for langgraph-cli or similar deployment tooling.", + "type": "object", + "required": [], + "oneOf": [ + { + "type": "object", + "properties": { + "python_version": { + "type": "string", + "description": "Optional. Python version in 'major.minor' format (e.g. '3.11').\nMust be at least 3.11 or greater for this deployment to function properly.\n", + "enum": [ + "3.11", + "3.12" + ] + }, + "pip_config_file": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + }, + "ui": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file.\n" + } + }, + "required": [ + "dependencies", + "graphs" + ] + }, + { + "type": "object", + "properties": { + "node_version": { + "anyOf": [ + { + "type": "string", + "enum": [ + "20" + ] + }, + { + "type": "null" + } + ], + "description": "Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node.\nMust be >= 20 if provided.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + }, + "ui": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file.\n" + } + }, + "required": [ + "node_version", + "graphs" + ] + } + ] + }, + "AuthConfig": { + "title": "AuthConfig", + "description": "Configuration for custom authentication logic and how it integrates into the OpenAPI spec.", + "type": "object", + "properties": { + "disable_studio_auth": { + "type": "boolean", + "description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If True, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n" + }, + "openapi": { + "$ref": "#/$defs/SecurityConfig", + "description": "Required. Detailed security configuration that merges into your deployment's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n" + }, + "path": { + "type": "string", + "description": "Required. Path to an instance of the Auth() class that implements custom authentication.\n" + } + }, + "required": [] + }, + "SecurityConfig": { + "title": "SecurityConfig", + "description": "Configuration for OpenAPI security definitions and requirements.\n\nUseful for specifying global or path-level authentication and authorization flows\n(e.g., OAuth2, API key headers, etc.).", + "type": "object", + "properties": { + "paths": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "description": "Optional. Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n" + }, + "security": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "Optional. Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])." + }, + "securitySchemes": { + "type": "object", + "additionalProperties": { + "type": "object" + }, + "description": "Required. Dict describing each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions." + } + }, + "required": [] + }, + "HttpConfig": { + "title": "HttpConfig", + "description": "Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.", + "type": "object", + "properties": { + "app": { + "type": "string", + "description": "Optional. Import path to a custom Starlette/FastAPI application to mount.\n" + }, + "cors": { + "anyOf": [ + { + "$ref": "#/$defs/CorsConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines CORS restrictions. If omitted, no special rules are set and\ncross-origin behavior depends on default server settings.\n" + }, + "disable_assistants": { + "type": "boolean", + "description": "Optional. If True, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n" + }, + "disable_meta": { + "type": "boolean", + "description": "Optional. If True, all meta endpoints (/ok, /info, /metrics, /docs) are disabled.\n\nDefault is False.\n" + }, + "disable_runs": { + "type": "boolean", + "description": "Optional. If True, /runs routes are removed.\n\nDefault is False.\n" + }, + "disable_store": { + "type": "boolean", + "description": "Optional. If True, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n" + }, + "disable_threads": { + "type": "boolean", + "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n" + } + }, + "required": [] + }, + "CorsConfig": { + "title": "CorsConfig", + "description": "Specifies Cross-Origin Resource Sharing (CORS) rules for your server.\n\nIf omitted, defaults are typically very restrictive (often no cross-origin requests).\nConfigure carefully if you want to allow usage from browsers hosted on other domains.", + "type": "object", + "properties": { + "allow_credentials": { + "type": "boolean", + "description": "Optional. If True, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n" + }, + "allow_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP headers that can be used in cross-origin requests (e.g. [\"Content-Type\", \"Authorization\"])." + }, + "allow_methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP methods permitted for cross-origin requests (e.g. [\"GET\", \"POST\"]).\n\nDefault might be [\"GET\", \"POST\", \"OPTIONS\"] depending on your server framework.\n" + }, + "allow_origin_regex": { + "type": "string", + "description": "Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains.\n" + }, + "allow_origins": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of allowed origins (e.g., \"https://example.com\").\n\nDefault is often an empty list (no external origins).\nUse \"*\" only if you trust all origins, as that bypasses most restrictions.\n" + }, + "expose_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts." + }, + "max_age": { + "type": "integer", + "description": "Optional. How many seconds the browser may cache preflight responses.\n\nDefault might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations.\n" + } + }, + "required": [] + }, + "StoreConfig": { + "title": "StoreConfig", + "description": "Configuration for the built-in long-term memory store.\n\nThis store can optionally perform semantic search. If you omit `index`,\nthe store will just handle traditional (non-embedded) data without vector lookups.", + "type": "object", + "properties": { + "index": { + "anyOf": [ + { + "$ref": "#/$defs/IndexConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the vector-based semantic search configuration.\n\n- Generate embeddings according to `index.embed`\n- Enforce the embedding dimension given by `index.dims`\n- Embed only specified JSON fields (if any) from `index.fields`\n\nIf omitted, no vector index is initialized.\n" + }, + "ttl": { + "anyOf": [ + { + "$ref": "#/$defs/TTLConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the TTL (time-to-live) behavior configuration.\n\nIf provided, the store will apply TTL settings according to the configuration.\nIf omitted, no TTL behavior is configured.\n" + } + }, + "required": [] + }, + "IndexConfig": { + "title": "IndexConfig", + "description": "Configuration for indexing documents for semantic search in the store.\n\nThis governs how text is converted into embeddings and stored for vector-based lookups.", + "type": "object", + "properties": { + "dims": { + "type": "integer", + "description": "Required. Dimensionality of the embedding vectors you will store.\n\nMust match the output dimension of your selected embedding model or custom embed function.\nIf mismatched, you will likely encounter shape/size errors when inserting or querying vectors.\n\n" + }, + "embed": { + "type": "string", + "description": "Required. Identifier or reference to the embedding model or a custom embedding function.\n\n- \"my_custom_embed\" if it's a known alias in your system\n" + }, + "fields": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. List of JSON fields to extract before generating embeddings.\n\nDefaults to [\"$\"], which means the entire JSON object is embedded as one piece of text.\nIf you provide multiple fields (e.g. [\"title\", \"content\"]), each is extracted and embedded separately,\noften saving token usage if you only care about certain parts of the data.\n" + } + }, + "required": [] + }, + "TTLConfig": { + "title": "TTLConfig", + "description": "Configuration for TTL (time-to-live) behavior in the store.", + "type": "object", + "properties": { + "default_ttl": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "refresh_on_read": { + "type": "boolean" + } + }, + "required": [] + } + }, + "title": "LangGraph CLI Configuration", + "description": "Configuration schema for langgraph-cli", + "version": "v0" +} \ No newline at end of file diff --git a/libs/cli/schemas/schema.v0.json b/libs/cli/schemas/schema.v0.json new file mode 100644 index 000000000..72eeec475 --- /dev/null +++ b/libs/cli/schemas/schema.v0.json @@ -0,0 +1,470 @@ +{ + "$ref": "#/$defs/Config", + "$defs": { + "Config": { + "title": "Config", + "description": "Top-level config for langgraph-cli or similar deployment tooling.", + "type": "object", + "required": [], + "oneOf": [ + { + "type": "object", + "properties": { + "python_version": { + "type": "string", + "description": "Optional. Python version in 'major.minor' format (e.g. '3.11').\nMust be at least 3.11 or greater for this deployment to function properly.\n", + "enum": [ + "3.11", + "3.12" + ] + }, + "pip_config_file": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + }, + "ui": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file.\n" + } + }, + "required": [ + "dependencies", + "graphs" + ] + }, + { + "type": "object", + "properties": { + "node_version": { + "anyOf": [ + { + "type": "string", + "enum": [ + "20" + ] + }, + { + "type": "null" + } + ], + "description": "Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node.\nMust be >= 20 if provided.\n" + }, + "auth": { + "anyOf": [ + { + "$ref": "#/$defs/AuthConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Custom authentication config, including the path to your Python auth logic and\nthe OpenAPI security definitions it uses.\n" + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Python dependencies to install, either from PyPI or local paths.\n" + }, + "dockerfile_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. Additional Docker instructions that will be appended to your base Dockerfile.\n\nUseful for installing OS packages, setting environment variables, etc." + }, + "env": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string" + } + ], + "description": "Optional. Environment variables to set for your deployment.\n\n- If given as a dict, keys are variable names and values are their values.\n- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.\n\nenv=\".env\n" + }, + "graphs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Optional. Named definitions of graphs, each pointing to a Python object.\n\n\nGraphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context\nmanagers that accept a single configuration argument (of type RunnableConfig) and return a pregel object\n(instance of Stategraph, etc.).\n" + }, + "http": { + "anyOf": [ + { + "$ref": "#/$defs/HttpConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed\nand how cross-origin requests are handled.\n" + }, + "store": { + "anyOf": [ + { + "$ref": "#/$defs/StoreConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Configuration for the built-in long-term memory store, including semantic search indexing.\n\nIf omitted, no vector index is set up (the object store will still be present, however).\n" + }, + "ui": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file.\n" + } + }, + "required": [ + "node_version", + "graphs" + ] + } + ] + }, + "AuthConfig": { + "title": "AuthConfig", + "description": "Configuration for custom authentication logic and how it integrates into the OpenAPI spec.", + "type": "object", + "properties": { + "disable_studio_auth": { + "type": "boolean", + "description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If True, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n" + }, + "openapi": { + "$ref": "#/$defs/SecurityConfig", + "description": "Required. Detailed security configuration that merges into your deployment's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n" + }, + "path": { + "type": "string", + "description": "Required. Path to an instance of the Auth() class that implements custom authentication.\n" + } + }, + "required": [] + }, + "SecurityConfig": { + "title": "SecurityConfig", + "description": "Configuration for OpenAPI security definitions and requirements.\n\nUseful for specifying global or path-level authentication and authorization flows\n(e.g., OAuth2, API key headers, etc.).", + "type": "object", + "properties": { + "paths": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "description": "Optional. Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n" + }, + "security": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "Optional. Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])." + }, + "securitySchemes": { + "type": "object", + "additionalProperties": { + "type": "object" + }, + "description": "Required. Dict describing each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions." + } + }, + "required": [] + }, + "HttpConfig": { + "title": "HttpConfig", + "description": "Configuration for the built-in HTTP server that powers your deployment's routes and endpoints.", + "type": "object", + "properties": { + "app": { + "type": "string", + "description": "Optional. Import path to a custom Starlette/FastAPI application to mount.\n" + }, + "cors": { + "anyOf": [ + { + "$ref": "#/$defs/CorsConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines CORS restrictions. If omitted, no special rules are set and\ncross-origin behavior depends on default server settings.\n" + }, + "disable_assistants": { + "type": "boolean", + "description": "Optional. If True, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n" + }, + "disable_meta": { + "type": "boolean", + "description": "Optional. If True, all meta endpoints (/ok, /info, /metrics, /docs) are disabled.\n\nDefault is False.\n" + }, + "disable_runs": { + "type": "boolean", + "description": "Optional. If True, /runs routes are removed.\n\nDefault is False.\n" + }, + "disable_store": { + "type": "boolean", + "description": "Optional. If True, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n" + }, + "disable_threads": { + "type": "boolean", + "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n" + } + }, + "required": [] + }, + "CorsConfig": { + "title": "CorsConfig", + "description": "Specifies Cross-Origin Resource Sharing (CORS) rules for your server.\n\nIf omitted, defaults are typically very restrictive (often no cross-origin requests).\nConfigure carefully if you want to allow usage from browsers hosted on other domains.", + "type": "object", + "properties": { + "allow_credentials": { + "type": "boolean", + "description": "Optional. If True, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n" + }, + "allow_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP headers that can be used in cross-origin requests (e.g. [\"Content-Type\", \"Authorization\"])." + }, + "allow_methods": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. HTTP methods permitted for cross-origin requests (e.g. [\"GET\", \"POST\"]).\n\nDefault might be [\"GET\", \"POST\", \"OPTIONS\"] depending on your server framework.\n" + }, + "allow_origin_regex": { + "type": "string", + "description": "Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains.\n" + }, + "allow_origins": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of allowed origins (e.g., \"https://example.com\").\n\nDefault is often an empty list (no external origins).\nUse \"*\" only if you trust all origins, as that bypasses most restrictions.\n" + }, + "expose_headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts." + }, + "max_age": { + "type": "integer", + "description": "Optional. How many seconds the browser may cache preflight responses.\n\nDefault might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations.\n" + } + }, + "required": [] + }, + "StoreConfig": { + "title": "StoreConfig", + "description": "Configuration for the built-in long-term memory store.\n\nThis store can optionally perform semantic search. If you omit `index`,\nthe store will just handle traditional (non-embedded) data without vector lookups.", + "type": "object", + "properties": { + "index": { + "anyOf": [ + { + "$ref": "#/$defs/IndexConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the vector-based semantic search configuration.\n\n- Generate embeddings according to `index.embed`\n- Enforce the embedding dimension given by `index.dims`\n- Embed only specified JSON fields (if any) from `index.fields`\n\nIf omitted, no vector index is initialized.\n" + }, + "ttl": { + "anyOf": [ + { + "$ref": "#/$defs/TTLConfig" + }, + { + "type": "null" + } + ], + "description": "Optional. Defines the TTL (time-to-live) behavior configuration.\n\nIf provided, the store will apply TTL settings according to the configuration.\nIf omitted, no TTL behavior is configured.\n" + } + }, + "required": [] + }, + "IndexConfig": { + "title": "IndexConfig", + "description": "Configuration for indexing documents for semantic search in the store.\n\nThis governs how text is converted into embeddings and stored for vector-based lookups.", + "type": "object", + "properties": { + "dims": { + "type": "integer", + "description": "Required. Dimensionality of the embedding vectors you will store.\n\nMust match the output dimension of your selected embedding model or custom embed function.\nIf mismatched, you will likely encounter shape/size errors when inserting or querying vectors.\n\n" + }, + "embed": { + "type": "string", + "description": "Required. Identifier or reference to the embedding model or a custom embedding function.\n\n- \"my_custom_embed\" if it's a known alias in your system\n" + }, + "fields": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Optional. List of JSON fields to extract before generating embeddings.\n\nDefaults to [\"$\"], which means the entire JSON object is embedded as one piece of text.\nIf you provide multiple fields (e.g. [\"title\", \"content\"]), each is extracted and embedded separately,\noften saving token usage if you only care about certain parts of the data.\n" + } + }, + "required": [] + }, + "TTLConfig": { + "title": "TTLConfig", + "description": "Configuration for TTL (time-to-live) behavior in the store.", + "type": "object", + "properties": { + "default_ttl": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "refresh_on_read": { + "type": "boolean" + } + }, + "required": [] + } + }, + "title": "LangGraph CLI Configuration", + "description": "Configuration schema for langgraph-cli", + "version": "v0" +} \ No newline at end of file diff --git a/libs/cli/tests/unit_tests/test_config.py b/libs/cli/tests/unit_tests/test_config.py index 95e20033e..397fca031 100644 --- a/libs/cli/tests/unit_tests/test_config.py +++ b/libs/cli/tests/unit_tests/test_config.py @@ -33,6 +33,7 @@ def test_validate_config(): "store": None, "auth": None, "http": None, + "ui": None, **expected_config, } actual_config = validate_config(expected_config) @@ -52,6 +53,7 @@ def test_validate_config(): "store": None, "auth": None, "http": None, + "ui": None, } actual_config = validate_config(expected_config) assert actual_config == expected_config @@ -467,6 +469,7 @@ def test_config_to_docker_nodejs(): "node_version": "20", "graphs": graphs, "dockerfile_lines": ["ARG meow", "ARG foo"], + "ui": {"agent": "./graphs/agent.ui.jsx"}, } ), "langchain/langgraphjs-api", @@ -477,6 +480,7 @@ ARG foo ADD . /deps/unit_tests RUN cd /deps/unit_tests && npm i ENV LANGSERVE_GRAPHS='{"agent": "./graphs/agent.js:graph"}' +ENV LANGGRAPH_UI='{"agent": "./graphs/agent.ui.jsx"}' WORKDIR /deps/unit_tests RUN (test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not found, skipping") || tsx /api/langgraph_api/js/build.mts""" diff --git a/libs/langgraph/README.md b/libs/langgraph/README.md index 01c1330cf..f656b962d 100644 --- a/libs/langgraph/README.md +++ b/libs/langgraph/README.md @@ -1,339 +1,81 @@ # 🦜🕸️LangGraph -![Version](https://img.shields.io/pypi/v/langgraph) +[![Version](https://img.shields.io/pypi/v/langgraph.svg)](https://pypi.org/project/langgraph/) [![Downloads](https://static.pepy.tech/badge/langgraph/month)](https://pepy.tech/project/langgraph) [![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/) -⚡ Building language agents as graphs ⚡ - > [!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/). -## Overview +LangGraph — used by Replit, Uber, LinkedIn, GitLab and more — is a low-level orchestration framework for building controllable agents. While langchain provides integrations and composable components to streamline LLM application development, the LangGraph library enables agent orchestration — offering customizable architectures, long-term memory, and human-in-the-loop to reliably handle complex tasks. -[LangGraph](https://langchain-ai.github.io/langgraph/) is a library for building -stateful, multi-actor applications with LLMs, used to create agent and multi-agent -workflows. Check out an introductory tutorial [here](https://langchain-ai.github.io/langgraph/tutorials/introduction/). - - -LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain. - -### Why use LangGraph? - -LangGraph powers [production-grade agents](https://www.langchain.com/built-with-langgraph), trusted by Linkedin, Uber, Klarna, GitLab, and many more. LangGraph provides fine-grained control over both the flow and state of your agent applications. It implements a central [persistence layer](https://langchain-ai.github.io/langgraph/concepts/persistence/), enabling features that are common to most agent architectures: - -- **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**: Because state is checkpointed, execution can be interrupted -and resumed, allowing for decisions, validation, and corrections at key stages via -human input. - -Standardizing these components allows individuals and teams to focus on the behavior -of their agent, instead of its supporting infrastructure. - -Through [LangGraph Platform](#langgraph-platform), LangGraph also provides tooling for -the development, deployment, debugging, and monitoring of your applications. - -LangGraph integrates seamlessly with -[LangChain](https://python.langchain.com/docs/introduction/) and -[LangSmith](https://docs.smith.langchain.com/) (but does not require them). - -To learn more about LangGraph, check out our first LangChain Academy -course, *Introduction to LangGraph*, available for free -[here](https://academy.langchain.com/courses/intro-to-langgraph). - -### LangGraph Platform - -[LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform) is infrastructure for deploying LangGraph agents. It is a commercial solution for deploying agentic applications to production, built on the open-source LangGraph framework. The LangGraph Platform consists of several components that work together to support the development, deployment, debugging, and monitoring of LangGraph applications: [LangGraph Server](https://langchain-ai.github.io/langgraph/concepts/langgraph_server) (APIs), [LangGraph SDKs](https://langchain-ai.github.io/langgraph/concepts/sdk) (clients for the APIs), [LangGraph CLI](https://langchain-ai.github.io/langgraph/concepts/langgraph_cli) (command line tool for building the server), and [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio) (UI/debugger). - -See deployment options [here](https://langchain-ai.github.io/langgraph/concepts/deployment_options/) -(includes a free tier). - -Here are some common issues that arise in complex deployments, which LangGraph Platform addresses: - -- **Streaming support**: LangGraph Server provides [multiple streaming modes](https://langchain-ai.github.io/langgraph/concepts/streaming) optimized for various application needs -- **Background runs**: Runs agents asynchronously in the background -- **Support for long running agents**: Infrastructure that can handle long running processes -- **[Double texting](https://langchain-ai.github.io/langgraph/concepts/double_texting)**: Handle the case where you get two messages from the user before the agent can respond -- **Handle burstiness**: Task queue for ensuring requests are handled consistently without loss, even under heavy loads - -## Installation - -```shell +```bash pip install -U langgraph ``` -## Example - -Let's build a tool-calling [ReAct-style](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-implementation) agent that uses a search tool! - -```shell -pip install langchain-anthropic -``` - -```shell -export ANTHROPIC_API_KEY=sk-... -``` - -Optionally, we can set up [LangSmith](https://docs.smith.langchain.com/) for best-in-class observability. - -```shell -export LANGSMITH_TRACING=true -export LANGSMITH_API_KEY=lsv2_sk_... -``` - -The simplest way to create a tool-calling agent in LangGraph is to use `create_react_agent`: - -
- High-level implementation +To learn more about how to use LangGraph, check out [the docs](https://langchain-ai.github.io/langgraph/). We show a simple example below of how to create a ReAct agent. ```python +from langchain_anthropic import ChatAnthropic from langgraph.prebuilt import create_react_agent -from langgraph.checkpoint.memory import MemorySaver -from langchain_anthropic import ChatAnthropic -from langchain_core.tools import tool -# Define the tools for the agent to use -@tool def search(query: str): """Call to surf the web.""" - # This is a placeholder, but don't tell the LLM that... if "sf" in query.lower() or "san francisco" in query.lower(): return "It's 60 degrees and foggy." return "It's 90 degrees and sunny." - +model = ChatAnthropic(model=“claude-3-7-sonnet-latest”) tools = [search] -model = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0) - -# Initialize memory to persist state between graph runs -checkpointer = MemorySaver() - -app = create_react_agent(model, tools, checkpointer=checkpointer) - -# Use the agent -final_state = app.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]}, - config={"configurable": {"thread_id": 42}} +agent = create_react_agent(model, tools) +agent.invoke( + {"messages": [{"role": "user", "content": "what is the weather in sf"}]} ) -final_state["messages"][-1].content -``` -``` -"Based on the search results, I can tell you that the current weather in San Francisco is:\n\nTemperature: 60 degrees Fahrenheit\nConditions: Foggy\n\nSan Francisco is known for its microclimates and frequent fog, especially during the summer months. The temperature of 60°F (about 15.5°C) is quite typical for the city, which tends to have mild temperatures year-round. The fog, often referred to as "Karl the Fog" by locals, is a characteristic feature of San Francisco\'s weather, particularly in the mornings and evenings.\n\nIs there anything else you\'d like to know about the weather in San Francisco or any other location?" ``` -Now when we pass the same "thread_id", the conversation context is retained via the saved state (i.e. stored list of messages) +## Why use LangGraph? -```python -final_state = app.invoke( - {"messages": [{"role": "user", "content": "what about ny"}]}, - config={"configurable": {"thread_id": 42}} -) -final_state["messages"][-1].content -``` +LangGraph is built for developers who want to build powerful, adaptable AI agents. Developers choose LangGraph for: -``` -"Based on the search results, I can tell you that the current weather in New York City is:\n\nTemperature: 90 degrees Fahrenheit (approximately 32.2 degrees Celsius)\nConditions: Sunny\n\nThis weather is quite different from what we just saw in San Francisco. New York is experiencing much warmer temperatures right now. Here are a few points to note:\n\n1. The temperature of 90°F is quite hot, typical of summer weather in New York City.\n2. The sunny conditions suggest clear skies, which is great for outdoor activities but also means it might feel even hotter due to direct sunlight.\n3. This kind of weather in New York often comes with high humidity, which can make it feel even warmer than the actual temperature suggests.\n\nIt's interesting to see the stark contrast between San Francisco's mild, foggy weather and New York's hot, sunny conditions. This difference illustrates how varied weather can be across different parts of the United States, even on the same day.\n\nIs there anything else you'd like to know about the weather in New York or any other location?" -``` -
+- **Reliability and controllability.** Steer agent actions with moderation checks and human-in-the-loop approvals. LangGraph persists context for long-running workflows, keeping your agents on course. +- **Low-level and extensible.** Build custom agents with fully descriptive, low-level primitives – free from rigid abstractions that limit customization. Design scalable multi-agent systems, with each agent serving a specific role tailored to your use case. +- **First-class streaming support.** With token-by-token streaming and streaming of intermediate steps, LangGraph gives users clear visibility into agent reasoning and actions as they unfold in real time. -> [!TIP] -> LangGraph is a **low-level** framework that allows you to implement any custom agent -architectures. Click on the low-level implementation below to see how to implement a -tool-calling agent from scratch. +LangGraph is trusted in production and powering agents for companies like: -
-Low-level implementation +- [Klarna](https://blog.langchain.dev/customers-klarna/): Customer support bot for 85 million active users +- [Elastic](https://www.elastic.co/blog/elastic-security-generative-ai-features): Security AI assistant for threat detection +- [Uber](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/): Automated unit test generation +- [Replit](https://www.langchain.com/breakoutagents/replit): Code generation +- And many more ([see list here](https://www.langchain.com/built-with-langgraph)) -```python -from typing import Literal +## LangGraph’s ecosystem -from langchain_anthropic import ChatAnthropic -from langchain_core.tools import tool -from langgraph.checkpoint.memory import MemorySaver -from langgraph.graph import END, START, StateGraph, MessagesState -from langgraph.prebuilt import ToolNode +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/). -# Define the tools for the agent to use -@tool -def search(query: str): - """Call to surf the web.""" - # This is a placeholder, but don't tell the LLM that... - if "sf" in query.lower() or "san francisco" in query.lower(): - return "It's 60 degrees and foggy." - return "It's 90 degrees and sunny." +## Pairing with LangGraph Platform +While LangGraph is our open-source agent orchestration framework, enterprises that need scalable agent deployment can benefit from [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/). -tools = [search] +LangGraph Platform can help engineering teams: -tool_node = ToolNode(tools) +- **Accelerate agent development**: Quickly create agent UXs with configurable templates and [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/) for visualizing and debugging agent interactions. +- **Deploy seamlessly**: We handle the complexity of deploying your agent. LangGraph Platform includes robust APIs for memory, threads, and cron jobs plus auto-scaling task queues & servers. +- **Centralize agent management & reusability**: Discover, reuse, and manage agents across the organization. Business users can also modify agents without coding. -model = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0).bind_tools(tools) +## Additional resources -# Define the function that determines whether to continue or not -def should_continue(state: MessagesState) -> Literal["tools", END]: - messages = state['messages'] - last_message = messages[-1] - # If the LLM makes a tool call, then we route to the "tools" node - if last_message.tool_calls: - return "tools" - # Otherwise, we stop (reply to the user) - return END +- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course. +- [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Simple walkthroughs with guided examples on getting started with LangGraph. +- [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted. +- [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.). +- [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components. +- [Built with LangGraph](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. +## Acknowledgements -# Define the function that calls the model -def call_model(state: MessagesState): - messages = state['messages'] - response = model.invoke(messages) - # We return a list, because this will get added to the existing list - return {"messages": [response]} - - -# Define a new graph -workflow = StateGraph(MessagesState) - -# Define the two nodes we will cycle between -workflow.add_node("agent", call_model) -workflow.add_node("tools", tool_node) - -# Set the entrypoint as `agent` -# This means that this node is the first one called -workflow.add_edge(START, "agent") - -# We now add a conditional edge -workflow.add_conditional_edges( - # First, we define the start node. We use `agent`. - # This means these are the edges taken after the `agent` node is called. - "agent", - # Next, we pass in the function that will determine which node is called next. - should_continue, -) - -# We now add a normal edge from `tools` to `agent`. -# This means that after `tools` is called, `agent` node is called next. -workflow.add_edge("tools", 'agent') - -# Initialize memory to persist state between graph runs -checkpointer = MemorySaver() - -# Finally, we compile it! -# This compiles it into a LangChain Runnable, -# meaning you can use it as you would any other runnable. -# Note that we're (optionally) passing the memory when compiling the graph -app = workflow.compile(checkpointer=checkpointer) - -# Use the agent -final_state = app.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]}, - config={"configurable": {"thread_id": 42}} -) -final_state["messages"][-1].content -``` - -Step-by-step Breakdown: - -
-Initialize the model and tools. -
    -
  • - We use ChatAnthropic as our LLM. NOTE: we need to make sure the model knows that it has these tools available to call. We can do this by converting the LangChain tools into the format for OpenAI tool calling using the .bind_tools() method. -
  • -
  • - We define the tools we want to use - a search tool in our case. It is really easy to create your own tools - see documentation here on how to do that here. -
  • -
-
- -
-Initialize graph with state. - -
    -
  • We initialize graph (StateGraph) by passing state schema (in our case MessagesState)
  • -
  • MessagesState is a prebuilt state schema that has one attribute -- a list of LangChain Message objects, as well as logic for merging the updates from each node into the state.
  • -
-
- -
-Define graph nodes. - -There are two main nodes we need: - -
    -
  • The agent node: responsible for deciding what (if any) actions to take.
  • -
  • The tools node that invokes tools: if the agent decides to take an action, this node will then execute that action.
  • -
-
- -
-Define entry point and graph edges. - -First, we need to set the entry point for graph execution - agent node. - -Then we define one normal and one conditional edge. Conditional edge means that the destination depends on the contents of the graph's state (MessagesState). In our case, the destination is not known until the agent (LLM) decides. - -
    -
  • Conditional edge: after the agent is called, we should either: -
      -
    • a. Run tools if the agent said to take an action, OR
    • -
    • b. Finish (respond to the user) if the agent did not ask to run tools
    • -
    -
  • -
  • Normal edge: after the tools are invoked, the graph should always return to the agent to decide what to do next
  • -
-
- -
-Compile the graph. - -
    -
  • - When we compile the graph, we turn it into a LangChain - Runnable, - which automatically enables calling .invoke(), .stream() and .batch() - with your inputs -
  • -
  • - We can also optionally pass checkpointer object for persisting state between graph runs, and enabling memory, - human-in-the-loop workflows, time travel and more. In our case we use MemorySaver - - a simple in-memory checkpointer -
  • -
-
- -
-Execute the graph. - -
    -
  1. LangGraph adds the input message to the internal state, then passes the state to the entrypoint node, "agent".
  2. -
  3. The "agent" node executes, invoking the chat model.
  4. -
  5. The chat model returns an AIMessage. LangGraph adds this to the state.
  6. -
  7. Graph cycles the following steps until there are no more tool_calls on AIMessage: -
      -
    • If AIMessage has tool_calls, "tools" node executes
    • -
    • The "agent" node executes again and returns AIMessage
    • -
    -
  8. -
  9. Execution progresses to the special END value and outputs the final state. And as a result, we get a list of all our chat messages as output.
  10. -
-
- -
- -## Documentation - -* [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Learn to build with LangGraph through guided examples. -* [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Accomplish specific things within LangGraph, from streaming, to adding memory & persistence, to common design patterns (branching, subgraphs, etc.), these are the place to go if you want to copy and run a specific code snippet. -* [Conceptual Guides](https://langchain-ai.github.io/langgraph/concepts/high_level/): In-depth explanations of the key concepts and principles behind LangGraph, such as nodes, edges, state and more. -* [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Review important classes and methods, simple examples of how to use the graph and checkpointing APIs, higher-level prebuilt components and more. -* [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform): LangGraph Platform is a commercial solution for deploying agentic applications in production, built on the open-source LangGraph framework. - -## Resources - -* [Built with LangGraph](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. - -## Contributing - -For more information on how to contribute, see [here](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md). +LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain. \ No newline at end of file diff --git a/libs/langgraph/langgraph/channels/py.typed b/libs/langgraph/langgraph/channels/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/func/__init__.py b/libs/langgraph/langgraph/func/__init__.py index a3d012e55..787254687 100644 --- a/libs/langgraph/langgraph/func/__init__.py +++ b/libs/langgraph/langgraph/func/__init__.py @@ -36,23 +36,31 @@ from langgraph.types import _DC_KWARGS, RetryPolicy, StreamMode @overload def task( - *, name: Optional[str] = None, retry: Optional[RetryPolicy] = None -) -> Callable[[Callable[P, T]], Callable[P, SyncAsyncFuture[T]]]: ... + *, + name: Optional[str] = None, + retry: Optional[RetryPolicy] = None, +) -> Callable[ + [Union[Callable[P, Awaitable[T]], Callable[P, T]]], + Callable[P, SyncAsyncFuture[T]], +]: ... @overload def task( - __func_or_none__: Callable[P, T], + __func_or_none__: Union[Callable[P, Awaitable[T]], Callable[P, T]], ) -> Callable[P, SyncAsyncFuture[T]]: ... def task( - __func_or_none__: Optional[Union[Callable[P, T], Callable[P, Awaitable[T]]]] = None, + __func_or_none__: Optional[Union[Callable[P, Awaitable[T]], Callable[P, T]]] = None, *, name: Optional[str] = None, retry: Optional[RetryPolicy] = None, ) -> Union[ - Callable[[Callable[P, T]], Callable[P, SyncAsyncFuture[T]]], + Callable[ + [Union[Callable[P, Awaitable[T]], Callable[P, T]]], + Callable[P, SyncAsyncFuture[T]], + ], Callable[P, SyncAsyncFuture[T]], ]: """Define a LangGraph task using the `task` decorator. @@ -345,7 +353,7 @@ class entrypoint: value: R """Value to return. A value will always be returned even if it is None.""" save: S - """The value for the state for the next checkpoint. + """The value for the state for the next checkpoint. A value will always be saved even if it is None. """ diff --git a/libs/langgraph/langgraph/func/py.typed b/libs/langgraph/langgraph/func/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/graph/branch.py b/libs/langgraph/langgraph/graph/branch.py new file mode 100644 index 000000000..8e90d9097 --- /dev/null +++ b/libs/langgraph/langgraph/graph/branch.py @@ -0,0 +1,215 @@ +import asyncio +from inspect import ( + isfunction, + ismethod, + signature, +) +from types import FunctionType +from typing import ( + Any, + Awaitable, + Callable, + Hashable, + Literal, + NamedTuple, + Optional, + Sequence, + Type, + Union, + cast, + get_args, + get_origin, + get_type_hints, +) + +from langchain_core.runnables import ( + Runnable, + RunnableConfig, + RunnableLambda, +) + +from langgraph.constants import END, START +from langgraph.errors import InvalidUpdateError +from langgraph.pregel.write import ChannelWrite +from langgraph.types import Send +from langgraph.utils.runnable import ( + RunnableCallable, +) + + +def _get_branch_path_input_schema( + path: Union[ + Callable[..., Union[Hashable, list[Hashable]]], + Callable[..., Awaitable[Union[Hashable, list[Hashable]]]], + Runnable[Any, Union[Hashable, list[Hashable]]], + ], +) -> Optional[Type[Any]]: + input = None + # detect input schema annotation in the branch callable + try: + callable_: Optional[ + Union[ + Callable[..., Union[Hashable, list[Hashable]]], + Callable[..., Awaitable[Union[Hashable, list[Hashable]]]], + ] + ] = None + if isinstance(path, (RunnableCallable, RunnableLambda)): + if isfunction(path.func) or ismethod(path.func): + callable_ = path.func + elif (callable_method := getattr(path.func, "__call__", None)) and ismethod( + callable_method + ): + callable_ = callable_method + elif isfunction(path.afunc) or ismethod(path.afunc): + callable_ = path.afunc + elif ( + callable_method := getattr(path.afunc, "__call__", None) + ) and ismethod(callable_method): + callable_ = callable_method + elif callable(path): + callable_ = path + + if callable_ is not None and (hints := get_type_hints(callable_)): + first_parameter_name = next( + iter(signature(cast(FunctionType, callable_)).parameters.keys()) + ) + if input_hint := hints.get(first_parameter_name): + if isinstance(input_hint, type) and get_type_hints(input_hint): + input = input_hint + except (TypeError, StopIteration): + pass + + return input + + +class Branch(NamedTuple): + path: Runnable[Any, Union[Hashable, list[Hashable]]] + ends: Optional[dict[Hashable, str]] + then: Optional[str] = None + input_schema: Optional[Type[Any]] = None + + @classmethod + def from_path( + cls, + path: Runnable[Any, Union[Hashable, list[Hashable]]], + path_map: Optional[Union[dict[Hashable, str], list[str]]], + then: Optional[str] = None, + infer_schema: bool = False, + ) -> "Branch": + # coerce path_map to a dictionary + path_map_: Optional[dict[Hashable, str]] = None + try: + if isinstance(path_map, dict): + path_map_ = path_map.copy() + elif isinstance(path_map, list): + path_map_ = {name: name for name in path_map} + else: + # find func + func: Optional[Callable] = None + if isinstance(path, (RunnableCallable, RunnableLambda)): + func = path.func or path.afunc + if func is not None: + # find callable method + if (cal := getattr(path, "__call__", None)) and ismethod(cal): + func = cal + # get the return type + if rtn_type := get_type_hints(func).get("return"): + if get_origin(rtn_type) is Literal: + path_map_ = {name: name for name in get_args(rtn_type)} + except Exception: + pass + # infer input schema + input_schema = _get_branch_path_input_schema(path) if infer_schema else None + # create branch + return cls(path=path, ends=path_map_, then=then, input_schema=input_schema) + + def run( + self, + writer: Callable[ + [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] + ], + reader: Optional[Callable[[RunnableConfig], Any]] = None, + ) -> RunnableCallable: + return ChannelWrite.register_writer( + RunnableCallable( + func=self._route, + afunc=self._aroute, + writer=writer, + reader=reader, + name=None, + trace=False, + ) + ) + + def _route( + self, + input: Any, + config: RunnableConfig, + *, + reader: Optional[Callable[[RunnableConfig], Any]], + writer: Callable[ + [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] + ], + ) -> Runnable: + if reader: + value = reader(config) + # passthrough additional keys from node to branch + # only doable when using dict states + if ( + isinstance(value, dict) + and isinstance(input, dict) + and self.input_schema is None + ): + value = {**input, **value} + else: + value = input + result = self.path.invoke(value, config) + return self._finish(writer, input, result, config) + + async def _aroute( + self, + input: Any, + config: RunnableConfig, + *, + reader: Optional[Callable[[RunnableConfig], Any]], + writer: Callable[ + [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] + ], + ) -> Runnable: + if reader: + value = await asyncio.to_thread(reader, config) + # passthrough additional keys from node to branch + # only doable when using dict states + if ( + isinstance(value, dict) + and isinstance(input, dict) + and self.input_schema is None + ): + value = {**input, **value} + else: + value = input + result = await self.path.ainvoke(value, config) + return self._finish(writer, input, result, config) + + def _finish( + self, + writer: Callable[ + [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] + ], + input: Any, + result: Any, + config: RunnableConfig, + ) -> Union[Runnable, Any]: + if not isinstance(result, (list, tuple)): + result = [result] + if self.ends: + destinations: Sequence[Union[Send, str]] = [ + r if isinstance(r, Send) else self.ends[r] for r in result + ] + else: + destinations = cast(Sequence[Union[Send, str]], result) + if any(dest is None or dest == START for dest in destinations): + raise ValueError("Branch did not return a valid destination") + if any(p.node == END for p in destinations if isinstance(p, Send)): + raise InvalidUpdateError("Cannot send a packet to the END node") + return writer(destinations, config) or input diff --git a/libs/langgraph/langgraph/graph/graph.py b/libs/langgraph/langgraph/graph/graph.py index 4bda590c3..137eb0862 100644 --- a/libs/langgraph/langgraph/graph/graph.py +++ b/libs/langgraph/langgraph/graph/graph.py @@ -1,4 +1,3 @@ -import asyncio import logging from collections import defaultdict from typing import ( @@ -6,15 +5,11 @@ from typing import ( Awaitable, Callable, Hashable, - Literal, NamedTuple, Optional, Sequence, Union, cast, - get_args, - get_origin, - get_type_hints, overload, ) @@ -34,12 +29,12 @@ from langgraph.constants import ( TAG_HIDDEN, Send, ) -from langgraph.errors import InvalidUpdateError +from langgraph.graph.branch import Branch from langgraph.pregel import Channel, Pregel from langgraph.pregel.read import PregelNode from langgraph.pregel.write import ChannelWrite, ChannelWriteEntry from langgraph.types import All, Checkpointer -from langgraph.utils.runnable import RunnableCallable, RunnableLike, coerce_to_runnable +from langgraph.utils.runnable import RunnableLike, coerce_to_runnable logger = logging.getLogger(__name__) @@ -50,95 +45,6 @@ class NodeSpec(NamedTuple): ends: Optional[Union[tuple[str, ...], dict[str, str]]] = EMPTY_SEQ -class Branch(NamedTuple): - path: Runnable[Any, Union[Hashable, list[Hashable]]] - ends: Optional[dict[Hashable, str]] - then: Optional[str] = None - - def run( - self, - writer: Callable[ - [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] - ], - reader: Optional[Callable[[RunnableConfig], Any]] = None, - ) -> RunnableCallable: - return ChannelWrite.register_writer( - RunnableCallable( - func=self._route, - afunc=self._aroute, - writer=writer, - reader=reader, - name=None, - trace=False, - ) - ) - - def _route( - self, - input: Any, - config: RunnableConfig, - *, - reader: Optional[Callable[[RunnableConfig], Any]], - writer: Callable[ - [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] - ], - ) -> Runnable: - if reader: - value = reader(config) - # passthrough additional keys from node to branch - # only doable when using dict states - if isinstance(value, dict) and isinstance(input, dict): - value = {**input, **value} - else: - value = input - result = self.path.invoke(value, config) - return self._finish(writer, input, result, config) - - async def _aroute( - self, - input: Any, - config: RunnableConfig, - *, - reader: Optional[Callable[[RunnableConfig], Any]], - writer: Callable[ - [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] - ], - ) -> Runnable: - if reader: - value = await asyncio.to_thread(reader, config) - # passthrough additional keys from node to branch - # only doable when using dict states - if isinstance(value, dict) and isinstance(input, dict): - value = {**input, **value} - else: - value = input - result = await self.path.ainvoke(value, config) - return self._finish(writer, input, result, config) - - def _finish( - self, - writer: Callable[ - [Sequence[Union[str, Send]], RunnableConfig], Optional[ChannelWrite] - ], - input: Any, - result: Any, - config: RunnableConfig, - ) -> Union[Runnable, Any]: - if not isinstance(result, (list, tuple)): - result = [result] - if self.ends: - destinations: Sequence[Union[Send, str]] = [ - r if isinstance(r, Send) else self.ends[r] for r in result - ] - else: - destinations = cast(Sequence[Union[Send, str]], result) - if any(dest is None or dest == START for dest in destinations): - raise ValueError("Branch did not return a valid destination") - if any(p.node == END for p in destinations if isinstance(p, Send)): - raise InvalidUpdateError("Cannot send a packet to the END node") - return writer(destinations, config) or input - - class Graph: def __init__(self) -> None: self.nodes: dict[str, NodeSpec] = {} @@ -267,25 +173,7 @@ class Graph: "Adding an edge to a graph that has already been compiled. This will " "not be reflected in the compiled graph." ) - # coerce path_map to a dictionary - try: - if isinstance(path_map, dict): - path_map_ = path_map.copy() - elif isinstance(path_map, list): - path_map_ = {name: name for name in path_map} - elif isinstance(path, Runnable): - path_map_ = None - elif rtn_type := get_type_hints(path.__call__).get( # type: ignore[operator] - "return" - ) or get_type_hints(path).get("return"): - if get_origin(rtn_type) is Literal: - path_map_ = {name: name for name in get_args(rtn_type)} - else: - path_map_ = None - else: - path_map_ = None - except Exception: - path_map_ = None + # find a name for the condition path = coerce_to_runnable(path, name=None, trace=True) name = path.name or "condition" @@ -295,7 +183,7 @@ class Graph: f"Branch with name `{path.name}` already exists for node " f"`{source}`" ) # save it - self.branches[source][name] = Branch(path, path_map_, then) + self.branches[source][name] = Branch.from_path(path, path_map, then, False) return self def set_entry_point(self, key: str) -> Self: @@ -584,7 +472,7 @@ class CompiledGraph(Pregel): ) subgraph.trim_first_node() subgraph.trim_last_node() - if len(subgraph.nodes) > 1: + if len(subgraph.nodes) >= 1: e, s = graph.extend(subgraph, prefix=key) if e is None: raise ValueError( diff --git a/libs/langgraph/langgraph/graph/py.typed b/libs/langgraph/langgraph/graph/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/graph/state.py b/libs/langgraph/langgraph/graph/state.py index a48356df5..2dcd2e95e 100644 --- a/libs/langgraph/langgraph/graph/state.py +++ b/libs/langgraph/langgraph/graph/state.py @@ -7,7 +7,9 @@ from inspect import isclass, isfunction, ismethod, signature from types import FunctionType from typing import ( Any, + Awaitable, Callable, + Hashable, Literal, NamedTuple, Optional, @@ -40,7 +42,14 @@ from langgraph.errors import ( ParentCommand, create_error_message, ) -from langgraph.graph.graph import END, START, Branch, CompiledGraph, Graph, Send +from langgraph.graph.branch import Branch +from langgraph.graph.graph import ( + END, + START, + CompiledGraph, + Graph, + Send, +) from langgraph.managed.base import ( ChannelKeyPlaceholder, ChannelTypePlaceholder, @@ -461,6 +470,57 @@ class StateGraph(Graph): self.waiting_edges.add((tuple(start_key), end_key)) return self + def add_conditional_edges( + self, + source: str, + path: Union[ + Callable[..., Union[Hashable, list[Hashable]]], + Callable[..., Awaitable[Union[Hashable, list[Hashable]]]], + Runnable[Any, Union[Hashable, list[Hashable]]], + ], + path_map: Optional[Union[dict[Hashable, str], list[str]]] = None, + then: Optional[str] = None, + ) -> Self: + """Add a conditional edge from the starting node to any number of destination nodes. + + Args: + source (str): The starting node. This conditional edge will run when + exiting this node. + path (Union[Callable, Runnable]): The callable that determines the next + node or nodes. If not specifying `path_map` it should return one or + more nodes. If it returns END, the graph will stop execution. + path_map (Optional[dict[Hashable, str]]): Optional mapping of paths to node + names. If omitted the paths returned by `path` should be node names. + then (Optional[str]): The name of a node to execute after the nodes + selected by `path`. + + Returns: + Self: The instance of the graph, allowing for method chaining. + + Note: Without typehints on the `path` function's return value (e.g., `-> Literal["foo", "__end__"]:`) + or a path_map, the graph visualization assumes the edge could transition to any node in the graph. + + """ # noqa: E501 + if self.compiled: + logger.warning( + "Adding an edge to a graph that has already been compiled. This will " + "not be reflected in the compiled graph." + ) + + # find a name for the condition + path = coerce_to_runnable(path, name=None, trace=True) + name = path.name or "condition" + # validate the condition + if name in self.branches[source]: + raise ValueError( + f"Branch with name `{path.name}` already exists for node " f"`{source}`" + ) + # save it + self.branches[source][name] = Branch.from_path(path, path_map, then, True) + if schema := self.branches[source][name].input_schema: + self._add_schema(schema) + return self + def add_sequence( self, nodes: Sequence[Union[RunnableLike, tuple[str, RunnableLike]]], @@ -566,6 +626,11 @@ class StateGraph(Graph): compiled = CompiledStateGraph( builder=self, config_type=self.config_schema, + input_model=self.input + if len(self.channels) > 1 + and isclass(self.input) + and issubclass(self.input, (BaseModel, BaseModelV1)) + else None, nodes={}, channels={ **self.channels, @@ -695,23 +760,22 @@ class CompiledStateGraph(CompiledGraph): updates.extend(_get_updates(i) or ()) return updates elif get_type_hints(type(input)): - # if input is a Pydantic model, only update values - # for the keys that have been explicitly set by the users - # (this is needed to avoid sending updates for fields with None defaults) - output_keys_ = output_keys # Pydantic v2 - if hasattr(input, "model_fields_set"): - output_keys_ = [ - k for k in output_keys if k in input.model_fields_set - ] + if hasattr(input, "model_fields"): + defaults = {k: v.default for k, v in input.model_fields.items()} # Pydantic v1 - elif hasattr(input, "__fields_set__"): - output_keys_ = [k for k in output_keys if k in input.__fields_set__] + elif hasattr(input, "__fields__"): + defaults = {k: v.default for k, v in input.__fields__.items()} + else: + defaults = {} + # if input is a Pydantic model, only update values + # that are different from the default values return [ - (k, getattr(input, k)) - for k in output_keys_ - if getattr(input, k, MISSING) is not MISSING + (k, value) + for k in output_keys + if (value := getattr(input, k, MISSING)) is not MISSING + and value != defaults.get(k) ] else: msg = create_error_message( @@ -752,11 +816,7 @@ class CompiledStateGraph(CompiledGraph): # read state keys and managed values channels=(list(input_values) if is_single_input else input_values), # coerce state dict to schema class (eg. pydantic model) - mapper=( - None - if is_single_input or issubclass(input_schema, dict) - else partial(_coerce_state, input_schema) - ), + mapper=_pick_mapper(list(input_values), input_schema), writers=[ # publish to this channel and state keys ChannelWrite( @@ -826,12 +886,12 @@ class CompiledStateGraph(CompiledGraph): config, cast(Sequence[Union[Send, ChannelWriteEntry]], writes) ) - # attach branch publisher - schema = ( + schema = branch.input_schema or ( self.builder.nodes[start].input if start in self.builder.nodes else self.builder.schema ) + # attach branch publisher self.nodes[start] |= branch.run( branch_writer, _get_state_reader(self.builder, schema) if with_reader else None, @@ -871,14 +931,34 @@ def _get_state_reader( select=select[0] if select == ["__root__"] else select, fresh=True, # coerce state dict to schema class (eg. pydantic model) - mapper=( - None - if state_keys == ["__root__"] or issubclass(schema, dict) - else partial(_coerce_state, schema) - ), + mapper=_pick_mapper(state_keys, schema), ) +def _pick_mapper( + state_keys: Sequence[str], schema: Type[Any] +) -> Optional[Callable[[Any], Any]]: + if state_keys == ["__root__"]: + return None + if issubclass(schema, dict): + return None + if issubclass(schema, BaseModel): + return partial(_coerce_state_pydantic, schema) + if issubclass(schema, BaseModelV1): + return partial(_coerce_state_pydantic_v1, schema) + return partial(_coerce_state, schema) + + +def _coerce_state_pydantic(schema: Type[Any], input: dict[str, Any]) -> dict[str, Any]: + return schema.model_construct(**input) + + +def _coerce_state_pydantic_v1( + schema: Type[Any], input: dict[str, Any] +) -> dict[str, Any]: + return schema.construct(**input) + + def _coerce_state(schema: Type[Any], input: dict[str, Any]) -> dict[str, Any]: return schema(**input) diff --git a/libs/langgraph/langgraph/managed/py.typed b/libs/langgraph/langgraph/managed/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/prebuilt/tool_executor.py b/libs/langgraph/langgraph/prebuilt/tool_executor.py deleted file mode 100644 index 692fa6b9a..000000000 --- a/libs/langgraph/langgraph/prebuilt/tool_executor.py +++ /dev/null @@ -1,134 +0,0 @@ -from typing import Any, Callable, Sequence, Union - -from langchain_core.load.serializable import Serializable -from langchain_core.runnables import RunnableConfig -from langchain_core.tools import BaseTool -from langchain_core.tools import tool as create_tool - -from langgraph._api.deprecation import deprecated -from langgraph.utils.runnable import RunnableCallable - -INVALID_TOOL_MSG_TEMPLATE = ( - "{requested_tool_name} is not a valid tool, " - "try one of [{available_tool_names_str}]." -) - - -@deprecated("0.2.0", "langgraph.prebuilt.ToolNode", removal="0.3.0") -class ToolInvocationInterface: - """Interface for invoking a tool. - - Attributes: - tool (str): The name of the tool to invoke. - tool_input (Union[str, dict]): The input to pass to the tool. - - """ - - tool: str - tool_input: Union[str, dict] - - -@deprecated("0.2.0", "langgraph.prebuilt.ToolNode", removal="0.3.0") -class ToolInvocation(Serializable): - """Information about how to invoke a tool. - - Attributes: - tool (str): The name of the Tool to execute. - tool_input (Union[str, dict]): The input to pass in to the Tool. - - Examples: - Basic usage: - ```pycon - >>> invocation = ToolInvocation( - ... tool="search", - ... tool_input="What is the capital of France?" - ... ) - ``` - """ - - tool: str - tool_input: Union[str, dict] - - -@deprecated("0.2.0", "langgraph.prebuilt.ToolNode", removal="0.3.0") -class ToolExecutor(RunnableCallable): - """Executes a tool invocation. - - Args: - tools (Sequence[BaseTool]): A sequence of tools that can be invoked. - invalid_tool_msg_template (str, optional): The template for the error message - when an invalid tool is requested. Defaults to INVALID_TOOL_MSG_TEMPLATE. - - Examples: - Basic usage: - - ```pycon - >>> from langchain_core.tools import tool - >>> from langgraph.prebuilt.tool_executor import ToolExecutor, ToolInvocation - ... - ... - >>> @tool - ... def search(query: str) -> str: - ... \"\"\"Search engine.\"\"\" - ... return f"Searching for: {query}" - ... - ... - >>> tools = [search] - >>> executor = ToolExecutor(tools) - ... - >>> invocation = ToolInvocation(tool="search", tool_input="What is the capital of France?") - >>> result = executor.invoke(invocation) - >>> print(result) - "Searching for: What is the capital of France?" - ``` - Handling invalid tool: - - ```pycon - >>> invocation = ToolInvocation( - ... tool="nonexistent", tool_input="What is the capital of France?" - ... ) - >>> result = executor.invoke(invocation) - >>> print(result) - "nonexistent is not a valid tool, try one of [search]." - ``` - """ - - def __init__( - self, - tools: Sequence[Union[BaseTool, Callable]], - *, - invalid_tool_msg_template: str = INVALID_TOOL_MSG_TEMPLATE, - ) -> None: - super().__init__(self._execute, afunc=self._aexecute, trace=False) - tools_ = [ - tool if isinstance(tool, BaseTool) else create_tool(tool) for tool in tools - ] - self.tools = tools_ - self.tool_map = {t.name: t for t in tools_} - self.invalid_tool_msg_template = invalid_tool_msg_template - - def _execute( - self, tool_invocation: ToolInvocationInterface, config: RunnableConfig - ) -> Any: - if tool_invocation.tool not in self.tool_map: - return self.invalid_tool_msg_template.format( - requested_tool_name=tool_invocation.tool, - available_tool_names_str=", ".join([t.name for t in self.tools]), - ) - else: - tool = self.tool_map[tool_invocation.tool] - output = tool.invoke(tool_invocation.tool_input, config) - return output - - async def _aexecute( - self, tool_invocation: ToolInvocationInterface, config: RunnableConfig - ) -> Any: - if tool_invocation.tool not in self.tool_map: - return self.invalid_tool_msg_template.format( - requested_tool_name=tool_invocation.tool, - available_tool_names_str=", ".join([t.name for t in self.tools]), - ) - else: - tool = self.tool_map[tool_invocation.tool] - output = await tool.ainvoke(tool_invocation.tool_input, config) - return output diff --git a/libs/langgraph/langgraph/pregel/__init__.py b/libs/langgraph/langgraph/pregel/__init__.py index df6784e67..362c1459c 100644 --- a/libs/langgraph/langgraph/pregel/__init__.py +++ b/libs/langgraph/langgraph/pregel/__init__.py @@ -18,6 +18,7 @@ from typing import ( Type, Union, cast, + get_type_hints, overload, ) from uuid import UUID, uuid5 @@ -119,7 +120,7 @@ from langgraph.utils.config import ( recast_checkpoint_ns, ) from langgraph.utils.fields import get_enhanced_type_hints -from langgraph.utils.pydantic import create_model +from langgraph.utils.pydantic import create_model, is_supported_by_pydantic from langgraph.utils.queue import AsyncQueue, SyncQueue # type: ignore[attr-defined] WriteValue = Union[Callable[[Input], Output], Any] @@ -495,6 +496,8 @@ class Pregel(PregelProtocol): config_type: Optional[Type[Any]] = None + input_model: Optional[Type[BaseModel]] = None + config: Optional[RunnableConfig] = None name: str = "LangGraph" @@ -518,6 +521,7 @@ class Pregel(PregelProtocol): store: Optional[BaseStore] = None, retry_policy: Optional[RetryPolicy] = None, config_type: Optional[Type[Any]] = None, + input_model: Optional[Type[BaseModel]] = None, config: Optional[RunnableConfig] = None, name: str = "LangGraph", ) -> None: @@ -536,6 +540,7 @@ class Pregel(PregelProtocol): self.store = store self.retry_policy = retry_policy self.config_type = config_type + self.input_model = input_model self.config = config self.name = name if auto_validate: @@ -609,6 +614,36 @@ class Pregel(PregelProtocol): ] ] + def config_schema( + self, *, include: Optional[Sequence[str]] = None + ) -> Type[BaseModel]: + # If the config type is not set explicitly, we will try to infer it. + # If the config type is provided, but isn't directly supported by pydantic + # (e.g., vanilla python class), we will also delegate to the parent class, + # which handles cases where Pydantic doesn't support the type. + if self.config_type is None or not is_supported_by_pydantic(self.config_type): + return super().config_schema(include=include) + + include = include or [] + fields = { + "configurable": (self.config_type, None), + **{ + field_name: (field_type, None) + for field_name, field_type in get_type_hints(RunnableConfig).items() + if field_name in [i for i in include if i != "configurable"] + }, + } + return create_model(self.get_name("Config"), field_definitions=fields) + + def get_config_jsonschema( + self, *, include: Optional[Sequence[str]] = None + ) -> Dict[str, Any]: + schema = self.config_schema(include=include) + if hasattr(schema, "model_json_schema"): + return schema.model_json_schema() + else: + return schema.schema() + @property def InputType(self) -> Any: if isinstance(self.input_channels, str): @@ -619,6 +654,8 @@ class Pregel(PregelProtocol): def get_input_schema( self, config: Optional[RunnableConfig] = None ) -> Type[BaseModel]: + if self.input_model is not None: + return self.input_model config = merge_configs(self.config, config) if isinstance(self.input_channels, str): return super().get_input_schema(config) @@ -634,7 +671,7 @@ class Pregel(PregelProtocol): def get_input_jsonschema( self, config: Optional[RunnableConfig] = None - ) -> Dict[All, Any]: + ) -> Dict[str, Any]: schema = self.get_input_schema(config) if hasattr(schema, "model_json_schema"): return schema.model_json_schema() @@ -666,7 +703,7 @@ class Pregel(PregelProtocol): def get_output_jsonschema( self, config: Optional[RunnableConfig] = None - ) -> Dict[All, Any]: + ) -> Dict[str, Any]: schema = self.get_output_schema(config) if hasattr(schema, "model_json_schema"): return schema.model_json_schema() @@ -971,6 +1008,12 @@ class Pregel(PregelProtocol): raise ValueError(f"Subgraph {recast} not found") config = merge_configs(self.config, config) if self.config else config + if self.checkpointer is True: + ns = cast(str, config[CONF][CONFIG_KEY_CHECKPOINT_NS]) + config = merge_configs( + config, {CONF: {CONFIG_KEY_CHECKPOINT_NS: recast_checkpoint_ns(ns)}} + ) + saved = checkpointer.get_tuple(config) return self._prepare_state_snapshot( config, @@ -1004,6 +1047,12 @@ class Pregel(PregelProtocol): raise ValueError(f"Subgraph {recast} not found") config = merge_configs(self.config, config) if self.config else config + if self.checkpointer is True: + ns = cast(str, config[CONF][CONFIG_KEY_CHECKPOINT_NS]) + config = merge_configs( + config, {CONF: {CONFIG_KEY_CHECKPOINT_NS: recast_checkpoint_ns(ns)}} + ) + saved = await checkpointer.aget_tuple(config) return await self._aprepare_state_snapshot( config, @@ -1911,9 +1960,7 @@ class Pregel(PregelProtocol): # set up subgraph checkpointing if self.checkpointer is True: ns = cast(str, config[CONF][CONFIG_KEY_CHECKPOINT_NS]) - config[CONF][CONFIG_KEY_CHECKPOINT_NS] = NS_SEP.join( - part.split(NS_END)[0] for part in ns.split(NS_SEP) - ) + config[CONF][CONFIG_KEY_CHECKPOINT_NS] = recast_checkpoint_ns(ns) # set up messages stream mode if "messages" in stream_modes: run_manager.inheritable_handlers.append( @@ -1926,6 +1973,7 @@ class Pregel(PregelProtocol): ) with SyncPregelLoop( input, + input_model=self.input_model, stream=StreamProtocol(stream.put, stream_modes), config=config, store=store, @@ -2201,9 +2249,7 @@ class Pregel(PregelProtocol): # set up subgraph checkpointing if self.checkpointer is True: ns = cast(str, config[CONF][CONFIG_KEY_CHECKPOINT_NS]) - config[CONF][CONFIG_KEY_CHECKPOINT_NS] = NS_SEP.join( - part.split(NS_END)[0] for part in ns.split(NS_SEP) - ) + config[CONF][CONFIG_KEY_CHECKPOINT_NS] = recast_checkpoint_ns(ns) # set up messages stream mode if "messages" in stream_modes: run_manager.inheritable_handlers.append( @@ -2218,6 +2264,7 @@ class Pregel(PregelProtocol): ) async with AsyncPregelLoop( input, + input_model=self.input_model, stream=StreamProtocol(stream.put_nowait, stream_modes), config=config, store=store, diff --git a/libs/langgraph/langgraph/pregel/loop.py b/libs/langgraph/langgraph/pregel/loop.py index 0f70c1499..66f0a60f5 100644 --- a/libs/langgraph/langgraph/pregel/loop.py +++ b/libs/langgraph/langgraph/pregel/loop.py @@ -2,7 +2,6 @@ import asyncio import concurrent.futures from collections import defaultdict, deque from contextlib import AsyncExitStack, ExitStack -from dataclasses import replace from inspect import signature from types import TracebackType from typing import ( @@ -24,6 +23,7 @@ from typing import ( from langchain_core.callbacks import AsyncParentRunManager, ParentRunManager from langchain_core.runnables import RunnableConfig +from pydantic import BaseModel from typing_extensions import ParamSpec, Self from langgraph.channels.base import BaseChannel @@ -55,6 +55,7 @@ from langgraph.constants import ( ERROR, INPUT, INTERRUPT, + MISSING, NS_SEP, NULL_TASK_ID, PUSH, @@ -67,7 +68,6 @@ from langgraph.errors import ( EmptyInputError, GraphDelegate, GraphInterrupt, - ParentCommand, ) from langgraph.managed.base import ( ManagedValueMapping, @@ -126,6 +126,7 @@ P = ParamSpec("P") INPUT_DONE = object() INPUT_RESUMING = object() +INPUT_SHOULD_VALIDATE = object() SPECIAL_CHANNELS = (ERROR, INTERRUPT, SCHEDULED) @@ -140,6 +141,7 @@ def DuplexStream(*streams: StreamProtocol) -> StreamProtocol: class PregelLoop(LoopProtocol): input: Optional[Any] + input_model: Optional[Type[BaseModel]] checkpointer: Optional[BaseCheckpointSaver] nodes: Mapping[str, PregelNode] specs: Mapping[str, Union[BaseChannel, ManagedValueSpec]] @@ -203,6 +205,7 @@ class PregelLoop(LoopProtocol): interrupt_after: Union[All, Sequence[str]] = EMPTY_SEQ, interrupt_before: Union[All, Sequence[str]] = EMPTY_SEQ, manager: Union[None, AsyncParentRunManager, ParentRunManager] = None, + input_model: Optional[Type[BaseModel]] = None, debug: bool = False, ) -> None: super().__init__( @@ -213,6 +216,7 @@ class PregelLoop(LoopProtocol): store=store, ) self.input = input + self.input_model = input_model self.checkpointer = checkpointer self.nodes = nodes self.specs = specs @@ -396,13 +400,14 @@ class PregelLoop(LoopProtocol): if self.status != "pending": raise RuntimeError("Cannot tick when status is no longer 'pending'") - if self.input not in (INPUT_DONE, INPUT_RESUMING): + if self.input not in (INPUT_DONE, INPUT_RESUMING, INPUT_SHOULD_VALIDATE): self._first(input_keys=input_keys) elif self.to_interrupt: # if we need to interrupt, do so self.status = "interrupt_before" raise GraphInterrupt() elif all(task.writes for task in self.tasks.values()): + # finish superstep writes = [w for t in self.tasks.values() for w in t.writes] # debug flag if self.debug: @@ -425,6 +430,13 @@ class PregelLoop(LoopProtocol): # apply writes to managed values for key, values in mv_writes.items(): self._update_mv(key, values) + # validate input if requested + if self.input is INPUT_SHOULD_VALIDATE: + self.input = INPUT_DONE + # validate + cast(Type[BaseModel], self.input_model)( + **read_channels(self.channels, self.stream_keys) + ) # produce values output self._emit( "values", map_output_values, self.output_keys, writes, self.channels @@ -451,6 +463,9 @@ class PregelLoop(LoopProtocol): ): self.status = "interrupt_after" raise GraphInterrupt() + + # unset resuming flag + self.config[CONF].pop(CONFIG_KEY_RESUMING, None) else: return False @@ -562,7 +577,13 @@ class PregelLoop(LoopProtocol): is_resuming = bool(self.checkpoint["channel_versions"]) and bool( configurable.get( CONFIG_KEY_RESUMING, - self.input is None or isinstance(self.input, Command), + self.input is None + or isinstance(self.input, Command) + or ( + not self.is_nested + and self.config.get("metadata", {}).get("run_id") + == self.checkpoint_metadata.get("run_id", MISSING) + ), ) ) @@ -613,6 +634,8 @@ class PregelLoop(LoopProtocol): self._emit( "values", map_output_values, self.output_keys, True, self.channels ) + # set flag + self.input = INPUT_RESUMING # map inputs to channel updates elif input_writes := deque(map_input(input_keys, self.input)): # TODO shouldn't these writes be passed to put_writes too? @@ -653,10 +676,19 @@ class PregelLoop(LoopProtocol): assert not mv_writes, "Can't write to SharedValues in graph input" # save input checkpoint self._put_checkpoint({"source": "input", "writes": dict(input_writes)}) + # set flag + if ( + self.input_model is not None + and not isinstance(self.input, self.input_model) + and not isinstance(self.stream_keys, str) + ): + self.input = INPUT_SHOULD_VALIDATE + else: + self.input = INPUT_DONE elif CONFIG_KEY_RESUMING not in configurable: raise EmptyInputError(f"Received no input for {input_keys}") - # done with input - self.input = INPUT_RESUMING if is_resuming else INPUT_DONE + else: + self.input = INPUT_DONE # update config if not self.is_nested: self.config = patch_configurable( @@ -738,15 +770,6 @@ class PregelLoop(LoopProtocol): exc_value: Optional[BaseException], traceback: Optional[TracebackType], ) -> Optional[bool]: - # add current state to parent command - if isinstance(exc_value, ParentCommand): - cmd = exc_value.args[0] - state = ( - [(self.output_keys, read_channels(self.channels, self.output_keys))] - if isinstance(self.output_keys, str) - else list(read_channels(self.channels, self.output_keys).items()) - ) - exc_value.args = (replace(cmd, update=[*state, *cmd._update_as_tuples()]),) # suppress interrupt suppress = isinstance(exc_value, GraphInterrupt) and not self.is_nested if suppress: @@ -840,10 +863,12 @@ class SyncPregelLoop(PregelLoop, ContextManager): interrupt_before: Union[All, Sequence[str]] = EMPTY_SEQ, output_keys: Union[str, Sequence[str]] = EMPTY_SEQ, stream_keys: Union[str, Sequence[str]] = EMPTY_SEQ, + input_model: Optional[Type[BaseModel]] = None, debug: bool = False, ) -> None: super().__init__( input, + input_model=input_model, stream=stream, config=config, checkpointer=checkpointer, @@ -979,10 +1004,12 @@ class AsyncPregelLoop(PregelLoop, AsyncContextManager): manager: Union[None, AsyncParentRunManager, ParentRunManager] = None, output_keys: Union[str, Sequence[str]] = EMPTY_SEQ, stream_keys: Union[str, Sequence[str]] = EMPTY_SEQ, + input_model: Optional[Type[BaseModel]] = None, debug: bool = False, ) -> None: super().__init__( input, + input_model=input_model, stream=stream, config=config, checkpointer=checkpointer, diff --git a/libs/langgraph/langgraph/pregel/messages.py b/libs/langgraph/langgraph/pregel/messages.py index ffb07eddb..867012fa6 100644 --- a/libs/langgraph/langgraph/pregel/messages.py +++ b/libs/langgraph/langgraph/pregel/messages.py @@ -127,6 +127,16 @@ class StreamMessagesHandler(BaseCallbackHandler, _StreamingCallbackHandler): tuple(cast(str, metadata["langgraph_checkpoint_ns"]).split(NS_SEP)), metadata, ) + if isinstance(inputs, dict): + for key, value in inputs.items(): + if isinstance(value, BaseMessage): + if value.id is not None: + self.seen.add(value.id) + elif isinstance(value, Sequence) and not isinstance(value, str): + for item in value: + if isinstance(item, BaseMessage): + if item.id is not None: + self.seen.add(item.id) def on_chain_end( self, diff --git a/libs/langgraph/langgraph/pregel/py.typed b/libs/langgraph/langgraph/pregel/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/pregel/validate.py b/libs/langgraph/langgraph/pregel/validate.py index cf957dc07..6b43f7b7c 100644 --- a/libs/langgraph/langgraph/pregel/validate.py +++ b/libs/langgraph/langgraph/pregel/validate.py @@ -32,11 +32,17 @@ def validate_graph( for chan in subscribed_channels: if chan not in channels: - raise ValueError(f"Subscribed channel '{chan}' not in 'channels'") + raise ValueError( + f"Subscribed channel '{chan}' not " + f"in known channels: '{repr(sorted(channels))[:100]}'" + ) if isinstance(input_channels, str): if input_channels not in channels: - raise ValueError(f"Input channel '{input_channels}' not in 'channels'") + raise ValueError( + f"Input channel '{input_channels}' not " + f"in known channels: '{repr(sorted(channels))[:100]}'" + ) if input_channels not in subscribed_channels: raise ValueError( f"Input channel {input_channels} is not subscribed to by any node" @@ -44,10 +50,13 @@ def validate_graph( else: for chan in input_channels: if chan not in channels: - raise ValueError(f"Input channel '{chan}' not in 'channels'") + raise ValueError( + f"Input channel '{chan}' not in '{repr(sorted(channels))[:100]}'" + ) if all(chan not in subscribed_channels for chan in input_channels): raise ValueError( - f"None of the input channels {input_channels} are subscribed to by any node" + f"None of the input channels {input_channels} " + f"are subscribed to by any node" ) all_output_channels = set[str]() @@ -62,7 +71,10 @@ def validate_graph( for chan in all_output_channels: if chan not in channels: - raise ValueError(f"Output channel '{chan}' not in 'channels'") + raise ValueError( + f"Output channel '{chan}' not " + f"in known channels: '{repr(sorted(channels))[:100]}'" + ) if interrupt_after_nodes != "*": for n in interrupt_after_nodes: diff --git a/libs/langgraph/langgraph/utils/config.py b/libs/langgraph/langgraph/utils/config.py index baf1bb8a9..20efec07b 100644 --- a/libs/langgraph/langgraph/utils/config.py +++ b/libs/langgraph/langgraph/utils/config.py @@ -1,4 +1,5 @@ from collections import ChainMap +from os import getenv from typing import Any, Optional, Sequence, cast from langchain_core.callbacks import ( @@ -11,7 +12,6 @@ from langchain_core.runnables import RunnableConfig from langchain_core.runnables.config import ( CONFIG_KEYS, COPIABLE_KEYS, - DEFAULT_RECURSION_LIMIT, var_child_runnable_config, ) @@ -26,6 +26,8 @@ from langgraph.constants import ( NS_SEP, ) +DEFAULT_RECURSION_LIMIT = int(getenv("LANGGRAPH_DEFAULT_RECURSION_LIMIT", "25")) + def recast_checkpoint_ns(ns: str) -> str: """Remove task IDs from checkpoint namespace. diff --git a/libs/langgraph/langgraph/utils/py.typed b/libs/langgraph/langgraph/utils/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/utils/pydantic.py b/libs/langgraph/langgraph/utils/pydantic.py index cd0984202..56cef30e6 100644 --- a/libs/langgraph/langgraph/utils/pydantic.py +++ b/libs/langgraph/langgraph/utils/pydantic.py @@ -1,5 +1,9 @@ +import sys +import typing +from dataclasses import is_dataclass from typing import Any, Dict, Optional, Union +import typing_extensions from pydantic import BaseModel from pydantic.v1 import BaseModel as BaseModelV1 @@ -35,3 +39,31 @@ def create_model( v1_kwargs["__root__"] = root return create_model(model_name, **v1_kwargs, **(field_definitions or {})) + + +def is_supported_by_pydantic(type_: Any) -> bool: + """Check if a given "complex" type is supported by pydantic. + + This will return False for primitive types like int, str, etc. + + The check is meant for container types like dataclasses, TypedDicts, etc. + """ + if is_dataclass(type_): + return True + + # Pydantic does not support mixing .v1 and root namespaces, so + # we only check for BaseModel (not pydantic.v1.BaseModel). + if isinstance(type_, type) and issubclass(type_, BaseModel): + return True + + if hasattr(type_, "__orig_bases__"): + for base in type_.__orig_bases__: + if base is typing_extensions.TypedDict: + return True + elif base is typing.TypedDict: # noqa: TID251 + # ignoring TID251 since it's OK to use typing.TypedDict in this case. + # Pydantic supports typing.TypedDict from Python 3.12 + # For older versions, only typing_extensions.TypedDict is supported. + if sys.version_info >= (3, 12): + return True + return False diff --git a/libs/langgraph/poetry.lock b/libs/langgraph/poetry.lock index 84cd79014..ef04df931 100644 --- a/libs/langgraph/poetry.lock +++ b/libs/langgraph/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "aiosqlite" @@ -1324,19 +1324,19 @@ files = [ [[package]] name = "langchain-core" -version = "0.3.30" +version = "0.3.44" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" groups = ["main", "dev"] files = [ - {file = "langchain_core-0.3.30-py3-none-any.whl", hash = "sha256:0a4c4e02fac5968b67fbb0142c00c2b976c97e45fce62c7ac9eb1636a6926493"}, - {file = "langchain_core-0.3.30.tar.gz", hash = "sha256:0f1281b4416977df43baf366633ad18e96c5dcaaeae6fcb8a799f9889c853243"}, + {file = "langchain_core-0.3.44-py3-none-any.whl", hash = "sha256:d989ce8bd62f1d07765acd575e6ec1254aec0cf7775aaea39fe4af8102377459"}, + {file = "langchain_core-0.3.44.tar.gz", hash = "sha256:7c0a01e78360f007cbca448178fe7e032404068e6431dbe8ce905f84febbdfa5"}, ] [package.dependencies] jsonpatch = ">=1.33,<2.0" -langsmith = ">=0.1.125,<0.3" +langsmith = ">=0.1.125,<0.4" packaging = ">=23.2,<25" pydantic = [ {version = ">=2.5.2,<3.0.0", markers = "python_full_version < \"3.12.4\""}, @@ -1348,7 +1348,7 @@ typing-extensions = ">=4.7" [[package]] name = "langgraph-checkpoint" -version = "2.0.10" +version = "2.0.18" description = "Library with base interfaces for LangGraph checkpoint savers." optional = false python-versions = "^3.9.0,<4.0" @@ -1366,7 +1366,7 @@ url = "../checkpoint" [[package]] name = "langgraph-checkpoint-postgres" -version = "2.0.12" +version = "2.0.16" description = "Library with a Postgres implementation of LangGraph checkpoint saver." optional = false python-versions = "^3.9.0,<4.0" @@ -1375,7 +1375,7 @@ files = [] develop = true [package.dependencies] -langgraph-checkpoint = "^2.0.10" +langgraph-checkpoint = "^2.0.15" orjson = ">=3.10.1" psycopg = "^3.2.0" psycopg-pool = "^3.2.0" @@ -1386,7 +1386,7 @@ url = "../checkpoint-postgres" [[package]] name = "langgraph-checkpoint-sqlite" -version = "2.0.3" +version = "2.0.6" description = "Library with a SQLite implementation of LangGraph checkpoint saver." optional = false python-versions = "^3.9.0" @@ -1395,16 +1395,34 @@ files = [] develop = true [package.dependencies] -aiosqlite = "^0.20.0" -langgraph-checkpoint = "^2.0.10" +aiosqlite = ">=0.20,<0.22" +langgraph-checkpoint = "^2.0.15" [package.source] type = "directory" url = "../checkpoint-sqlite" +[[package]] +name = "langgraph-prebuilt" +version = "0.1.2" +description = "Library with high-level APIs for creating and executing LangGraph agents and tools." +optional = false +python-versions = "^3.9.0,<4.0" +groups = ["main", "dev"] +files = [] +develop = true + +[package.dependencies] +langchain-core = ">=0.2.43,<0.4.0,!=0.3.0,!=0.3.1,!=0.3.2,!=0.3.3,!=0.3.4,!=0.3.5,!=0.3.6,!=0.3.7,!=0.3.8,!=0.3.9,!=0.3.10,!=0.3.11,!=0.3.12,!=0.3.13,!=0.3.14,!=0.3.15,!=0.3.16,!=0.3.17,!=0.3.18,!=0.3.19,!=0.3.20,!=0.3.21,!=0.3.22" +langgraph-checkpoint = "^2.0.10" + +[package.source] +type = "directory" +url = "../prebuilt" + [[package]] name = "langgraph-sdk" -version = "0.1.51" +version = "0.1.55" description = "SDK for interacting with LangGraph API" optional = false python-versions = "^3.9.0,<4.0" @@ -3491,4 +3509,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">=3.9.0,<4.0" -content-hash = "caf943b02b6913c05d15c37fda6d216669f789e2a059b7e8e2490b2bdcd23e0e" +content-hash = "eb85f0bcc0e8a715ef38afb58cf888f7c2ee8579ea6ed94900244365f24cddd9" diff --git a/libs/langgraph/pyproject.toml b/libs/langgraph/pyproject.toml index 802028818..deed4679b 100644 --- a/libs/langgraph/pyproject.toml +++ b/libs/langgraph/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph" -version = "0.2.74" +version = "0.3.8" description = "Building stateful, multi-actor applications with LLMs" authors = [] license = "MIT" @@ -9,9 +9,10 @@ repository = "https://www.github.com/langchain-ai/langgraph" [tool.poetry.dependencies] python = ">=3.9.0,<4.0" -langchain-core = ">=0.2.43,<0.4.0,!=0.3.0,!=0.3.1,!=0.3.2,!=0.3.3,!=0.3.4,!=0.3.5,!=0.3.6,!=0.3.7,!=0.3.8,!=0.3.9,!=0.3.10,!=0.3.11,!=0.3.12,!=0.3.13,!=0.3.14,!=0.3.15,!=0.3.16,!=0.3.17,!=0.3.18,!=0.3.19,!=0.3.20,!=0.3.21,!=0.3.22" +langchain-core = ">=0.1,<0.4" langgraph-checkpoint = "^2.0.10" langgraph-sdk = "^0.1.42" +langgraph-prebuilt = ">=0.1.1,<0.2" [tool.poetry.group.dev.dependencies] pytest = "^8.3.2" @@ -26,6 +27,7 @@ ruff = "^0.6.2" jupyter = "^1.0.0" pytest-xdist = {extras = ["psutil"], version = "^3.6.1"} pytest-repeat = "^0.9.3" +langgraph-prebuilt = {path = "../prebuilt", develop = true} langgraph-checkpoint = {path = "../checkpoint", develop = true} langgraph-checkpoint-sqlite = {path = "../checkpoint-sqlite", develop = true} langgraph-checkpoint-postgres = {path = "../checkpoint-postgres", develop = true} diff --git a/libs/langgraph/tests/__snapshots__/test_large_cases.ambr b/libs/langgraph/tests/__snapshots__/test_large_cases.ambr index 017b1aa9b..62517bcb7 100644 --- a/libs/langgraph/tests/__snapshots__/test_large_cases.ambr +++ b/libs/langgraph/tests/__snapshots__/test_large_cases.ambr @@ -3116,8 +3116,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -3126,6 +3124,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -3141,8 +3141,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -3151,6 +3149,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -3166,8 +3166,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -3176,6 +3174,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -3191,8 +3191,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -3201,6 +3199,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -3216,8 +3216,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -3226,6 +3224,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -3241,8 +3241,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -3251,6 +3249,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 diff --git a/libs/langgraph/tests/__snapshots__/test_large_cases_async.ambr b/libs/langgraph/tests/__snapshots__/test_large_cases_async.ambr index 898dd4f89..107532c66 100644 --- a/libs/langgraph/tests/__snapshots__/test_large_cases_async.ambr +++ b/libs/langgraph/tests/__snapshots__/test_large_cases_async.ambr @@ -6,8 +6,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -16,6 +14,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -31,8 +31,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -41,6 +39,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -56,8 +56,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -66,6 +64,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -81,8 +81,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -91,6 +89,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -106,8 +106,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -116,6 +114,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 @@ -131,8 +131,6 @@ __start__([

__start__

]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node
__interrupt = before) __end__([

__end__

]):::last __start__ --> router_node; normal_llm_node --> __end__; @@ -141,6 +139,8 @@ router_node -.-> weather_graph_model_node; router_node -.-> __end__; subgraph weather_graph + weather_graph_model_node(model_node) + weather_graph_weather_node(weather_node
__interrupt = before) weather_graph_model_node --> weather_graph_weather_node; end classDef default fill:#f2f0ff,line-height:1.2 diff --git a/libs/langgraph/tests/__snapshots__/test_pregel.ambr b/libs/langgraph/tests/__snapshots__/test_pregel.ambr index 4d9622955..c751b924f 100644 --- a/libs/langgraph/tests/__snapshots__/test_pregel.ambr +++ b/libs/langgraph/tests/__snapshots__/test_pregel.ambr @@ -1217,6 +1217,426 @@ 'type': 'object', }) # --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[memory] + ''' + graph TD; + __start__ --> rewrite_query; + analyzer_one --> retriever_one; + qa --> __end__; + retriever_one --> qa; + retriever_two --> qa; + rewrite_query --> analyzer_one; + rewrite_query -.-> retriever_two; + + ''' +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[memory].1 + dict({ + '$defs': dict({ + 'InnerObject': dict({ + 'properties': dict({ + 'yo': dict({ + 'title': 'Yo', + 'type': 'integer', + }), + }), + 'required': list([ + 'yo', + ]), + 'title': 'InnerObject', + 'type': 'object', + }), + }), + 'properties': dict({ + 'inner': dict({ + '$ref': '#/$defs/InnerObject', + }), + 'query': dict({ + 'title': 'Query', + 'type': 'string', + }), + }), + 'required': list([ + 'query', + 'inner', + ]), + 'title': 'Input', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[memory].2 + dict({ + 'properties': dict({ + 'answer': dict({ + 'title': 'Answer', + 'type': 'string', + }), + 'docs': dict({ + 'items': dict({ + 'type': 'string', + }), + 'title': 'Docs', + 'type': 'array', + }), + }), + 'required': list([ + 'answer', + 'docs', + ]), + 'title': 'Output', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres] + ''' + graph TD; + __start__ --> rewrite_query; + analyzer_one --> retriever_one; + qa --> __end__; + retriever_one --> qa; + retriever_two --> qa; + rewrite_query --> analyzer_one; + rewrite_query -.-> retriever_two; + + ''' +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres].1 + dict({ + '$defs': dict({ + 'InnerObject': dict({ + 'properties': dict({ + 'yo': dict({ + 'title': 'Yo', + 'type': 'integer', + }), + }), + 'required': list([ + 'yo', + ]), + 'title': 'InnerObject', + 'type': 'object', + }), + }), + 'properties': dict({ + 'inner': dict({ + '$ref': '#/$defs/InnerObject', + }), + 'query': dict({ + 'title': 'Query', + 'type': 'string', + }), + }), + 'required': list([ + 'query', + 'inner', + ]), + 'title': 'Input', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres].2 + dict({ + 'properties': dict({ + 'answer': dict({ + 'title': 'Answer', + 'type': 'string', + }), + 'docs': dict({ + 'items': dict({ + 'type': 'string', + }), + 'title': 'Docs', + 'type': 'array', + }), + }), + 'required': list([ + 'answer', + 'docs', + ]), + 'title': 'Output', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_pipe] + ''' + graph TD; + __start__ --> rewrite_query; + analyzer_one --> retriever_one; + qa --> __end__; + retriever_one --> qa; + retriever_two --> qa; + rewrite_query --> analyzer_one; + rewrite_query -.-> retriever_two; + + ''' +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_pipe].1 + dict({ + '$defs': dict({ + 'InnerObject': dict({ + 'properties': dict({ + 'yo': dict({ + 'title': 'Yo', + 'type': 'integer', + }), + }), + 'required': list([ + 'yo', + ]), + 'title': 'InnerObject', + 'type': 'object', + }), + }), + 'properties': dict({ + 'inner': dict({ + '$ref': '#/$defs/InnerObject', + }), + 'query': dict({ + 'title': 'Query', + 'type': 'string', + }), + }), + 'required': list([ + 'query', + 'inner', + ]), + 'title': 'Input', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_pipe].2 + dict({ + 'properties': dict({ + 'answer': dict({ + 'title': 'Answer', + 'type': 'string', + }), + 'docs': dict({ + 'items': dict({ + 'type': 'string', + }), + 'title': 'Docs', + 'type': 'array', + }), + }), + 'required': list([ + 'answer', + 'docs', + ]), + 'title': 'Output', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_pool] + ''' + graph TD; + __start__ --> rewrite_query; + analyzer_one --> retriever_one; + qa --> __end__; + retriever_one --> qa; + retriever_two --> qa; + rewrite_query --> analyzer_one; + rewrite_query -.-> retriever_two; + + ''' +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_pool].1 + dict({ + '$defs': dict({ + 'InnerObject': dict({ + 'properties': dict({ + 'yo': dict({ + 'title': 'Yo', + 'type': 'integer', + }), + }), + 'required': list([ + 'yo', + ]), + 'title': 'InnerObject', + 'type': 'object', + }), + }), + 'properties': dict({ + 'inner': dict({ + '$ref': '#/$defs/InnerObject', + }), + 'query': dict({ + 'title': 'Query', + 'type': 'string', + }), + }), + 'required': list([ + 'query', + 'inner', + ]), + 'title': 'Input', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_pool].2 + dict({ + 'properties': dict({ + 'answer': dict({ + 'title': 'Answer', + 'type': 'string', + }), + 'docs': dict({ + 'items': dict({ + 'type': 'string', + }), + 'title': 'Docs', + 'type': 'array', + }), + }), + 'required': list([ + 'answer', + 'docs', + ]), + 'title': 'Output', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_shallow] + ''' + graph TD; + __start__ --> rewrite_query; + analyzer_one --> retriever_one; + qa --> __end__; + retriever_one --> qa; + retriever_two --> qa; + rewrite_query --> analyzer_one; + rewrite_query -.-> retriever_two; + + ''' +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_shallow].1 + dict({ + '$defs': dict({ + 'InnerObject': dict({ + 'properties': dict({ + 'yo': dict({ + 'title': 'Yo', + 'type': 'integer', + }), + }), + 'required': list([ + 'yo', + ]), + 'title': 'InnerObject', + 'type': 'object', + }), + }), + 'properties': dict({ + 'inner': dict({ + '$ref': '#/$defs/InnerObject', + }), + 'query': dict({ + 'title': 'Query', + 'type': 'string', + }), + }), + 'required': list([ + 'query', + 'inner', + ]), + 'title': 'Input', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[postgres_shallow].2 + dict({ + 'properties': dict({ + 'answer': dict({ + 'title': 'Answer', + 'type': 'string', + }), + 'docs': dict({ + 'items': dict({ + 'type': 'string', + }), + 'title': 'Docs', + 'type': 'array', + }), + }), + 'required': list([ + 'answer', + 'docs', + ]), + 'title': 'Output', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[sqlite] + ''' + graph TD; + __start__ --> rewrite_query; + analyzer_one --> retriever_one; + qa --> __end__; + retriever_one --> qa; + retriever_two --> qa; + rewrite_query --> analyzer_one; + rewrite_query -.-> retriever_two; + + ''' +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[sqlite].1 + dict({ + '$defs': dict({ + 'InnerObject': dict({ + 'properties': dict({ + 'yo': dict({ + 'title': 'Yo', + 'type': 'integer', + }), + }), + 'required': list([ + 'yo', + ]), + 'title': 'InnerObject', + 'type': 'object', + }), + }), + 'properties': dict({ + 'inner': dict({ + '$ref': '#/$defs/InnerObject', + }), + 'query': dict({ + 'title': 'Query', + 'type': 'string', + }), + }), + 'required': list([ + 'query', + 'inner', + ]), + 'title': 'Input', + 'type': 'object', + }) +# --- +# name: test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input[sqlite].2 + dict({ + 'properties': dict({ + 'answer': dict({ + 'title': 'Answer', + 'type': 'string', + }), + 'docs': dict({ + 'items': dict({ + 'type': 'string', + }), + 'title': 'Docs', + 'type': 'array', + }), + }), + 'required': list([ + 'answer', + 'docs', + ]), + 'title': 'Output', + 'type': 'object', + }) +# --- # name: test_in_one_fan_out_state_graph_waiting_edge_via_branch[memory] ''' graph TD; @@ -1302,13 +1722,13 @@ __start__([

__start__

]):::first uno(uno) dos(dos) - subgraph_one(one) - subgraph_two(two) - subgraph_three(three) __start__ --> uno; uno -.-> dos; uno -.-> subgraph_one; subgraph subgraph + subgraph_one(one) + subgraph_two(two) + subgraph_three(three) subgraph_one -.-> subgraph_two; subgraph_one -.-> subgraph_three; end @@ -1332,12 +1752,14 @@ %%{init: {'flowchart': {'curve': 'linear'}}}%% graph TD; __start__([

__start__

]):::first - inner(inner) side(side) __end__([

__end__

]):::last - __start__ --> inner; - inner --> side; + __start__ --> inner_up; + inner_up --> side; side --> __end__; + subgraph inner + inner_up(up) + end classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 classDef last fill:#bfb6fc @@ -1475,10 +1897,6 @@ graph TD; __start__([

__start__

]):::first tool_one(tool_one) - tool_two___start__(

__start__

) - tool_two_tool_two_slow(tool_two_slow) - tool_two_tool_two_fast(tool_two_fast) - tool_two___end__(

__end__

) tool_three(tool_three) __end__([

__end__

]):::last __start__ -.-> tool_one; @@ -1488,6 +1906,10 @@ __start__ -.-> tool_three; tool_three --> __end__; subgraph tool_two + tool_two___start__(

__start__

) + tool_two_tool_two_slow(tool_two_slow) + tool_two_tool_two_fast(tool_two_fast) + tool_two___end__(

__end__

) tool_two___start__ -.-> tool_two_tool_two_slow; tool_two_tool_two_slow --> tool_two___end__; tool_two___start__ -.-> tool_two_tool_two_fast; @@ -1528,7 +1950,7 @@ ''' # --- # name: test_state_graph_w_config_inherited_state_keys - '{"$defs": {"Configurable": {"properties": {"tools": {"default": null, "items": {"type": "string"}, "title": "Tools", "type": "array"}}, "title": "Configurable", "type": "object"}}, "properties": {"configurable": {"$ref": "#/$defs/Configurable", "default": null}}, "title": "LangGraphConfig", "type": "object"}' + '{"$defs": {"Config": {"properties": {"tools": {"items": {"type": "string"}, "title": "Tools", "type": "array"}}, "title": "Config", "type": "object"}}, "properties": {"configurable": {"$ref": "#/$defs/Config", "default": null}}, "title": "LangGraphConfig", "type": "object"}' # --- # name: test_state_graph_w_config_inherited_state_keys.1 '{"$defs": {"AgentAction": {"description": "Represents a request to execute an action by an agent.\\n\\nThe action consists of the name of the tool to execute and the input to pass\\nto the tool. The log is used to pass along extra information about the action.", "properties": {"tool": {"title": "Tool", "type": "string"}, "tool_input": {"anyOf": [{"type": "string"}, {"type": "object"}], "title": "Tool Input"}, "log": {"title": "Log", "type": "string"}, "type": {"const": "AgentAction", "default": "AgentAction", "enum": ["AgentAction"], "title": "Type", "type": "string"}}, "required": ["tool", "tool_input", "log"], "title": "AgentAction", "type": "object"}, "AgentFinish": {"description": "Final return value of an ActionAgent.\\n\\nAgents return an AgentFinish when they have reached a stopping condition.", "properties": {"return_values": {"title": "Return Values", "type": "object"}, "log": {"title": "Log", "type": "string"}, "type": {"const": "AgentFinish", "default": "AgentFinish", "enum": ["AgentFinish"], "title": "Type", "type": "string"}}, "required": ["return_values", "log"], "title": "AgentFinish", "type": "object"}}, "properties": {"input": {"title": "Input", "type": "string"}, "agent_outcome": {"anyOf": [{"$ref": "#/$defs/AgentAction"}, {"$ref": "#/$defs/AgentFinish"}, {"type": "null"}], "default": null, "title": "Agent Outcome"}, "intermediate_steps": {"default": null, "items": {"maxItems": 2, "minItems": 2, "prefixItems": [{"$ref": "#/$defs/AgentAction"}, {"type": "string"}], "type": "array"}, "title": "Intermediate Steps", "type": "array"}}, "required": ["input"], "title": "LangGraphInput", "type": "object"}' @@ -1542,24 +1964,24 @@ graph TD; __start__([

__start__

]):::first gp_one(gp_one) - gp_two___start__(

__start__

) - gp_two_p_one(p_one) - gp_two_p_two___start__(

__start__

) - gp_two_p_two_c_one(c_one) - gp_two_p_two_c_two(c_two) - gp_two_p_two___end__(

__end__

) - gp_two___end__(

__end__

) __end__([

__end__

]):::last __start__ --> gp_one; gp_two___end__ --> gp_one; gp_one -.  0  .-> gp_two___start__; gp_one -.  1  .-> __end__; subgraph gp_two + gp_two___start__(

__start__

) + gp_two_p_one(p_one) + gp_two___end__(

__end__

) gp_two___start__ --> gp_two_p_one; gp_two_p_two___end__ --> gp_two_p_one; gp_two_p_one -.  0  .-> gp_two_p_two___start__; gp_two_p_one -.  1  .-> gp_two___end__; subgraph p_two + gp_two_p_two___start__(

__start__

) + gp_two_p_two_c_one(c_one) + gp_two_p_two_c_two(c_two) + gp_two_p_two___end__(

__end__

) gp_two_p_two___start__ --> gp_two_p_two_c_one; gp_two_p_two_c_two --> gp_two_p_two_c_one; gp_two_p_two_c_one -.  0  .-> gp_two_p_two_c_two; @@ -1578,16 +2000,16 @@ graph TD; __start__([

__start__

]):::first p_one(p_one) - p_two___start__(

__start__

) - p_two_c_one(c_one) - p_two_c_two(c_two) - p_two___end__(

__end__

) __end__([

__end__

]):::last __start__ --> p_one; p_two___end__ --> p_one; p_one -.  0  .-> p_two___start__; p_one -.  1  .-> __end__; subgraph p_two + p_two___start__(

__start__

) + p_two_c_one(c_one) + p_two_c_two(c_two) + p_two___end__(

__end__

) p_two___start__ --> p_two_c_one; p_two_c_two --> p_two_c_one; p_two_c_one -.  0  .-> p_two_c_two; diff --git a/libs/langgraph/tests/test_large_cases.py b/libs/langgraph/tests/test_large_cases.py index f562720b8..f049e4e81 100644 --- a/libs/langgraph/tests/test_large_cases.py +++ b/libs/langgraph/tests/test_large_cases.py @@ -2827,7 +2827,7 @@ def test_state_graph_packets( } # Define decision-making logic - def should_continue(data: AgentState) -> str: + def should_continue(data: dict) -> str: assert isinstance(data["session"], httpx.Client) assert ( data["something_extra"] == "hi there" diff --git a/libs/langgraph/tests/test_pregel.py b/libs/langgraph/tests/test_pregel.py index bb5c7d972..938ee63f3 100644 --- a/libs/langgraph/tests/test_pregel.py +++ b/libs/langgraph/tests/test_pregel.py @@ -10,7 +10,7 @@ import warnings from collections import Counter, deque from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager -from dataclasses import dataclass +from dataclasses import dataclass, field from random import randrange from typing import ( Annotated, @@ -275,6 +275,61 @@ def test_checkpoint_errors() -> None: graph.invoke("", {"configurable": {"thread_id": "thread-1"}}) +def test_config_json_schema() -> None: + """Test that config json schema is generated properly.""" + chain = Channel.subscribe_to("input") | Channel.write_to("output") + + @dataclass + class Foo: + x: int + y: str = field(default="foo") + + app = Pregel( + nodes={ + "one": chain, + }, + channels={ + "ephemeral": EphemeralValue(Any), + "input": LastValue(int), + "output": LastValue(int), + }, + input_channels=["input", "ephemeral"], + output_channels="output", + config_type=Foo, + ) + + assert app.get_config_jsonschema() == { + "$defs": { + "Foo": { + "properties": { + "x": { + "title": "X", + "type": "integer", + }, + "y": { + "default": "foo", + "title": "Y", + "type": "string", + }, + }, + "required": [ + "x", + ], + "title": "Foo", + "type": "object", + }, + }, + "properties": { + "configurable": { + "$ref": "#/$defs/Foo", + "default": None, + }, + }, + "title": "LangGraphConfig", + "type": "object", + } + + def test_node_schemas_custom_output() -> None: class State(TypedDict): hello: str @@ -1444,7 +1499,7 @@ def test_imp_task(request: pytest.FixtureRequest, checkpointer_name: str) -> Non checkpointer = request.getfixturevalue(f"checkpointer_{checkpointer_name}") mapper_calls = 0 - class Config: + class Configurable: model: str @task() @@ -1454,7 +1509,7 @@ def test_imp_task(request: pytest.FixtureRequest, checkpointer_name: str) -> Non time.sleep(input / 100) return str(input) * 2 - @entrypoint(checkpointer=checkpointer, config_schema=Config) + @entrypoint(checkpointer=checkpointer, config_schema=Configurable) def graph(input: list[int]) -> list[str]: futures = [mapper(i) for i in input] mapped = [f.result() for f in futures] @@ -2839,6 +2894,139 @@ def test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic2( } +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_in_one_fan_out_state_graph_waiting_edge_custom_state_class_pydantic_input( + snapshot: SnapshotAssertion, + mocker: MockerFixture, + request: pytest.FixtureRequest, + checkpointer_name: str, +) -> None: + from pydantic import BaseModel + + checkpointer = request.getfixturevalue(f"checkpointer_{checkpointer_name}") + + def sorted_add( + x: list[str], y: Union[list[str], list[tuple[str, str]]] + ) -> list[str]: + if isinstance(y[0], tuple): + for rem, _ in y: + x.remove(rem) + y = [t[1] for t in y] + return sorted(operator.add(x, y)) + + class InnerObject(BaseModel): + yo: int + + class QueryModel(BaseModel): + query: str + + class State(QueryModel): + inner: InnerObject + answer: Optional[str] = None + docs: Annotated[list[str], sorted_add] + + class StateUpdate(BaseModel): + query: Optional[str] = None + answer: Optional[str] = None + docs: Optional[list[str]] = None + + class Input(QueryModel): + inner: InnerObject + + class Output(BaseModel): + answer: str + docs: list[str] + + def rewrite_query(data: State) -> State: + return {"query": f"query: {data.query}"} + + def analyzer_one(data: State) -> State: + return StateUpdate(query=f"analyzed: {data.query}") + + def retriever_one(data: State) -> State: + return {"docs": ["doc1", "doc2"]} + + def retriever_two(data: State) -> State: + time.sleep(0.1) + return {"docs": ["doc3", "doc4"]} + + def qa(data: State) -> State: + return {"answer": ",".join(data.docs)} + + def decider(data: State) -> str: + assert isinstance(data, State) + return "retriever_two" + + workflow = StateGraph(State, input=Input, output=Output) + + workflow.add_node("rewrite_query", rewrite_query) + workflow.add_node("analyzer_one", analyzer_one) + workflow.add_node("retriever_one", retriever_one) + workflow.add_node("retriever_two", retriever_two) + workflow.add_node("qa", qa) + + workflow.set_entry_point("rewrite_query") + workflow.add_edge("rewrite_query", "analyzer_one") + workflow.add_edge("analyzer_one", "retriever_one") + workflow.add_conditional_edges( + "rewrite_query", decider, {"retriever_two": "retriever_two"} + ) + workflow.add_edge(["retriever_one", "retriever_two"], "qa") + workflow.set_finish_point("qa") + + app = workflow.compile() + + assert app.invoke( + Input(query="what is weather in sf", inner=InnerObject(yo=1)) + ) == { + "docs": ["doc1", "doc2", "doc3", "doc4"], + "answer": "doc1,doc2,doc3,doc4", + } + + assert [ + *app.stream(Input(query="what is weather in sf", inner=InnerObject(yo=1))) + ] == [ + {"rewrite_query": {"query": "query: what is weather in sf"}}, + {"analyzer_one": {"query": "analyzed: query: what is weather in sf"}}, + {"retriever_two": {"docs": ["doc3", "doc4"]}}, + {"retriever_one": {"docs": ["doc1", "doc2"]}}, + {"qa": {"answer": "doc1,doc2,doc3,doc4"}}, + ] + + app_w_interrupt = workflow.compile( + checkpointer=checkpointer, + interrupt_after=["retriever_one"], + ) + config = {"configurable": {"thread_id": "1"}} + + assert [ + c + for c in app_w_interrupt.stream( + Input(query="what is weather in sf", inner=InnerObject(yo=1)), config + ) + ] == [ + {"rewrite_query": {"query": "query: what is weather in sf"}}, + {"analyzer_one": {"query": "analyzed: query: what is weather in sf"}}, + {"retriever_two": {"docs": ["doc3", "doc4"]}}, + {"retriever_one": {"docs": ["doc1", "doc2"]}}, + {"__interrupt__": ()}, + ] + + assert [c for c in app_w_interrupt.stream(None, config)] == [ + {"qa": {"answer": "doc1,doc2,doc3,doc4"}}, + ] + + assert app_w_interrupt.update_state( + config, {"docs": ["doc5"]}, as_node="rewrite_query" + ) == { + "configurable": { + "thread_id": "1", + "checkpoint_id": AnyStr(), + "checkpoint_ns": "", + } + } + + @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) def test_in_one_fan_out_state_graph_waiting_edge_plus_regular( request: pytest.FixtureRequest, checkpointer_name: str @@ -2905,14 +3093,24 @@ def test_in_one_fan_out_state_graph_waiting_edge_plus_regular( "answer": "doc1,doc2,doc3,doc4", } - assert [*app.stream({"query": "what is weather in sf"})] == [ - {"rewrite_query": {"query": "query: what is weather in sf"}}, - {"qa": {"answer": ""}}, - {"analyzer_one": {"query": "analyzed: query: what is weather in sf"}}, - {"retriever_two": {"docs": ["doc3", "doc4"]}}, - {"retriever_one": {"docs": ["doc1", "doc2"]}}, - {"qa": {"answer": "doc1,doc2,doc3,doc4"}}, - ] + assert [*app.stream({"query": "what is weather in sf"})] in ( + [ + {"rewrite_query": {"query": "query: what is weather in sf"}}, + {"qa": {"answer": ""}}, + {"analyzer_one": {"query": "analyzed: query: what is weather in sf"}}, + {"retriever_two": {"docs": ["doc3", "doc4"]}}, + {"retriever_one": {"docs": ["doc1", "doc2"]}}, + {"qa": {"answer": "doc1,doc2,doc3,doc4"}}, + ], + [ + {"rewrite_query": {"query": "query: what is weather in sf"}}, + {"analyzer_one": {"query": "analyzed: query: what is weather in sf"}}, + {"qa": {"answer": ""}}, + {"retriever_two": {"docs": ["doc3", "doc4"]}}, + {"retriever_one": {"docs": ["doc1", "doc2"]}}, + {"qa": {"answer": "doc1,doc2,doc3,doc4"}}, + ], + ) app_w_interrupt = workflow.compile( checkpointer=checkpointer, @@ -3371,6 +3569,59 @@ def test_subgraph_checkpoint_true( ] +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_subgraph_checkpoint_true_interrupt( + request: pytest.FixtureRequest, checkpointer_name: str +) -> None: + checkpointer = request.getfixturevalue("checkpointer_" + checkpointer_name) + + # Define subgraph + class SubgraphState(TypedDict): + # note that none of these keys are shared with the parent graph state + bar: str + baz: str + + def subgraph_node_1(state: SubgraphState): + baz_value = interrupt("Provide baz value") + return {"baz": baz_value} + + def subgraph_node_2(state: SubgraphState): + return {"bar": state["bar"] + state["baz"]} + + subgraph_builder = StateGraph(SubgraphState) + subgraph_builder.add_node(subgraph_node_1) + subgraph_builder.add_node(subgraph_node_2) + subgraph_builder.add_edge(START, "subgraph_node_1") + subgraph_builder.add_edge("subgraph_node_1", "subgraph_node_2") + subgraph = subgraph_builder.compile(checkpointer=True) + + class ParentState(TypedDict): + foo: str + + def node_1(state: ParentState): + return {"foo": "hi! " + state["foo"]} + + def node_2(state: ParentState): + response = subgraph.invoke({"bar": state["foo"]}) + return {"foo": response["bar"]} + + builder = StateGraph(ParentState) + builder.add_node("node_1", node_1) + builder.add_node("node_2", node_2) + builder.add_edge(START, "node_1") + builder.add_edge("node_1", "node_2") + + checkpointer = MemorySaver() + graph = builder.compile(checkpointer=checkpointer) + config = {"configurable": {"thread_id": "1"}} + + assert graph.invoke({"foo": "foo"}, config) == {"foo": "hi! foo"} + assert graph.get_state(config, subgraphs=True).tasks[0].state.values == { + "bar": "hi! foo" + } + assert graph.invoke(Command(resume="baz"), config) == {"foo": "hi! foobaz"} + + @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) def test_stream_subgraphs_during_execution( request: pytest.FixtureRequest, checkpointer_name: str @@ -4830,13 +5081,6 @@ def test_parent_command(request: pytest.FixtureRequest, checkpointer_name: str) "source": "loop", "writes": { "alice": { - "messages": [ - _AnyIdHumanMessage( - content="get user name", - additional_kwargs={}, - response_metadata={}, - ), - ], "user_name": "Meow", } }, @@ -6176,151 +6420,6 @@ def test_multiple_subgraphs_checkpointer( ] -def test_merging_updates_command_parent(): - # simple reducer - def append_unique(left, right): - combined = list(left) - for item in right: - if item in combined: - continue - else: - combined.append(item) - return combined - - class State(TypedDict): - foo: str - bar: Annotated[list[str], append_unique] - - # Define subgraph - def subgraph_node_1(state: State): - return Command( - goto="subgraph_node_2", - update={ - "foo": "foo", - "bar": ["subgraph_node_1"], - }, - ) - - def subgraph_node_2(state: State): - return Command( - goto="node_3", - update={"bar": ["subgraph_node_2"]}, - graph=Command.PARENT, - ) - - subgraph_builder = StateGraph(State) - subgraph_builder.add_node(subgraph_node_1) - subgraph_builder.add_node(subgraph_node_2) - subgraph_builder.add_edge(START, "subgraph_node_1") - - # Define main graph - def node_1(state: State): - return Command( - goto="node_2", - update={"bar": ["node_1"]}, - ) - - def node_3(state: State, store): - return Command( - update={"bar": ["node_3"]}, - ) - - main_builder = StateGraph(State) - main_builder.add_node("node_1", node_1) - main_builder.add_node("node_2", subgraph_builder.compile()) - main_builder.add_node("node_3", node_3) - main_builder.add_edge(START, "node_1") - main_builder.add_edge("node_2", "node_3") - main_graph = main_builder.compile() - - assert main_graph.invoke({"foo": ""}) == { - "foo": "foo", - "bar": ["node_1", "subgraph_node_1", "subgraph_node_2", "node_3"], - } - - assert list( - main_graph.stream({"foo": ""}, stream_mode="updates", subgraphs=True) - ) == [ - ((), {"node_1": {"bar": ["node_1"]}}), - ( - (AnyStr("node_2:"),), - {"subgraph_node_1": {"foo": "foo", "bar": ["subgraph_node_1"]}}, - ), - ( - (), - { - "node_2": [ - {"foo": "foo"}, - {"bar": ["node_1", "subgraph_node_1"]}, - {"bar": ["subgraph_node_2"]}, - ] - }, - ), - ((), {"node_3": {"bar": ["node_3"]}}), - ] - - -def test_merging_non_overlapping_updates_command_parent(): - # simple reducer - def append_unique(left, right): - combined = list(left) - for item in right: - if item in combined: - continue - else: - combined.append(item) - return combined - - class State(TypedDict): - foo: Annotated[list, append_unique] - - # Define subgraph - def subgraph_node_1(state: State): - return Command( - goto="subgraph_node_2", - update={ - "foo": ["bar"], - "bar": ["subgraph_node_1"], - }, - ) - - def subgraph_node_2(state: State): - return Command( - goto="node_3", - update={"bar": ["subgraph_node_2"]}, - graph=Command.PARENT, - ) - - subgraph_builder = StateGraph(State) - subgraph_builder.add_node(subgraph_node_1) - subgraph_builder.add_node(subgraph_node_2) - subgraph_builder.add_edge(START, "subgraph_node_1") - - # Define main graph - def node_1(state: State): - return Command( - goto="node_2", - update={"foo": ["foo"]}, - ) - - def node_3(state: State, store): - return Command( - update={"foo": ["baz"]}, - ) - - main_builder = StateGraph(State) - main_builder.add_node("node_1", node_1) - main_builder.add_node("node_2", subgraph_builder.compile()) - main_builder.add_node("node_3", node_3) - main_builder.add_edge(START, "node_1") - main_builder.add_edge("node_2", "node_3") - main_graph = main_builder.compile() - - assert main_graph.invoke({"foo": []}) == { - "foo": ["foo", "bar", "baz"], - } - - def test_entrypoint_output_schema_with_return_and_save() -> None: """Test output schema inference with entrypoint.final.""" @@ -6559,6 +6658,40 @@ def test_pydantic_none_state_update() -> None: assert graph.invoke({"foo": ""}) == {"foo": None} +def test_pydantic_state_mutation() -> None: + from pydantic import BaseModel, Field + + class Inner(BaseModel): + a: int = 0 + + class State(BaseModel): + inner: Inner = Inner() + outer: int = 0 + + def my_node(state: State) -> State: + state.inner.a = 5 + state.outer = 10 + return state + + graph = StateGraph(State).add_node(my_node).add_edge(START, "my_node").compile() + + assert graph.invoke({"outer": 1}) == {"outer": 10, "inner": Inner(a=5)} + + # test w/ default_factory + class State(BaseModel): + inner: Inner = Field(default_factory=Inner) + outer: int = 0 + + def my_node(state: State) -> State: + state.inner.a = 5 + state.outer = 10 + return state + + graph = StateGraph(State).add_node(my_node).add_edge(START, "my_node").compile() + + assert graph.invoke({"outer": 1}) == {"outer": 10, "inner": Inner(a=5)} + + def test_get_stream_writer() -> None: class State(TypedDict): foo: str @@ -6588,3 +6721,194 @@ def test_get_stream_writer() -> None: }, ), ] + + +def test_stream_messages_dedupe_inputs() -> None: + from langchain_core.messages import AIMessage + + def call_model(state): + return {"messages": AIMessage("hi", id="1")} + + def route(state): + return Command(goto="node_2", graph=Command.PARENT) + + subgraph = ( + StateGraph(MessagesState) + .add_node(call_model) + .add_node(route) + .add_edge(START, "call_model") + .add_edge("call_model", "route") + .compile() + ) + + graph = ( + StateGraph(MessagesState) + .add_node("node_1", subgraph) + .add_node("node_2", lambda state: state) + .add_edge(START, "node_1") + .compile() + ) + + chunks = [ + chunk + for ns, chunk in graph.stream( + {"messages": "hi"}, stream_mode="messages", subgraphs=True + ) + ] + + assert len(chunks) == 1 + assert chunks[0][0] == AIMessage("hi", id="1") + assert chunks[0][1]["langgraph_node"] == "call_model" + + +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_stream_messages_dedupe_state( + request: pytest.FixtureRequest, checkpointer_name: str +) -> None: + from langchain_core.messages import AIMessage + + checkpointer = request.getfixturevalue(f"checkpointer_{checkpointer_name}") + to_emit = [AIMessage("bye", id="1"), AIMessage("bye again", id="2")] + + def call_model(state): + return {"messages": to_emit.pop(0)} + + def route(state): + return Command(goto="node_2", graph=Command.PARENT) + + subgraph = ( + StateGraph(MessagesState) + .add_node(call_model) + .add_node(route) + .add_edge(START, "call_model") + .add_edge("call_model", "route") + .compile() + ) + + graph = ( + StateGraph(MessagesState) + .add_node("node_1", subgraph) + .add_node("node_2", lambda state: state) + .add_edge(START, "node_1") + .compile(checkpointer=checkpointer) + ) + + thread1 = {"configurable": {"thread_id": "1"}} + + chunks = [ + chunk + for ns, chunk in graph.stream( + {"messages": "hi"}, thread1, stream_mode="messages", subgraphs=True + ) + ] + + assert len(chunks) == 1 + assert chunks[0][0] == AIMessage("bye", id="1") + assert chunks[0][1]["langgraph_node"] == "call_model" + + chunks = [ + chunk + for ns, chunk in graph.stream( + {"messages": "hi again"}, + thread1, + stream_mode="messages", + subgraphs=True, + ) + ] + + assert len(chunks) == 1 + assert chunks[0][0] == AIMessage("bye again", id="2") + assert chunks[0][1]["langgraph_node"] == "call_model" + + +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_interrupt_subgraph_reenter_checkpointer_true( + request: pytest.FixtureRequest, checkpointer_name: str +) -> None: + checkpointer = request.getfixturevalue(f"checkpointer_{checkpointer_name}") + + class SubgraphState(TypedDict): + foo: str + bar: str + + class ParentState(TypedDict): + foo: str + counter: int + + called = [] + bar_values = [] + + def subnode_1(state: SubgraphState): + called.append("subnode_1") + bar_values.append(state.get("bar")) + return {"foo": "subgraph_1"} + + def subnode_2(state: SubgraphState): + called.append("subnode_2") + value = interrupt("Provide value") + value += "baz" + return {"foo": "subgraph_2", "bar": value} + + subgraph = ( + StateGraph(SubgraphState) + .add_node(subnode_1) + .add_node(subnode_2) + .add_edge(START, "subnode_1") + .add_edge("subnode_1", "subnode_2") + .compile(checkpointer=True) + ) + + def call_subgraph(state: ParentState): + called.append("call_subgraph") + return subgraph.invoke(state) + + def node(state: ParentState): + called.append("parent") + if state["counter"] < 1: + return Command( + goto="call_subgraph", update={"counter": state["counter"] + 1} + ) + + return {"foo": state["foo"] + "|" + "parent"} + + parent = ( + StateGraph(ParentState) + .add_node(call_subgraph) + .add_node(node) + .add_edge(START, "call_subgraph") + .add_edge("call_subgraph", "node") + .compile(checkpointer=checkpointer) + ) + + config = {"configurable": {"thread_id": "1"}} + assert parent.invoke({"foo": "", "counter": 0}, config) == {"foo": "", "counter": 0} + assert parent.invoke(Command(resume="bar"), config) == { + "foo": "subgraph_2", + "counter": 1, + } + assert parent.invoke(Command(resume="qux"), config) == { + "foo": "subgraph_2|parent", + "counter": 1, + } + assert called == [ + "call_subgraph", + "subnode_1", + "subnode_2", + "call_subgraph", + "subnode_2", + "parent", + "call_subgraph", + "subnode_1", + "subnode_2", + "call_subgraph", + "subnode_2", + "parent", + ] + + # invoke parent again (new turn) + assert parent.invoke({"foo": "meow", "counter": 0}, config) == { + "foo": "meow", + "counter": 0, + } + # confirm that we preserve the state values from the previous invocation + assert bar_values == [None, "barbaz", "quxbaz"] diff --git a/libs/langgraph/tests/test_pregel_async.py b/libs/langgraph/tests/test_pregel_async.py index f369a7aa7..e131ffe44 100644 --- a/libs/langgraph/tests/test_pregel_async.py +++ b/libs/langgraph/tests/test_pregel_async.py @@ -6148,13 +6148,6 @@ async def test_parent_command(checkpointer_name: str) -> None: "source": "loop", "writes": { "alice": { - "messages": [ - _AnyIdHumanMessage( - content="get user name", - additional_kwargs={}, - response_metadata={}, - ), - ], "user_name": "Meow", } }, @@ -7282,9 +7275,7 @@ async def test_multiple_subgraphs_mixed_state_graph( @NEEDS_CONTEXTVARS @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) -async def test_multiple_subgraphs_checkpointer( - request: pytest.FixtureRequest, checkpointer_name: str -) -> None: +async def test_multiple_subgraphs_checkpointer(checkpointer_name: str) -> None: async with awith_checkpointer(checkpointer_name) as checkpointer: class SubgraphState(TypedDict): @@ -7513,3 +7504,249 @@ async def test_tags_stream_mode_messages() -> None: }, ) ] + + +async def test_stream_messages_dedupe_inputs() -> None: + from langchain_core.messages import AIMessage + + async def call_model(state): + return {"messages": AIMessage("hi", id="1")} + + async def route(state): + return Command(goto="node_2", graph=Command.PARENT) + + subgraph = ( + StateGraph(MessagesState) + .add_node(call_model) + .add_node(route) + .add_edge(START, "call_model") + .add_edge("call_model", "route") + .compile() + ) + + graph = ( + StateGraph(MessagesState) + .add_node("node_1", subgraph) + .add_node("node_2", lambda state: state) + .add_edge(START, "node_1") + .compile() + ) + + chunks = [ + chunk + async for ns, chunk in graph.astream( + {"messages": "hi"}, stream_mode="messages", subgraphs=True + ) + ] + + assert len(chunks) == 1 + assert chunks[0][0] == AIMessage("hi", id="1") + assert chunks[0][1]["langgraph_node"] == "call_model" + + +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) +async def test_stream_messages_dedupe_state(checkpointer_name: str) -> None: + async with awith_checkpointer(checkpointer_name) as checkpointer: + from langchain_core.messages import AIMessage + + to_emit = [AIMessage("bye", id="1"), AIMessage("bye again", id="2")] + + async def call_model(state): + return {"messages": to_emit.pop(0)} + + async def route(state): + return Command(goto="node_2", graph=Command.PARENT) + + subgraph = ( + StateGraph(MessagesState) + .add_node(call_model) + .add_node(route) + .add_edge(START, "call_model") + .add_edge("call_model", "route") + .compile() + ) + + graph = ( + StateGraph(MessagesState) + .add_node("node_1", subgraph) + .add_node("node_2", lambda state: state) + .add_edge(START, "node_1") + .compile(checkpointer=checkpointer) + ) + + thread1 = {"configurable": {"thread_id": "1"}} + + chunks = [ + chunk + async for ns, chunk in graph.astream( + {"messages": "hi"}, thread1, stream_mode="messages", subgraphs=True + ) + ] + + assert len(chunks) == 1 + assert chunks[0][0] == AIMessage("bye", id="1") + assert chunks[0][1]["langgraph_node"] == "call_model" + + chunks = [ + chunk + async for ns, chunk in graph.astream( + {"messages": "hi again"}, + thread1, + stream_mode="messages", + subgraphs=True, + ) + ] + + assert len(chunks) == 1 + assert chunks[0][0] == AIMessage("bye again", id="2") + assert chunks[0][1]["langgraph_node"] == "call_model" + + +@NEEDS_CONTEXTVARS +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) +async def test_interrupt_subgraph_reenter_checkpointer_true( + checkpointer_name: str, +) -> None: + async with awith_checkpointer(checkpointer_name) as checkpointer: + + class SubgraphState(TypedDict): + foo: str + bar: str + + class ParentState(TypedDict): + foo: str + counter: int + + called = [] + bar_values = [] + + async def subnode_1(state: SubgraphState): + called.append("subnode_1") + bar_values.append(state.get("bar")) + return {"foo": "subgraph_1"} + + async def subnode_2(state: SubgraphState): + called.append("subnode_2") + value = interrupt("Provide value") + value += "baz" + return {"foo": "subgraph_2", "bar": value} + + subgraph = ( + StateGraph(SubgraphState) + .add_node(subnode_1) + .add_node(subnode_2) + .add_edge(START, "subnode_1") + .add_edge("subnode_1", "subnode_2") + .compile(checkpointer=True) + ) + + async def call_subgraph(state: ParentState): + called.append("call_subgraph") + return await subgraph.ainvoke(state) + + async def node(state: ParentState): + called.append("parent") + if state["counter"] < 1: + return Command( + goto="call_subgraph", update={"counter": state["counter"] + 1} + ) + + return {"foo": state["foo"] + "|" + "parent"} + + parent = ( + StateGraph(ParentState) + .add_node(call_subgraph) + .add_node(node) + .add_edge(START, "call_subgraph") + .add_edge("call_subgraph", "node") + .compile(checkpointer=checkpointer) + ) + + config = {"configurable": {"thread_id": "1"}} + assert await parent.ainvoke({"foo": "", "counter": 0}, config) == { + "foo": "", + "counter": 0, + } + assert await parent.ainvoke(Command(resume="bar"), config) == { + "foo": "subgraph_2", + "counter": 1, + } + assert await parent.ainvoke(Command(resume="qux"), config) == { + "foo": "subgraph_2|parent", + "counter": 1, + } + assert called == [ + "call_subgraph", + "subnode_1", + "subnode_2", + "call_subgraph", + "subnode_2", + "parent", + "call_subgraph", + "subnode_1", + "subnode_2", + "call_subgraph", + "subnode_2", + "parent", + ] + + # invoke parent again (new turn) + assert await parent.ainvoke({"foo": "meow", "counter": 0}, config) == { + "foo": "meow", + "counter": 0, + } + # confirm that we preserve the state values from the previous invocation + assert bar_values == [None, "barbaz", "quxbaz"] + + +@NEEDS_CONTEXTVARS +async def test_handles_multiple_interrupts_from_tasks() -> None: + @task + async def add_participant(name: str) -> str: + feedback = interrupt(f"Hey do you want to add {name}?") + + if feedback is False: + return f"The user changed their mind and doesn't want to add {name}!" + + if feedback is True: + return f"Added {name}!" + + raise ValueError("Invalid feedback") + + @entrypoint(checkpointer=MemorySaver()) + async def program(_state: Any) -> list[str]: + first = await add_participant("James") + second = await add_participant("Will") + return [first, second] + + config = {"configurable": {"thread_id": "1"}} + + result = await program.ainvoke("this is ignored", config=config) + assert result is None + + state = await program.aget_state(config=config) + assert len(state.tasks[0].interrupts) == 1 + task_interrupt = state.tasks[0].interrupts[0] + assert task_interrupt.resumable is True + assert len(task_interrupt.ns) == 2 + assert task_interrupt.ns[0].startswith("program:") + assert task_interrupt.ns[1].startswith("add_participant:") + assert task_interrupt.value == "Hey do you want to add James?" + + result = await program.ainvoke(Command(resume=True), config=config) + assert result is None + + state = await program.aget_state(config=config) + assert len(state.tasks[0].interrupts) == 1 + task_interrupt = state.tasks[0].interrupts[0] + assert task_interrupt.resumable is True + assert len(task_interrupt.ns) == 2 + assert task_interrupt.ns[0].startswith("program:") + assert task_interrupt.ns[1].startswith("add_participant:") + assert task_interrupt.value == "Hey do you want to add Will?" + + result = await program.ainvoke(Command(resume=True), config=config) + assert result is not None + assert len(result) == 2 + assert result[0] == "Added James!" + assert result[1] == "Added Will!" diff --git a/libs/langgraph/tests/test_pydantic.py b/libs/langgraph/tests/test_pydantic.py new file mode 100644 index 000000000..f1a350033 --- /dev/null +++ b/libs/langgraph/tests/test_pydantic.py @@ -0,0 +1,43 @@ +import sys +import typing + +import pydantic +import typing_extensions + +from langgraph.utils.pydantic import is_supported_by_pydantic + + +def test_is_supported_by_pydantic() -> None: + """Test if types are supported by pydantic.""" + + class TypedDictExtensions(typing_extensions.TypedDict): + x: int + + assert is_supported_by_pydantic(TypedDictExtensions) is True + + class VanillaClass: + x: int + + assert is_supported_by_pydantic(VanillaClass) is False + + class BuiltinTypedDict(typing.TypedDict): # noqa: TID251 + x: int + + if sys.version_info >= (3, 12): + assert is_supported_by_pydantic(BuiltinTypedDict) is True + else: + assert is_supported_by_pydantic(BuiltinTypedDict) is False + + class PydanticModel(pydantic.BaseModel): + x: int + + assert is_supported_by_pydantic(PydanticModel) is True + + if hasattr(pydantic, "v1"): + + class PydanticModelV1(pydantic.v1.BaseModel): + x: int + + assert is_supported_by_pydantic(PydanticModelV1) is False + + assert is_supported_by_pydantic(int) is False diff --git a/libs/langgraph/tests/test_state.py b/libs/langgraph/tests/test_state.py index 5af406669..d85ccef94 100644 --- a/libs/langgraph/tests/test_state.py +++ b/libs/langgraph/tests/test_state.py @@ -1,4 +1,5 @@ import inspect +import operator import warnings from dataclasses import dataclass, field from typing import Annotated as Annotated2 @@ -328,3 +329,74 @@ def test__get_node_name() -> None: # class method assert _get_node_name(MyClass().class_method) == "class_method" + + +def test_input_schema_conditional_edge(): + class OverallState(TypedDict): + foo: Annotated[int, operator.add] + bar: str + + class PrivateState(TypedDict): + baz: str + + builder = StateGraph(OverallState) + + def node_1(state: OverallState): + return {"foo": 1, "baz": "bar"} + + def node_2(state: PrivateState): + return {"foo": 1, "bar": state["baz"], "something_else": "meow"} + + def node_3(state: OverallState): + return {"foo": 1} + + def router(state: OverallState): + assert state == {"foo": 2, "bar": "bar"} + if state["foo"] == 2: + return "node_3" + else: + return "__end__" + + builder.add_node(node_1) + builder.add_node(node_2) + builder.add_node(node_3) + builder.add_conditional_edges("node_2", router) + builder.add_edge("__start__", "node_1") + builder.add_edge("node_1", "node_2") + graph = builder.compile() + assert graph.invoke({"foo": 0}) == {"foo": 3, "bar": "bar"} + + +def test_private_input_schema_conditional_edge(): + class OverallState(TypedDict): + foo: Annotated[int, operator.add] + bar: str + + class RouterState(TypedDict): + baz: str + + class Node2State(TypedDict): + foo: Annotated[int, operator.add] + baz: str + + builder = StateGraph(OverallState) + + def node_1(state: OverallState): + return {"foo": 1, "baz": "meow"} + + def node_2(state: Node2State): + return {"foo": 1, "bar": state["baz"]} + + def router(state: RouterState): + assert state == {"baz": "meow"} + if state["baz"] == "meow": + return "node_2" + else: + return "__end__" + + builder.add_node(node_1) + builder.add_node(node_2) + builder.add_conditional_edges("node_1", router) + builder.add_edge("__start__", "node_1") + graph = builder.compile() + assert graph.invoke({"foo": 0}) == {"foo": 2, "bar": "meow"} diff --git a/libs/prebuilt/LICENSE b/libs/prebuilt/LICENSE new file mode 100644 index 000000000..fc0602fee --- /dev/null +++ b/libs/prebuilt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 LangChain, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/prebuilt/Makefile b/libs/prebuilt/Makefile new file mode 100644 index 000000000..08cd38c83 --- /dev/null +++ b/libs/prebuilt/Makefile @@ -0,0 +1,78 @@ +.PHONY: all format lint test test_watch integration_tests spell_check spell_fix benchmark profile + +# Default target executed when no arguments are given to make. +all: help + +###################### +# TESTING AND COVERAGE +###################### + +start-postgres: + docker compose -f tests/compose-postgres.yml up -V --force-recreate --wait --remove-orphans + +stop-postgres: + docker compose -f tests/compose-postgres.yml down -v + +TEST ?= . + +test: + make start-postgres && poetry run pytest $(TEST); \ + EXIT_CODE=$$?; \ + make stop-postgres; \ + exit $$EXIT_CODE + +test_watch: + make start-postgres && poetry run ptw $(TEST); \ + EXIT_CODE=$$?; \ + make stop-postgres; \ + exit $$EXIT_CODE + +###################### +# LINTING AND FORMATTING +###################### + +# Define a variable for Python and notebook files. +PYTHON_FILES=. +MYPY_CACHE=.mypy_cache +lint format: PYTHON_FILES=. +lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --relative --diff-filter=d main . | grep -E '\.py$$|\.ipynb$$') +lint_package: PYTHON_FILES=langgraph +lint_tests: PYTHON_FILES=tests +lint_tests: MYPY_CACHE=.mypy_cache_test + +lint lint_diff lint_package lint_tests: + poetry run ruff check . + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check --select I $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) + [ "$(PYTHON_FILES)" = "" ] || poetry run mypy langgraph --cache-dir $(MYPY_CACHE) + +format format_diff: + poetry run ruff format $(PYTHON_FILES) + poetry run ruff check --select I --fix $(PYTHON_FILES) + +spell_check: + poetry run codespell --toml pyproject.toml + +spell_fix: + poetry run codespell --toml pyproject.toml -w + + +###################### +# HELP +###################### + +help: + @echo '====================' + @echo '-- DOCUMENTATION --' + + @echo '-- LINTING --' + @echo 'format - run code formatters' + @echo 'lint - run linters' + @echo 'spell_check - run codespell on the project' + @echo 'spell_fix - run codespell on the project and fix the errors' + @echo '-- TESTS --' + @echo 'coverage - run unit tests and generate coverage report' + @echo 'test - run unit tests' + @echo 'test TEST_FILE= - run all tests in file' + @echo 'test_watch - run unit tests in watch mode' diff --git a/libs/prebuilt/README.md b/libs/prebuilt/README.md new file mode 100644 index 000000000..6a7d1e1a6 --- /dev/null +++ b/libs/prebuilt/README.md @@ -0,0 +1,117 @@ +# LangGraph Prebuilt + +This library defines high-level APIs for creating and executing LangGraph agents and tools. + +> [!IMPORTANT] +> This library is meant to be bundled with `langgraph`, don't install it directly + +## Agents + +`langgraph-prebuilt` provides an [implementation](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent) of a tool-calling [ReAct-style](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-implementation) agent - `create_react_agent`: + +```bash +pip install langchain-anthropic +``` + +```python +from langchain_anthropic import ChatAnthropic +from langgraph.prebuilt import create_react_agent + +# Define the tools for the agent to use +def search(query: str): + """Call to surf the web.""" + # This is a placeholder, but don't tell the LLM that... + if "sf" in query.lower() or "san francisco" in query.lower(): + return "It's 60 degrees and foggy." + return "It's 90 degrees and sunny." + +tools = [search] +model = ChatAnthropic(model="claude-3-7-sonnet-latest") + +app = create_react_agent(model, tools) +# run the agent +app.invoke( + {"messages": [{"role": "user", "content": "what is the weather in sf"}]}, +) +``` + +## Tools + +### ToolNode + +`langgraph-prebuilt` provides an [implementation](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode) of a node that executes tool calls - `ToolNode`: + +```python +from langgraph.prebuilt import ToolNode +from langchain_core.messages import AIMessage + +def search(query: str): + """Call to surf the web.""" + # This is a placeholder, but don't tell the LLM that... + if "sf" in query.lower() or "san francisco" in query.lower(): + return "It's 60 degrees and foggy." + return "It's 90 degrees and sunny." + +tool_node = ToolNode([search]) +tool_calls = [{"name": "search", "args": {"query": "what is the weather in sf"}, "id": "1"}] +ai_message = AIMessage(content="", tool_calls=tool_calls) +# execute tool call +tool_node.invoke({"messages": [ai_message]}) +``` + +### ValidationNode + +`langgraph-prebuilt` provides an [implementation](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_validator.ValidationNode) of a node that validates tool calls against a pydantic schema - `ValidationNode`: + +```python +from pydantic import BaseModel, field_validator +from langgraph.prebuilt import ValidationNode +from langchain_core.messages import AIMessage + + +class SelectNumber(BaseModel): + a: int + + @field_validator("a") + def a_must_be_meaningful(cls, v): + if v != 37: + raise ValueError("Only 37 is allowed") + return v + +validation_node = ValidationNode([SelectNumber]) +validation_node.invoke({ + "messages": [AIMessage("", tool_calls=[{"name": "SelectNumber", "args": {"a": 42}, "id": "1"}])] +}) +``` + +## Agent Inbox + +The library contains schemas for using the [Agent Inbox](https://github.com/langchain-ai/agent-inbox) with LangGraph agents. Learn more about how to use Agent Inbox [here](https://github.com/langchain-ai/agent-inbox#interrupts). + +```python +from langgraph.types import interrupt +from langgraph.prebuilt.interrupt import HumanInterrupt, HumanResponse + +def my_graph_function(): + # Extract the last tool call from the `messages` field in the state + tool_call = state["messages"][-1].tool_calls[0] + # Create an interrupt + request: HumanInterrupt = { + "action_request": { + "action": tool_call['name'], + "args": tool_call['args'] + }, + "config": { + "allow_ignore": True, + "allow_respond": True, + "allow_edit": False, + "allow_accept": False + }, + "description": _generate_email_markdown(state) # Generate a detailed markdown description. + } + # Send the interrupt request inside a list, and extract the first response + response = interrupt([request])[0] + if response['type'] == "response": + # Do something with the response + ... +``` \ No newline at end of file diff --git a/libs/langgraph/langgraph/prebuilt/__init__.py b/libs/prebuilt/langgraph/prebuilt/__init__.py similarity index 80% rename from libs/langgraph/langgraph/prebuilt/__init__.py rename to libs/prebuilt/langgraph/prebuilt/__init__.py index 671804258..0b9581053 100644 --- a/libs/langgraph/langgraph/prebuilt/__init__.py +++ b/libs/prebuilt/langgraph/prebuilt/__init__.py @@ -1,7 +1,6 @@ """langgraph.prebuilt exposes a higher-level API for creating and executing agents and tools.""" from langgraph.prebuilt.chat_agent_executor import create_react_agent -from langgraph.prebuilt.tool_executor import ToolExecutor, ToolInvocation from langgraph.prebuilt.tool_node import ( InjectedState, InjectedStore, @@ -12,8 +11,6 @@ from langgraph.prebuilt.tool_validator import ValidationNode __all__ = [ "create_react_agent", - "ToolExecutor", - "ToolInvocation", "ToolNode", "tools_condition", "ValidationNode", diff --git a/libs/langgraph/langgraph/prebuilt/chat_agent_executor.py b/libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py similarity index 88% rename from libs/langgraph/langgraph/prebuilt/chat_agent_executor.py rename to libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py index 1c94f08c1..0fead9c1e 100644 --- a/libs/langgraph/langgraph/prebuilt/chat_agent_executor.py +++ b/libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py @@ -10,6 +10,7 @@ from typing import ( TypeVar, Union, cast, + get_type_hints, ) from langchain_core.language_models import ( @@ -22,6 +23,7 @@ from langchain_core.runnables import ( Runnable, RunnableBinding, RunnableConfig, + RunnableSequence, ) from langchain_core.tools import BaseTool from pydantic import BaseModel @@ -32,7 +34,6 @@ from langgraph.graph import END, StateGraph from langgraph.graph.graph import CompiledGraph from langgraph.graph.message import add_messages from langgraph.managed import IsLastStep, RemainingSteps -from langgraph.prebuilt.tool_executor import ToolExecutor from langgraph.prebuilt.tool_node import ToolNode from langgraph.store.base import BaseStore from langgraph.types import Checkpointer, Send @@ -57,24 +58,31 @@ class AgentState(TypedDict): remaining_steps: RemainingSteps +class AgentStatePydantic(BaseModel): + """The state of the agent.""" + + messages: Annotated[Sequence[BaseMessage], add_messages] + + remaining_steps: RemainingSteps = 25 + + class AgentStateWithStructuredResponse(AgentState): """The state of the agent with a structured response.""" structured_response: StructuredResponse -StateSchema = TypeVar("StateSchema", bound=AgentState) +class AgentStateWithStructuredResponsePydantic(AgentStatePydantic): + """The state of the agent with a structured response.""" + + structured_response: StructuredResponse + + +StateSchema = TypeVar("StateSchema", bound=Union[AgentState, AgentStatePydantic]) StateSchemaType = Type[StateSchema] PROMPT_RUNNABLE_NAME = "Prompt" -MessagesModifier = Union[ - SystemMessage, - str, - Callable[[Sequence[BaseMessage]], LanguageModelInput], - Runnable[Sequence[BaseMessage], LanguageModelInput], -] - Prompt = Union[ SystemMessage, str, @@ -83,21 +91,29 @@ Prompt = Union[ ] +def _get_state_value(state: StateSchema, key: str, default: Any = None) -> Any: + return ( + state.get(key, default) + if isinstance(state, dict) + else getattr(state, key, default) + ) + + def _get_prompt_runnable(prompt: Optional[Prompt]) -> Runnable: prompt_runnable: Runnable if prompt is None: prompt_runnable = RunnableCallable( - lambda state: state["messages"], name=PROMPT_RUNNABLE_NAME + lambda state: _get_state_value(state, "messages"), name=PROMPT_RUNNABLE_NAME ) elif isinstance(prompt, str): _system_message: BaseMessage = SystemMessage(content=prompt) prompt_runnable = RunnableCallable( - lambda state: [_system_message] + state["messages"], + lambda state: [_system_message] + _get_state_value(state, "messages"), name=PROMPT_RUNNABLE_NAME, ) elif isinstance(prompt, SystemMessage): prompt_runnable = RunnableCallable( - lambda state: [prompt] + state["messages"], + lambda state: [prompt] + _get_state_value(state, "messages"), name=PROMPT_RUNNABLE_NAME, ) elif inspect.iscoroutinefunction(prompt): @@ -119,43 +135,20 @@ def _get_prompt_runnable(prompt: Optional[Prompt]) -> Runnable: return prompt_runnable -def _convert_messages_modifier_to_prompt( - messages_modifier: MessagesModifier, -) -> Prompt: - prompt: Prompt - if isinstance(messages_modifier, (str, SystemMessage)): - return messages_modifier - elif callable(messages_modifier): - - def prompt(state: AgentState) -> Sequence[BaseMessage]: - return messages_modifier(state["messages"]) - - return prompt - elif isinstance(messages_modifier, Runnable): - prompt = (lambda state: state["messages"]) | messages_modifier - return prompt - raise ValueError( - f"Got unexpected type for `messages_modifier`: {type(messages_modifier)}" - ) - - def _convert_modifier_to_prompt(func: F) -> F: - """Decorator that converts state_modifier/messages_modifier kwargs to prompt kwarg.""" + """Decorator that converts state_modifier kwarg to prompt kwarg.""" @functools.wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: prompt = kwargs.get("prompt") state_modifier = kwargs.pop("state_modifier", None) - messages_modifier = kwargs.pop("messages_modifier", None) - if sum(p is not None for p in (prompt, state_modifier, messages_modifier)) > 1: + if sum(p is not None for p in (prompt, state_modifier)) > 1: raise ValueError( - "Expected only one of prompt, state_modifier, or messages_modifier, got multiple values" + "Expected only one of (prompt, state_modifier), got multiple values" ) if state_modifier is not None: prompt = state_modifier - elif messages_modifier is not None: - prompt = _convert_messages_modifier_to_prompt(messages_modifier) kwargs["prompt"] = prompt return func(*args, **kwargs) @@ -164,6 +157,16 @@ def _convert_modifier_to_prompt(func: F) -> F: def _should_bind_tools(model: LanguageModelLike, tools: Sequence[BaseTool]) -> bool: + if isinstance(model, RunnableSequence): + model = next( + ( + step + for step in model.steps + if isinstance(step, (RunnableBinding, BaseChatModel)) + ), + model, + ) + if not isinstance(model, RunnableBinding): return True @@ -199,6 +202,16 @@ def _should_bind_tools(model: LanguageModelLike, tools: Sequence[BaseTool]) -> b def _get_model(model: LanguageModelLike) -> BaseChatModel: """Get the underlying model from a RunnableBinding or return the model itself.""" + if isinstance(model, RunnableSequence): + model = next( + ( + step + for step in model.steps + if isinstance(step, (RunnableBinding, BaseChatModel)) + ), + model, + ) + if isinstance(model, RunnableBinding): model = model.bound @@ -244,7 +257,7 @@ def _validate_chat_history( @_convert_modifier_to_prompt def create_react_agent( model: Union[str, LanguageModelLike], - tools: Union[ToolExecutor, Sequence[BaseTool], ToolNode], + tools: Union[Sequence[BaseTool], ToolNode], *, prompt: Optional[Prompt] = None, response_format: Optional[ @@ -264,7 +277,7 @@ def create_react_agent( Args: model: The `LangChain` chat model that supports tool calling. - tools: A list of tools, a ToolExecutor, or a ToolNode instance. + tools: A list of tools or a ToolNode instance. If an empty list is provided, the agent will consist of a single LLM node without tool calling. prompt: An optional prompt for the LLM. Can take a few different forms: @@ -273,8 +286,6 @@ def create_react_agent( - Callable: This function should take in full graph state and the output is then passed to the language model. - Runnable: This runnable should take in full graph state and the output is then passed to the language model. - !!! Note - Prior to `v0.2.68`, the prompt was set using `state_modifier` / `messages_modifier` parameters. response_format: An optional schema for the final agent output. If provided, output will be formatted to match the given schema and returned in the 'structured_response' state key. @@ -295,7 +306,7 @@ def create_react_agent( The graph will make a separate call to the LLM to generate the structured response after the agent loop is finished. This is not the only strategy to get structured responses, see more options in [this guide](https://langchain-ai.github.io/langgraph/how-tos/react-agent-structured-output/). state_schema: An optional state schema that defines graph state. - Must have `messages` and `is_last_step` keys. + Must have `messages` and `remaining_steps` keys. Defaults to `AgentState` that defines those two keys. config_schema: An optional schema for configuration. Use this to expose configurable parameters via agent.config_specs. @@ -607,7 +618,8 @@ def create_react_agent( if response_format is not None: required_keys.add("structured_response") - if missing_keys := required_keys - set(state_schema.__annotations__): + schema_keys = set(get_type_hints(state_schema)) + if missing_keys := required_keys - set(schema_keys): raise ValueError(f"Missing required key(s) {missing_keys} in state_schema") if state_schema is None: @@ -617,10 +629,7 @@ def create_react_agent( else AgentState ) - if isinstance(tools, ToolExecutor): - tool_classes: Sequence[BaseTool] = tools.tools - tool_node = ToolNode(tool_classes) - elif isinstance(tools, ToolNode): + if isinstance(tools, ToolNode): tool_classes = list(tools.tools_by_name.values()) tool_node = tools else: @@ -651,35 +660,34 @@ def create_react_agent( # our graph needs to check if these were called should_return_direct = {t.name for t in tool_classes if t.return_direct} - # Define the function that calls the model - def call_model(state: AgentState, config: RunnableConfig) -> AgentState: - _validate_chat_history(state["messages"]) - response = cast(AIMessage, model_runnable.invoke(state, config)) - # add agent name to the AIMessage - response.name = name + def _are_more_steps_needed(state: StateSchema, response: BaseMessage) -> bool: has_tool_calls = isinstance(response, AIMessage) and response.tool_calls all_tools_return_direct = ( all(call["name"] in should_return_direct for call in response.tool_calls) if isinstance(response, AIMessage) else False ) - if ( - ( - "remaining_steps" not in state - and state.get("is_last_step", False) - and has_tool_calls - ) + remaining_steps = _get_state_value(state, "remaining_steps", None) + is_last_step = _get_state_value(state, "is_last_step", False) + return ( + (remaining_steps is None and is_last_step and has_tool_calls) or ( - "remaining_steps" in state - and state["remaining_steps"] < 1 + remaining_steps is not None + and remaining_steps < 1 and all_tools_return_direct ) - or ( - "remaining_steps" in state - and state["remaining_steps"] < 2 - and has_tool_calls - ) - ): + or (remaining_steps is not None and remaining_steps < 2 and has_tool_calls) + ) + + # Define the function that calls the model + def call_model(state: StateSchema, config: RunnableConfig) -> StateSchema: + messages = _get_state_value(state, "messages") + _validate_chat_history(messages) + response = cast(AIMessage, model_runnable.invoke(state, config)) + # add agent name to the AIMessage + response.name = name + + if _are_more_steps_needed(state, response): return { "messages": [ AIMessage( @@ -691,34 +699,13 @@ def create_react_agent( # We return a list, because this will get added to the existing list return {"messages": [response]} - async def acall_model(state: AgentState, config: RunnableConfig) -> AgentState: - _validate_chat_history(state["messages"]) + async def acall_model(state: StateSchema, config: RunnableConfig) -> StateSchema: + messages = _get_state_value(state, "messages") + _validate_chat_history(messages) response = cast(AIMessage, await model_runnable.ainvoke(state, config)) # add agent name to the AIMessage response.name = name - has_tool_calls = isinstance(response, AIMessage) and response.tool_calls - all_tools_return_direct = ( - all(call["name"] in should_return_direct for call in response.tool_calls) - if isinstance(response, AIMessage) - else False - ) - if ( - ( - "remaining_steps" not in state - and state.get("is_last_step", False) - and has_tool_calls - ) - or ( - "remaining_steps" in state - and state["remaining_steps"] < 1 - and all_tools_return_direct - ) - or ( - "remaining_steps" in state - and state["remaining_steps"] < 2 - and has_tool_calls - ) - ): + if _are_more_steps_needed(state, response): return { "messages": [ AIMessage( @@ -731,11 +718,11 @@ def create_react_agent( return {"messages": [response]} def generate_structured_response( - state: AgentState, config: RunnableConfig - ) -> AgentState: + state: StateSchema, config: RunnableConfig + ) -> StateSchema: # NOTE: we exclude the last message because there is enough information # for the LLM to generate the structured response - messages = state["messages"][:-1] + messages = _get_state_value(state, "messages")[:-1] structured_response_schema = response_format if isinstance(response_format, tuple): system_prompt, structured_response_schema = response_format @@ -748,11 +735,11 @@ def create_react_agent( return {"structured_response": response} async def agenerate_structured_response( - state: AgentState, config: RunnableConfig - ) -> AgentState: + state: StateSchema, config: RunnableConfig + ) -> StateSchema: # NOTE: we exclude the last message because there is enough information # for the LLM to generate the structured response - messages = state["messages"][:-1] + messages = _get_state_value(state, "messages")[:-1] structured_response_schema = response_format if isinstance(response_format, tuple): system_prompt, structured_response_schema = response_format @@ -788,8 +775,8 @@ def create_react_agent( ) # Define the function that determines whether to continue or not - def should_continue(state: AgentState) -> Union[str, list]: - messages = state["messages"] + def should_continue(state: StateSchema) -> Union[str, list]: + messages = _get_state_value(state, "messages") last_message = messages[-1] # If there is no function call, then we finish if not isinstance(last_message, AIMessage) or not last_message.tool_calls: @@ -839,8 +826,8 @@ def create_react_agent( path_map=should_continue_destinations, ) - def route_tool_responses(state: AgentState) -> Literal["agent", "__end__"]: - for m in reversed(state["messages"]): + def route_tool_responses(state: StateSchema) -> Literal["agent", "__end__"]: + for m in reversed(_get_state_value(state, "messages")): if not isinstance(m, ToolMessage): break if m.name in should_return_direct: @@ -872,4 +859,7 @@ __all__ = [ "create_react_agent", "create_tool_calling_executor", "AgentState", + "AgentStatePydantic", + "AgentStateWithStructuredResponse", + "AgentStateWithStructuredResponsePydantic", ] diff --git a/libs/langgraph/langgraph/prebuilt/interrupt.py b/libs/prebuilt/langgraph/prebuilt/interrupt.py similarity index 100% rename from libs/langgraph/langgraph/prebuilt/interrupt.py rename to libs/prebuilt/langgraph/prebuilt/interrupt.py diff --git a/libs/prebuilt/langgraph/prebuilt/py.typed b/libs/prebuilt/langgraph/prebuilt/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/prebuilt/tool_node.py b/libs/prebuilt/langgraph/prebuilt/tool_node.py similarity index 100% rename from libs/langgraph/langgraph/prebuilt/tool_node.py rename to libs/prebuilt/langgraph/prebuilt/tool_node.py diff --git a/libs/langgraph/langgraph/prebuilt/tool_validator.py b/libs/prebuilt/langgraph/prebuilt/tool_validator.py similarity index 93% rename from libs/langgraph/langgraph/prebuilt/tool_validator.py rename to libs/prebuilt/langgraph/prebuilt/tool_validator.py index 3239905b6..70796a8d1 100644 --- a/libs/langgraph/langgraph/prebuilt/tool_validator.py +++ b/libs/prebuilt/langgraph/prebuilt/tool_validator.py @@ -29,6 +29,7 @@ from langchain_core.runnables import ( ) from langchain_core.runnables.config import get_executor_for_config from langchain_core.tools import BaseTool, create_schema_from_function +from langchain_core.utils.pydantic import is_basemodel_subclass from pydantic import BaseModel, ValidationError from pydantic.v1 import BaseModel as BaseModelV1 from pydantic.v1 import ValidationError as ValidationErrorV1 @@ -78,7 +79,7 @@ class ValidationNode(RunnableCallable): >>> from typing_extensions import TypedDict ... >>> from langchain_anthropic import ChatAnthropic - >>> from pydantic import BaseModel, validator + >>> from pydantic import BaseModel, field_validator ... >>> from langgraph.graph import END, START, StateGraph >>> from langgraph.prebuilt import ValidationNode @@ -88,18 +89,15 @@ class ValidationNode(RunnableCallable): >>> class SelectNumber(BaseModel): ... a: int ... - ... @validator("a") + ... @field_validator("a") ... def a_must_be_meaningful(cls, v): ... if v != 37: ... raise ValueError("Only 37 is allowed") ... return v ... ... - >>> class State(TypedDict): - ... messages: Annotated[list, add_messages] - ... - >>> builder = StateGraph(State) - >>> llm = ChatAnthropic(model="claude-3-haiku-20240307").bind_tools([SelectNumber]) + >>> builder = StateGraph(Annotated[list, add_messages]) + >>> llm = ChatAnthropic(model="claude-3-5-haiku-latest").bind_tools([SelectNumber]) >>> builder.add_node("model", llm) >>> builder.add_node("validation", ValidationNode([SelectNumber])) >>> builder.add_edge(START, "model") @@ -177,6 +175,13 @@ class ValidationNode(RunnableCallable): raise ValueError( f"Tool {schema.name} does not have an args_schema defined." ) + elif not isinstance( + schema.args_schema, type + ) or not is_basemodel_subclass(schema.args_schema): + raise ValueError( + "Validation node only works with tools that have a pydantic BaseModel args_schema. " + f"Got {schema.name} with args_schema: {schema.args_schema}." + ) self.schemas_by_name[schema.name] = schema.args_schema elif isinstance(schema, type) and issubclass( schema, (BaseModel, BaseModelV1) diff --git a/libs/prebuilt/poetry.lock b/libs/prebuilt/poetry.lock new file mode 100644 index 000000000..3000e6ae7 --- /dev/null +++ b/libs/prebuilt/poetry.lock @@ -0,0 +1,1476 @@ +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. + +[[package]] +name = "aiosqlite" +version = "0.20.0" +description = "asyncio bridge to the standard sqlite3 module" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "aiosqlite-0.20.0-py3-none-any.whl", hash = "sha256:36a1deaca0cac40ebe32aac9977a6e2bbc7f5189f23f4a54d5908986729e5bd6"}, + {file = "aiosqlite-0.20.0.tar.gz", hash = "sha256:6d35c8c256637f4672f843c31021464090805bf925385ac39473fb16eaaca3d7"}, +] + +[package.dependencies] +typing_extensions = ">=4.0" + +[package.extras] +dev = ["attribution (==1.7.0)", "black (==24.2.0)", "coverage[toml] (==7.4.1)", "flake8 (==7.0.0)", "flake8-bugbear (==24.2.6)", "flit (==3.9.0)", "mypy (==1.8.0)", "ufmt (==2.3.0)", "usort (==1.0.8.post1)"] +docs = ["sphinx (==7.2.6)", "sphinx-mdinclude (==0.5.3)"] + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.8.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, + {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +trio = ["trio (>=0.26.1)"] + +[[package]] +name = "certifi" +version = "2025.1.31" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +groups = ["main", "dev"] +files = [ + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +markers = "platform_python_implementation == \"PyPy\"" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.4.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, +] + +[[package]] +name = "codespell" +version = "2.4.1" +description = "Fix common misspellings in text files" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425"}, + {file = "codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5"}, +] + +[package.extras] +dev = ["Pygments", "build", "chardet", "pre-commit", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli", "twine"] +hard-encoding-detection = ["chardet"] +toml = ["tomli"] +types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "sys_platform == \"win32\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.7" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +groups = ["main", "dev"] +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +description = "Apply JSON-Patches (RFC 6902)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +groups = ["main", "dev"] +files = [ + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, +] + +[package.dependencies] +jsonpointer = ">=1.9" + +[[package]] +name = "jsonpointer" +version = "3.0.0" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, + {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, +] + +[[package]] +name = "langchain-core" +version = "0.3.40" +description = "Building applications with LLMs through composability" +optional = false +python-versions = "<4.0,>=3.9" +groups = ["main", "dev"] +files = [ + {file = "langchain_core-0.3.40-py3-none-any.whl", hash = "sha256:9f31358741f10a13db8531e8288b8a5ae91904018c5c2e6f739d6645a98fca03"}, + {file = "langchain_core-0.3.40.tar.gz", hash = "sha256:893a238b38491967c804662c1ec7c3e6ebaf223d1125331249c3cf3862ff2746"}, +] + +[package.dependencies] +jsonpatch = ">=1.33,<2.0" +langsmith = ">=0.1.125,<0.4" +packaging = ">=23.2,<25" +pydantic = [ + {version = ">=2.5.2,<3.0.0", markers = "python_full_version < \"3.12.4\""}, + {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, +] +PyYAML = ">=5.3" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" +typing-extensions = ">=4.7" + +[[package]] +name = "langgraph" +version = "0.3.0" +description = "Building stateful, multi-actor applications with LLMs" +optional = false +python-versions = ">=3.9.0,<4.0" +groups = ["dev"] +files = [] +develop = true + +[package.dependencies] +langchain-core = ">=0.1,<0.4" +langgraph-checkpoint = "^2.0.10" +langgraph-sdk = "^0.1.42" + +[package.source] +type = "directory" +url = "../langgraph" + +[[package]] +name = "langgraph-checkpoint" +version = "2.0.16" +description = "Library with base interfaces for LangGraph checkpoint savers." +optional = false +python-versions = "^3.9.0,<4.0" +groups = ["main", "dev"] +files = [] +develop = true + +[package.dependencies] +langchain-core = ">=0.2.38,<0.4" +msgpack = "^1.1.0" + +[package.source] +type = "directory" +url = "../checkpoint" + +[[package]] +name = "langgraph-checkpoint-postgres" +version = "2.0.15" +description = "Library with a Postgres implementation of LangGraph checkpoint saver." +optional = false +python-versions = "^3.9.0,<4.0" +groups = ["dev"] +files = [] +develop = true + +[package.dependencies] +langgraph-checkpoint = "^2.0.15" +orjson = ">=3.10.1" +psycopg = "^3.2.0" +psycopg-pool = "^3.2.0" + +[package.source] +type = "directory" +url = "../checkpoint-postgres" + +[[package]] +name = "langgraph-checkpoint-sqlite" +version = "2.0.5" +description = "Library with a SQLite implementation of LangGraph checkpoint saver." +optional = false +python-versions = "^3.9.0" +groups = ["dev"] +files = [] +develop = true + +[package.dependencies] +aiosqlite = ">=0.20,<0.22" +langgraph-checkpoint = "^2.0.15" + +[package.source] +type = "directory" +url = "../checkpoint-sqlite" + +[[package]] +name = "langgraph-sdk" +version = "0.1.53" +description = "SDK for interacting with LangGraph API" +optional = false +python-versions = "<4.0.0,>=3.9.0" +groups = ["dev"] +files = [ + {file = "langgraph_sdk-0.1.53-py3-none-any.whl", hash = "sha256:4fab62caad73661ffe4c3ababedcd0d7bfaaba986bee4416b9c28948458a3af5"}, + {file = "langgraph_sdk-0.1.53.tar.gz", hash = "sha256:12906ed965905fa27e0c28d9fa07dc6fd89e6895ff321ff049fdf3965d057cc4"}, +] + +[package.dependencies] +httpx = ">=0.25.2" +orjson = ">=3.10.1" + +[[package]] +name = "langsmith" +version = "0.3.11" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = "<4.0,>=3.9" +groups = ["main", "dev"] +files = [ + {file = "langsmith-0.3.11-py3-none-any.whl", hash = "sha256:0cca22737ef07d3b038a437c141deda37e00add56022582680188b681bec095e"}, + {file = "langsmith-0.3.11.tar.gz", hash = "sha256:ddf29d24352e99de79c9618aaf95679214324e146c5d3d9475a7ddd2870018b1"}, +] + +[package.dependencies] +httpx = ">=0.23.0,<1" +orjson = {version = ">=3.9.14,<4.0.0", markers = "platform_python_implementation != \"PyPy\""} +packaging = ">=23.2" +pydantic = [ + {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, + {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, +] +requests = ">=2,<3" +requests-toolbelt = ">=1.0.0,<2.0.0" +zstandard = ">=0.23.0,<0.24.0" + +[package.extras] +langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"] +pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4,<14.0.0)"] + +[[package]] +name = "msgpack" +version = "1.1.0" +description = "MessagePack serializer" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, + {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, + {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"}, + {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"}, + {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, + {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, + {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, + {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, + {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, + {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, + {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"}, + {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"}, + {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"}, + {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"}, + {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"}, + {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, +] + +[[package]] +name = "mypy" +version = "1.15.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"}, + {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"}, + {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"}, + {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"}, + {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"}, + {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"}, + {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"}, + {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"}, + {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"}, + {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"}, + {file = "mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078"}, + {file = "mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba"}, + {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5"}, + {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b"}, + {file = "mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2"}, + {file = "mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980"}, + {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"}, + {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"}, +] + +[package.dependencies] +mypy_extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing_extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "orjson" +version = "3.10.15" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf"}, + {file = "orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182"}, + {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e"}, + {file = "orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab"}, + {file = "orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806"}, + {file = "orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13"}, + {file = "orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388"}, + {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c"}, + {file = "orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e"}, + {file = "orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e"}, + {file = "orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41"}, + {file = "orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7"}, + {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a"}, + {file = "orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665"}, + {file = "orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa"}, + {file = "orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e"}, + {file = "orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561"}, + {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825"}, + {file = "orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890"}, + {file = "orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf"}, + {file = "orjson-3.10.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e8afd6200e12771467a1a44e5ad780614b86abb4b11862ec54861a82d677746"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9a18c500f19273e9e104cca8c1f0b40a6470bcccfc33afcc088045d0bf5ea6"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb00b7bfbdf5d34a13180e4805d76b4567025da19a197645ca746fc2fb536586"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33aedc3d903378e257047fee506f11e0833146ca3e57a1a1fb0ddb789876c1e1"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd0099ae6aed5eb1fc84c9eb72b95505a3df4267e6962eb93cdd5af03be71c98"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c864a80a2d467d7786274fce0e4f93ef2a7ca4ff31f7fc5634225aaa4e9e98c"}, + {file = "orjson-3.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c25774c9e88a3e0013d7d1a6c8056926b607a61edd423b50eb5c88fd7f2823ae"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e78c211d0074e783d824ce7bb85bf459f93a233eb67a5b5003498232ddfb0e8a"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:43e17289ffdbbac8f39243916c893d2ae41a2ea1a9cbb060a56a4d75286351ae"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:781d54657063f361e89714293c095f506c533582ee40a426cb6489c48a637b81"}, + {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6875210307d36c94873f553786a808af2788e362bd0cf4c8e66d976791e7b528"}, + {file = "orjson-3.10.15-cp38-cp38-win32.whl", hash = "sha256:305b38b2b8f8083cc3d618927d7f424349afce5975b316d33075ef0f73576b60"}, + {file = "orjson-3.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:5dd9ef1639878cc3efffed349543cbf9372bdbd79f478615a1c633fe4e4180d1"}, + {file = "orjson-3.10.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ffe19f3e8d68111e8644d4f4e267a069ca427926855582ff01fc012496d19969"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d433bf32a363823863a96561a555227c18a522a8217a6f9400f00ddc70139ae2"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da03392674f59a95d03fa5fb9fe3a160b0511ad84b7a3914699ea5a1b3a38da2"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a63bb41559b05360ded9132032239e47983a39b151af1201f07ec9370715c82"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3766ac4702f8f795ff3fa067968e806b4344af257011858cc3d6d8721588b53f"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1c73dcc8fadbd7c55802d9aa093b36878d34a3b3222c41052ce6b0fc65f8e8"}, + {file = "orjson-3.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b299383825eafe642cbab34be762ccff9fd3408d72726a6b2a4506d410a71ab3"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:abc7abecdbf67a173ef1316036ebbf54ce400ef2300b4e26a7b843bd446c2480"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3614ea508d522a621384c1d6639016a5a2e4f027f3e4a1c93a51867615d28829"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:295c70f9dc154307777ba30fe29ff15c1bcc9dfc5c48632f37d20a607e9ba85a"}, + {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:63309e3ff924c62404923c80b9e2048c1f74ba4b615e7584584389ada50ed428"}, + {file = "orjson-3.10.15-cp39-cp39-win32.whl", hash = "sha256:a2f708c62d026fb5340788ba94a55c23df4e1869fec74be455e0b2f5363b8507"}, + {file = "orjson-3.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:efcf6c735c3d22ef60c4aa27a5238f1a477df85e9b15f2142f9d669beb2d13fd"}, + {file = "orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e"}, +] +markers = {main = "platform_python_implementation != \"PyPy\""} + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "psycopg" +version = "3.2.5" +description = "PostgreSQL database adapter for Python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "psycopg-3.2.5-py3-none-any.whl", hash = "sha256:b782130983e5b3de30b4c529623d3687033b4dafa05bb661fc6bf45837ca5879"}, + {file = "psycopg-3.2.5.tar.gz", hash = "sha256:f5f750611c67cb200e85b408882f29265c66d1de7f813add4f8125978bfd70e8"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""} +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +binary = ["psycopg-binary (==3.2.5)"] +c = ["psycopg-c (==3.2.5)"] +dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "isort-psycopg", "isort[colors] (>=6.0)", "mypy (>=1.14)", "pre-commit (>=4.0.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] +docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] +pool = ["psycopg-pool"] +test = ["anyio (>=4.0)", "mypy (>=1.14)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] + +[[package]] +name = "psycopg-pool" +version = "3.2.5" +description = "Connection Pool for Psycopg" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "psycopg_pool-3.2.5-py3-none-any.whl", hash = "sha256:522b9befae8631550217fd2ae9904622daaf4b28a0a36ccfcc87ba3d2abc7100"}, + {file = "psycopg_pool-3.2.5.tar.gz", hash = "sha256:507d845bd13da83df449ded7fb581b35dba613421bdb12962e608b16e70d6be9"}, +] + +[package.dependencies] +typing-extensions = ">=4.6" + +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +markers = "platform_python_implementation == \"PyPy\"" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pydantic" +version = "2.10.6" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.27.2" +typing-extensions = ">=4.12.2" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pytest" +version = "7.4.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.2" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b"}, + {file = "pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-watcher" +version = "0.4.3" +description = "Automatically rerun your tests on file modifications" +optional = false +python-versions = "<4.0.0,>=3.7.0" +groups = ["dev"] +files = [ + {file = "pytest_watcher-0.4.3-py3-none-any.whl", hash = "sha256:d59b1e1396f33a65ea4949b713d6884637755d641646960056a90b267c3460f9"}, + {file = "pytest_watcher-0.4.3.tar.gz", hash = "sha256:0cb0e4661648c8c0ff2b2d25efa5a8e421784b9e4c60fcecbf9b7c30b2d731b3"}, +] + +[package.dependencies] +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} +watchdog = ">=2.0.0" + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main", "dev"] +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "ruff" +version = "0.6.9" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, + {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, + {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"}, + {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"}, + {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, + {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, + {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "tenacity" +version = "9.0.0" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, + {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, +] + +[package.extras] +doc = ["reno", "sphinx"] +test = ["pytest", "tornado (>=4.5)", "typeguard"] + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "tzdata" +version = "2025.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +groups = ["dev"] +markers = "sys_platform == \"win32\"" +files = [ + {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, + {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "watchdog" +version = "6.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[[package]] +name = "zstandard" +version = "0.23.0" +description = "Zstandard bindings for Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9"}, + {file = "zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77da4c6bfa20dd5ea25cbf12c76f181a8e8cd7ea231c673828d0386b1740b8dc"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2170c7e0367dde86a2647ed5b6f57394ea7f53545746104c6b09fc1f4223573"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16842b846a8d2a145223f520b7e18b57c8f476924bda92aeee3a88d11cfc391"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:157e89ceb4054029a289fb504c98c6a9fe8010f1680de0201b3eb5dc20aa6d9e"}, + {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:203d236f4c94cd8379d1ea61db2fce20730b4c38d7f1c34506a31b34edc87bdd"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dc5d1a49d3f8262be192589a4b72f0d03b72dcf46c51ad5852a4fdc67be7b9e4"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:752bf8a74412b9892f4e5b58f2f890a039f57037f52c89a740757ebd807f33ea"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80080816b4f52a9d886e67f1f96912891074903238fe54f2de8b786f86baded2"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84433dddea68571a6d6bd4fbf8ff398236031149116a7fff6f777ff95cad3df9"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19a2d91963ed9e42b4e8d77cd847ae8381576585bad79dbd0a8837a9f6620a"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:59556bf80a7094d0cfb9f5e50bb2db27fefb75d5138bb16fb052b61b0e0eeeb0"}, + {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27d3ef2252d2e62476389ca8f9b0cf2bbafb082a3b6bfe9d90cbcbb5529ecf7c"}, + {file = "zstandard-0.23.0-cp310-cp310-win32.whl", hash = "sha256:5d41d5e025f1e0bccae4928981e71b2334c60f580bdc8345f824e7c0a4c2a813"}, + {file = "zstandard-0.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:519fbf169dfac1222a76ba8861ef4ac7f0530c35dd79ba5727014613f91613d4"}, + {file = "zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e"}, + {file = "zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80a539906390591dd39ebb8d773771dc4db82ace6372c4d41e2d293f8e32b8db"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:445e4cb5048b04e90ce96a79b4b63140e3f4ab5f662321975679b5f6360b90e2"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd30d9c67d13d891f2360b2a120186729c111238ac63b43dbd37a5a40670b8ca"}, + {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d20fd853fbb5807c8e84c136c278827b6167ded66c72ec6f9a14b863d809211c"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed1708dbf4d2e3a1c5c69110ba2b4eb6678262028afd6c6fbcc5a8dac9cda68e"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be9b5b8659dff1f913039c2feee1aca499cfbc19e98fa12bc85e037c17ec6ca5"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65308f4b4890aa12d9b6ad9f2844b7ee42c7f7a4fd3390425b242ffc57498f48"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98da17ce9cbf3bfe4617e836d561e433f871129e3a7ac16d6ef4c680f13a839c"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed7d27cb56b3e058d3cf684d7200703bcae623e1dcc06ed1e18ecda39fee003"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b69bb4f51daf461b15e7b3db033160937d3ff88303a7bc808c67bbc1eaf98c78"}, + {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:034b88913ecc1b097f528e42b539453fa82c3557e414b3de9d5632c80439a473"}, + {file = "zstandard-0.23.0-cp311-cp311-win32.whl", hash = "sha256:f2d4380bf5f62daabd7b751ea2339c1a21d1c9463f1feb7fc2bdcea2c29c3160"}, + {file = "zstandard-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:62136da96a973bd2557f06ddd4e8e807f9e13cbb0bfb9cc06cfe6d98ea90dfe0"}, + {file = "zstandard-0.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b4567955a6bc1b20e9c31612e615af6b53733491aeaa19a6b3b37f3b65477094"}, + {file = "zstandard-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e172f57cd78c20f13a3415cc8dfe24bf388614324d25539146594c16d78fcc8"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e166f698c5a3e914947388c162be2583e0c638a4703fc6a543e23a88dea3c1"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a289832e520c6bd4dcaad68e944b86da3bad0d339ef7989fb7e88f92e96072"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d50d31bfedd53a928fed6707b15a8dbeef011bb6366297cc435accc888b27c20"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72c68dda124a1a138340fb62fa21b9bf4848437d9ca60bd35db36f2d3345f373"}, + {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53dd9d5e3d29f95acd5de6802e909ada8d8d8cfa37a3ac64836f3bc4bc5512db"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6a41c120c3dbc0d81a8e8adc73312d668cd34acd7725f036992b1b72d22c1772"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:40b33d93c6eddf02d2c19f5773196068d875c41ca25730e8288e9b672897c105"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9206649ec587e6b02bd124fb7799b86cddec350f6f6c14bc82a2b70183e708ba"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76e79bc28a65f467e0409098fa2c4376931fd3207fbeb6b956c7c476d53746dd"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66b689c107857eceabf2cf3d3fc699c3c0fe8ccd18df2219d978c0283e4c508a"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9c236e635582742fee16603042553d276cca506e824fa2e6489db04039521e90"}, + {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35"}, + {file = "zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d"}, + {file = "zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b"}, + {file = "zstandard-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:576856e8594e6649aee06ddbfc738fec6a834f7c85bf7cadd1c53d4a58186ef9"}, + {file = "zstandard-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38302b78a850ff82656beaddeb0bb989a0322a8bbb1bf1ab10c17506681d772a"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2240ddc86b74966c34554c49d00eaafa8200a18d3a5b6ffbf7da63b11d74ee2"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ef230a8fd217a2015bc91b74f6b3b7d6522ba48be29ad4ea0ca3a3775bf7dd5"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:774d45b1fac1461f48698a9d4b5fa19a69d47ece02fa469825b442263f04021f"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f77fa49079891a4aab203d0b1744acc85577ed16d767b52fc089d83faf8d8ed"}, + {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac184f87ff521f4840e6ea0b10c0ec90c6b1dcd0bad2f1e4a9a1b4fa177982ea"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c363b53e257246a954ebc7c488304b5592b9c53fbe74d03bc1c64dda153fb847"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e7792606d606c8df5277c32ccb58f29b9b8603bf83b48639b7aedf6df4fe8171"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0817825b900fcd43ac5d05b8b3079937073d2b1ff9cf89427590718b70dd840"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9da6bc32faac9a293ddfdcb9108d4b20416219461e4ec64dfea8383cac186690"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd7699e8fd9969f455ef2926221e0233f81a2542921471382e77a9e2f2b57f4b"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d477ed829077cd945b01fc3115edd132c47e6540ddcd96ca169facff28173057"}, + {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ce8b52c5987b3e34d5674b0ab529a4602b632ebab0a93b07bfb4dfc8f8a33"}, + {file = "zstandard-0.23.0-cp313-cp313-win32.whl", hash = "sha256:a9b07268d0c3ca5c170a385a0ab9fb7fdd9f5fd866be004c4ea39e44edce47dd"}, + {file = "zstandard-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b"}, + {file = "zstandard-0.23.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ef3775758346d9ac6214123887d25c7061c92afe1f2b354f9388e9e4d48acfc"}, + {file = "zstandard-0.23.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4051e406288b8cdbb993798b9a45c59a4896b6ecee2f875424ec10276a895740"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2d1a054f8f0a191004675755448d12be47fa9bebbcffa3cdf01db19f2d30a54"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f83fa6cae3fff8e98691248c9320356971b59678a17f20656a9e59cd32cee6d8"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32ba3b5ccde2d581b1e6aa952c836a6291e8435d788f656fe5976445865ae045"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f146f50723defec2975fb7e388ae3a024eb7151542d1599527ec2aa9cacb152"}, + {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bfe8de1da6d104f15a60d4a8a768288f66aa953bbe00d027398b93fb9680b26"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:29a2bc7c1b09b0af938b7a8343174b987ae021705acabcbae560166567f5a8db"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61f89436cbfede4bc4e91b4397eaa3e2108ebe96d05e93d6ccc95ab5714be512"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53ea7cdc96c6eb56e76bb06894bcfb5dfa93b7adcf59d61c6b92674e24e2dd5e"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:a4ae99c57668ca1e78597d8b06d5af837f377f340f4cce993b551b2d7731778d"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:379b378ae694ba78cef921581ebd420c938936a153ded602c4fea612b7eaa90d"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:50a80baba0285386f97ea36239855f6020ce452456605f262b2d33ac35c7770b"}, + {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:61062387ad820c654b6a6b5f0b94484fa19515e0c5116faf29f41a6bc91ded6e"}, + {file = "zstandard-0.23.0-cp38-cp38-win32.whl", hash = "sha256:b8c0bd73aeac689beacd4e7667d48c299f61b959475cdbb91e7d3d88d27c56b9"}, + {file = "zstandard-0.23.0-cp38-cp38-win_amd64.whl", hash = "sha256:a05e6d6218461eb1b4771d973728f0133b2a4613a6779995df557f70794fd60f"}, + {file = "zstandard-0.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa014d55c3af933c1315eb4bb06dd0459661cc0b15cd61077afa6489bec63bb"}, + {file = "zstandard-0.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7f0804bb3799414af278e9ad51be25edf67f78f916e08afdb983e74161b916"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb2b1ecfef1e67897d336de3a0e3f52478182d6a47eda86cbd42504c5cbd009a"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:837bb6764be6919963ef41235fd56a6486b132ea64afe5fafb4cb279ac44f259"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1516c8c37d3a053b01c1c15b182f3b5f5eef19ced9b930b684a73bad121addf4"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48ef6a43b1846f6025dde6ed9fee0c24e1149c1c25f7fb0a0585572b2f3adc58"}, + {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11e3bf3c924853a2d5835b24f03eeba7fc9b07d8ca499e247e06ff5676461a15"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2fb4535137de7e244c230e24f9d1ec194f61721c86ebea04e1581d9d06ea1269"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c24f21fa2af4bb9f2c492a86fe0c34e6d2c63812a839590edaf177b7398f700"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8c86881813a78a6f4508ef9daf9d4995b8ac2d147dcb1a450448941398091c9"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe3b385d996ee0822fd46528d9f0443b880d4d05528fd26a9119a54ec3f91c69"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:82d17e94d735c99621bf8ebf9995f870a6b3e6d14543b99e201ae046dfe7de70"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c7c517d74bea1a6afd39aa612fa025e6b8011982a0897768a2f7c8ab4ebb78a2"}, + {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fd7e0f1cfb70eb2f95a19b472ee7ad6d9a0a992ec0ae53286870c104ca939e5"}, + {file = "zstandard-0.23.0-cp39-cp39-win32.whl", hash = "sha256:43da0f0092281bf501f9c5f6f3b4c975a8a0ea82de49ba3f7100e64d422a1274"}, + {file = "zstandard-0.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:f8346bfa098532bc1fb6c7ef06783e969d87a99dd1d2a5a18a892c1d7a643c58"}, + {file = "zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09"}, +] + +[package.dependencies] +cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""} + +[package.extras] +cffi = ["cffi (>=1.11)"] + +[metadata] +lock-version = "2.1" +python-versions = "^3.9.0,<4.0" +content-hash = "af5dc04219a8b3bce05705a0664ff424b40b426e47575d0a8a36415563553942" diff --git a/libs/prebuilt/pyproject.toml b/libs/prebuilt/pyproject.toml new file mode 100644 index 000000000..3246572e3 --- /dev/null +++ b/libs/prebuilt/pyproject.toml @@ -0,0 +1,62 @@ +[tool.poetry] +name = "langgraph-prebuilt" +version = "0.1.2" +description = "Library with high-level APIs for creating and executing LangGraph agents and tools." +authors = [] +license = "MIT" +readme = "README.md" +repository = "https://www.github.com/langchain-ai/langgraph" +packages = [{ include = "langgraph" }] + +[tool.poetry.dependencies] +python = "^3.9.0,<4.0" +langgraph-checkpoint = "^2.0.10" +langchain-core = ">=0.2.43,<0.4.0,!=0.3.0,!=0.3.1,!=0.3.2,!=0.3.3,!=0.3.4,!=0.3.5,!=0.3.6,!=0.3.7,!=0.3.8,!=0.3.9,!=0.3.10,!=0.3.11,!=0.3.12,!=0.3.13,!=0.3.14,!=0.3.15,!=0.3.16,!=0.3.17,!=0.3.18,!=0.3.19,!=0.3.20,!=0.3.21,!=0.3.22" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.6.2" +codespell = "^2.2.0" +pytest = "^7.2.1" +pytest-asyncio = "^0.21.1" +pytest-mock = "^3.11.1" +pytest-watcher = "^0.4.1" +mypy = "^1.10.0" +langgraph = {path = "../langgraph", develop = true} +langgraph-checkpoint = {path = "../checkpoint", develop = true} +langgraph-checkpoint-sqlite = {path = "../checkpoint-sqlite", develop = true} +langgraph-checkpoint-postgres = {path = "../checkpoint-postgres", develop = true} + +[tool.pytest.ini_options] +# --strict-markers will raise errors on unknown marks. +# https://docs.pytest.org/en/7.1.x/how-to/mark.html#raising-errors-on-unknown-marks +# +# https://docs.pytest.org/en/7.1.x/reference/reference.html +# --strict-config any warnings encountered while parsing the `pytest` +# section of the configuration file raise errors. +addopts = "--strict-markers --strict-config --durations=5 -vv" +asyncio_mode = "auto" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +lint.select = [ "E", "F", "I", "TID251" ] +lint.ignore = [ "E501" ] + +[tool.pytest-watcher] +now = true +delay = 0.1 +runner_args = ["--ff", "-v", "--tb", "short"] +patterns = ["*.py"] + +[tool.mypy] +# https://mypy.readthedocs.io/en/stable/config_file.html +disallow_untyped_defs = "True" +explicit_package_bases = "True" +warn_no_return = "False" +warn_unused_ignores = "True" +warn_redundant_casts = "True" +allow_redefinition = "True" +disable_error_code = "typeddict-item, return-value" diff --git a/libs/prebuilt/tests/__init__.py b/libs/prebuilt/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/libs/prebuilt/tests/any_str.py b/libs/prebuilt/tests/any_str.py new file mode 100644 index 000000000..5643a00fb --- /dev/null +++ b/libs/prebuilt/tests/any_str.py @@ -0,0 +1,86 @@ +import re +from typing import Any, Sequence, Union + +from typing_extensions import Self + + +class FloatBetween(float): + def __new__(cls, min_value: float, max_value: float) -> Self: + return super().__new__(cls, min_value) + + def __init__(self, min_value: float, max_value: float) -> None: + super().__init__() + self.min_value = min_value + self.max_value = max_value + + def __eq__(self, other: object) -> bool: + return ( + isinstance(other, float) + and other >= self.min_value + and other <= self.max_value + ) + + def __hash__(self) -> int: + return hash((float(self), self.min_value, self.max_value)) + + +class AnyStr(str): + def __init__(self, prefix: Union[str, re.Pattern] = "") -> None: + super().__init__() + self.prefix = prefix + + def __eq__(self, other: object) -> bool: + return isinstance(other, str) and ( + other.startswith(self.prefix) + if isinstance(self.prefix, str) + else self.prefix.match(other) + ) + + def __hash__(self) -> int: + return hash((str(self), self.prefix)) + + +class AnyDict(dict): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, dict) or len(self) != len(other): + return False + for k, v in self.items(): + if kk := next((kk for kk in other if kk == k), None): + if v == other[kk]: + continue + else: + return False + else: + return True + + +class AnyVersion: + def __init__(self) -> None: + super().__init__() + + def __eq__(self, other: object) -> bool: + return isinstance(other, (str, int, float)) + + def __hash__(self) -> int: + return hash(str(self)) + + +class UnsortedSequence: + def __init__(self, *values: Any) -> None: + self.seq = values + + def __eq__(self, value: object) -> bool: + return ( + isinstance(value, Sequence) + and len(self.seq) == len(value) + and all(a in value for a in self.seq) + ) + + def __hash__(self) -> int: + return hash(frozenset(self.seq)) + + def __repr__(self) -> str: + return repr(self.seq) diff --git a/libs/prebuilt/tests/compose-postgres.yml b/libs/prebuilt/tests/compose-postgres.yml new file mode 100644 index 000000000..221b35daf --- /dev/null +++ b/libs/prebuilt/tests/compose-postgres.yml @@ -0,0 +1,17 @@ +name: langgraph-tests +services: + postgres-test: + image: postgres:16 + ports: + - "5442:5432" + environment: + POSTGRES_DB: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + healthcheck: + test: pg_isready -U postgres + start_period: 10s + timeout: 1s + retries: 5 + interval: 60s + start_interval: 1s diff --git a/libs/prebuilt/tests/conftest.py b/libs/prebuilt/tests/conftest.py new file mode 100644 index 000000000..20f9e15f6 --- /dev/null +++ b/libs/prebuilt/tests/conftest.py @@ -0,0 +1,448 @@ +import sys +from contextlib import asynccontextmanager +from typing import AsyncIterator, Optional +from uuid import UUID, uuid4 + +import pytest +from langchain_core import __version__ as core_version +from packaging import version +from psycopg import AsyncConnection, Connection +from psycopg_pool import AsyncConnectionPool, ConnectionPool +from pytest_mock import MockerFixture + +from langgraph.checkpoint.base import BaseCheckpointSaver +from langgraph.checkpoint.postgres import PostgresSaver, ShallowPostgresSaver +from langgraph.checkpoint.postgres.aio import ( + AsyncPostgresSaver, + AsyncShallowPostgresSaver, +) +from langgraph.checkpoint.sqlite import SqliteSaver +from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver +from langgraph.store.base import BaseStore +from langgraph.store.memory import InMemoryStore +from langgraph.store.postgres import AsyncPostgresStore, PostgresStore + +pytest.register_assert_rewrite("tests.memory_assert") + +DEFAULT_POSTGRES_URI = "postgres://postgres:postgres@localhost:5442/" +# TODO: fix this once core is released +IS_LANGCHAIN_CORE_030_OR_GREATER = version.parse(core_version) >= version.parse( + "0.3.0.dev0" +) + + +@pytest.fixture +def anyio_backend(): + return "asyncio" + + +@pytest.fixture() +def deterministic_uuids(mocker: MockerFixture) -> MockerFixture: + side_effect = ( + UUID(f"00000000-0000-4000-8000-{i:012}", version=4) for i in range(10000) + ) + return mocker.patch("uuid.uuid4", side_effect=side_effect) + + +# checkpointer fixtures + + +@pytest.fixture(scope="function") +def checkpointer_memory(): + from tests.memory_assert import MemorySaverAssertImmutable + + yield MemorySaverAssertImmutable() + + +@pytest.fixture(scope="function") +def checkpointer_sqlite(): + with SqliteSaver.from_conn_string(":memory:") as checkpointer: + yield checkpointer + + +@asynccontextmanager +async def _checkpointer_sqlite_aio(): + async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer: + yield checkpointer + + +@pytest.fixture(scope="function") +def checkpointer_postgres(): + database = f"test_{uuid4().hex[:16]}" + # create unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + with PostgresSaver.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as checkpointer: + checkpointer.setup() + yield checkpointer + finally: + # drop unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"DROP DATABASE {database}") + + +@pytest.fixture(scope="function") +def checkpointer_postgres_shallow(): + database = f"test_{uuid4().hex[:16]}" + # create unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + with ShallowPostgresSaver.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as checkpointer: + checkpointer.setup() + yield checkpointer + finally: + # drop unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"DROP DATABASE {database}") + + +@pytest.fixture(scope="function") +def checkpointer_postgres_pipe(): + database = f"test_{uuid4().hex[:16]}" + # create unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + with PostgresSaver.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as checkpointer: + checkpointer.setup() + # setup can't run inside pipeline because of implicit transaction + with checkpointer.conn.pipeline() as pipe: + checkpointer.pipe = pipe + yield checkpointer + finally: + # drop unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"DROP DATABASE {database}") + + +@pytest.fixture(scope="function") +def checkpointer_postgres_pool(): + database = f"test_{uuid4().hex[:16]}" + # create unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + with ConnectionPool( + DEFAULT_POSTGRES_URI + database, max_size=10, kwargs={"autocommit": True} + ) as pool: + checkpointer = PostgresSaver(pool) + checkpointer.setup() + yield checkpointer + finally: + # drop unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"DROP DATABASE {database}") + + +@asynccontextmanager +async def _checkpointer_postgres_aio(): + if sys.version_info < (3, 10): + pytest.skip("Async Postgres tests require Python 3.10+") + database = f"test_{uuid4().hex[:16]}" + # create unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + async with AsyncPostgresSaver.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as checkpointer: + await checkpointer.setup() + yield checkpointer + finally: + # drop unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"DROP DATABASE {database}") + + +@asynccontextmanager +async def _checkpointer_postgres_aio_shallow(): + if sys.version_info < (3, 10): + pytest.skip("Async Postgres tests require Python 3.10+") + database = f"test_{uuid4().hex[:16]}" + # create unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + async with AsyncShallowPostgresSaver.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as checkpointer: + await checkpointer.setup() + yield checkpointer + finally: + # drop unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"DROP DATABASE {database}") + + +@asynccontextmanager +async def _checkpointer_postgres_aio_pipe(): + if sys.version_info < (3, 10): + pytest.skip("Async Postgres tests require Python 3.10+") + database = f"test_{uuid4().hex[:16]}" + # create unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + async with AsyncPostgresSaver.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as checkpointer: + await checkpointer.setup() + # setup can't run inside pipeline because of implicit transaction + async with checkpointer.conn.pipeline() as pipe: + checkpointer.pipe = pipe + yield checkpointer + finally: + # drop unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"DROP DATABASE {database}") + + +@asynccontextmanager +async def _checkpointer_postgres_aio_pool(): + if sys.version_info < (3, 10): + pytest.skip("Async Postgres tests require Python 3.10+") + database = f"test_{uuid4().hex[:16]}" + # create unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"CREATE DATABASE {database}") + try: + # yield checkpointer + async with AsyncConnectionPool( + DEFAULT_POSTGRES_URI + database, max_size=10, kwargs={"autocommit": True} + ) as pool: + checkpointer = AsyncPostgresSaver(pool) + await checkpointer.setup() + yield checkpointer + finally: + # drop unique db + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"DROP DATABASE {database}") + + +@asynccontextmanager +async def awith_checkpointer( + checkpointer_name: Optional[str], +) -> AsyncIterator[BaseCheckpointSaver]: + if checkpointer_name is None: + yield None + elif checkpointer_name == "memory": + from tests.memory_assert import MemorySaverAssertImmutable + + yield MemorySaverAssertImmutable() + elif checkpointer_name == "sqlite_aio": + async with _checkpointer_sqlite_aio() as checkpointer: + yield checkpointer + elif checkpointer_name == "postgres_aio": + async with _checkpointer_postgres_aio() as checkpointer: + yield checkpointer + elif checkpointer_name == "postgres_aio_shallow": + async with _checkpointer_postgres_aio_shallow() as checkpointer: + yield checkpointer + elif checkpointer_name == "postgres_aio_pipe": + async with _checkpointer_postgres_aio_pipe() as checkpointer: + yield checkpointer + elif checkpointer_name == "postgres_aio_pool": + async with _checkpointer_postgres_aio_pool() as checkpointer: + yield checkpointer + else: + raise NotImplementedError(f"Unknown checkpointer: {checkpointer_name}") + + +@asynccontextmanager +async def _store_postgres_aio(): + if sys.version_info < (3, 10): + pytest.skip("Async Postgres tests require Python 3.10+") + database = f"test_{uuid4().hex[:16]}" + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"CREATE DATABASE {database}") + try: + async with AsyncPostgresStore.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as store: + await store.setup() + yield store + finally: + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"DROP DATABASE {database}") + + +@asynccontextmanager +async def _store_postgres_aio_pipe(): + if sys.version_info < (3, 10): + pytest.skip("Async Postgres tests require Python 3.10+") + database = f"test_{uuid4().hex[:16]}" + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"CREATE DATABASE {database}") + try: + async with AsyncPostgresStore.from_conn_string( + DEFAULT_POSTGRES_URI + database + ) as store: + await store.setup() # Run in its own transaction + async with AsyncPostgresStore.from_conn_string( + DEFAULT_POSTGRES_URI + database, pipeline=True + ) as store: + yield store + finally: + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"DROP DATABASE {database}") + + +@asynccontextmanager +async def _store_postgres_aio_pool(): + if sys.version_info < (3, 10): + pytest.skip("Async Postgres tests require Python 3.10+") + database = f"test_{uuid4().hex[:16]}" + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"CREATE DATABASE {database}") + try: + async with AsyncPostgresStore.from_conn_string( + DEFAULT_POSTGRES_URI + database, + pool_config={"max_size": 10}, + ) as store: + await store.setup() + yield store + finally: + async with await AsyncConnection.connect( + DEFAULT_POSTGRES_URI, autocommit=True + ) as conn: + await conn.execute(f"DROP DATABASE {database}") + + +@pytest.fixture(scope="function") +def store_postgres(): + database = f"test_{uuid4().hex[:16]}" + # create unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"CREATE DATABASE {database}") + try: + # yield store + with PostgresStore.from_conn_string(DEFAULT_POSTGRES_URI + database) as store: + store.setup() + yield store + finally: + # drop unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"DROP DATABASE {database}") + + +@pytest.fixture(scope="function") +def store_postgres_pipe(): + database = f"test_{uuid4().hex[:16]}" + # create unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"CREATE DATABASE {database}") + try: + # yield store + with PostgresStore.from_conn_string(DEFAULT_POSTGRES_URI + database) as store: + store.setup() # Run in its own transaction + with PostgresStore.from_conn_string( + DEFAULT_POSTGRES_URI + database, pipeline=True + ) as store: + yield store + finally: + # drop unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"DROP DATABASE {database}") + + +@pytest.fixture(scope="function") +def store_postgres_pool(): + database = f"test_{uuid4().hex[:16]}" + # create unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"CREATE DATABASE {database}") + try: + # yield store + with PostgresStore.from_conn_string( + DEFAULT_POSTGRES_URI + database, pool_config={"max_size": 10} + ) as store: + store.setup() + yield store + finally: + # drop unique db + with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn: + conn.execute(f"DROP DATABASE {database}") + + +@pytest.fixture(scope="function") +def store_in_memory(): + yield InMemoryStore() + + +@asynccontextmanager +async def awith_store(store_name: Optional[str]) -> AsyncIterator[BaseStore]: + if store_name is None: + yield None + elif store_name == "in_memory": + yield InMemoryStore() + elif store_name == "postgres_aio": + async with _store_postgres_aio() as store: + yield store + elif store_name == "postgres_aio_pipe": + async with _store_postgres_aio_pipe() as store: + yield store + elif store_name == "postgres_aio_pool": + async with _store_postgres_aio_pool() as store: + yield store + else: + raise NotImplementedError(f"Unknown store {store_name}") + + +ALL_CHECKPOINTERS_SYNC = [ + "memory", + "sqlite", + "postgres", + "postgres_pipe", + "postgres_pool", + "postgres_shallow", +] + +ALL_CHECKPOINTERS_ASYNC = [ + "memory", + "sqlite_aio", + "postgres_aio", + "postgres_aio_pipe", + "postgres_aio_pool", + "postgres_aio_shallow", +] diff --git a/libs/prebuilt/tests/memory_assert.py b/libs/prebuilt/tests/memory_assert.py new file mode 100644 index 000000000..f88f0358f --- /dev/null +++ b/libs/prebuilt/tests/memory_assert.py @@ -0,0 +1,134 @@ +import asyncio +import os +import tempfile +from collections import defaultdict +from functools import partial +from typing import Any, Optional + +from langchain_core.runnables import RunnableConfig + +from langgraph.checkpoint.base import ( + ChannelVersions, + Checkpoint, + CheckpointMetadata, + CheckpointTuple, + SerializerProtocol, + copy_checkpoint, +) +from langgraph.checkpoint.memory import InMemorySaver, PersistentDict + + +class NoopSerializer(SerializerProtocol): + def loads_typed(self, data: tuple[str, bytes]) -> Any: + return data[1] + + def dumps_typed(self, obj: Any) -> tuple[str, bytes]: + return "type", obj + + +class MemorySaverAssertImmutable(InMemorySaver): + storage_for_copies: defaultdict[str, dict[str, dict[str, Checkpoint]]] + + def __init__( + self, + *, + serde: Optional[SerializerProtocol] = None, + put_sleep: Optional[float] = None, + ) -> None: + _, filename = tempfile.mkstemp() + super().__init__( + serde=serde, factory=partial(PersistentDict, filename=filename) + ) + self.storage_for_copies = defaultdict(lambda: defaultdict(dict)) + self.put_sleep = put_sleep + self.stack.callback(os.remove, filename) + + def put( + self, + config: dict, + checkpoint: Checkpoint, + metadata: CheckpointMetadata, + new_versions: ChannelVersions, + ) -> None: + if self.put_sleep: + import time + + time.sleep(self.put_sleep) + # assert checkpoint hasn't been modified since last written + thread_id = config["configurable"]["thread_id"] + checkpoint_ns = config["configurable"]["checkpoint_ns"] + if saved := super().get(config): + assert ( + self.serde.loads_typed( + self.storage_for_copies[thread_id][checkpoint_ns][saved["id"]] + ) + == saved + ) + self.storage_for_copies[thread_id][checkpoint_ns][checkpoint["id"]] = ( + self.serde.dumps_typed(copy_checkpoint(checkpoint)) + ) + # call super to write checkpoint + return super().put(config, checkpoint, metadata, new_versions) + + +class MemorySaverAssertCheckpointMetadata(InMemorySaver): + """This custom checkpointer is for verifying that a run's configurable + fields are merged with the previous checkpoint config for each step in + the run. This is the desired behavior. Because the checkpointer's (a)put() + method is called for each step, the implementation of this checkpointer + should produce a side effect that can be asserted. + """ + + def put( + self, + config: RunnableConfig, + checkpoint: Checkpoint, + metadata: CheckpointMetadata, + new_versions: ChannelVersions, + ) -> None: + """The implementation of put() merges config["configurable"] (a run's + configurable fields) with the metadata field. The state of the + checkpoint metadata can be asserted to confirm that the run's + configurable fields were merged with the previous checkpoint config. + """ + configurable = config["configurable"].copy() + + # remove checkpoint_id to make testing simpler + checkpoint_id = configurable.pop("checkpoint_id", None) + thread_id = config["configurable"]["thread_id"] + checkpoint_ns = config["configurable"]["checkpoint_ns"] + self.storage[thread_id][checkpoint_ns].update( + { + checkpoint["id"]: ( + self.serde.dumps_typed(checkpoint), + # merge configurable fields and metadata + self.serde.dumps_typed({**configurable, **metadata}), + checkpoint_id, + ) + } + ) + return { + "configurable": { + "thread_id": config["configurable"]["thread_id"], + "checkpoint_id": checkpoint["id"], + } + } + + async def aput( + self, + config: RunnableConfig, + checkpoint: Checkpoint, + metadata: CheckpointMetadata, + new_versions: ChannelVersions, + ) -> RunnableConfig: + return await asyncio.get_running_loop().run_in_executor( + None, self.put, config, checkpoint, metadata, new_versions + ) + + +class MemorySaverNoPending(InMemorySaver): + def get_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]: + result = super().get_tuple(config) + if result: + return CheckpointTuple(result.config, result.checkpoint, result.metadata) + return result diff --git a/libs/prebuilt/tests/messages.py b/libs/prebuilt/tests/messages.py new file mode 100644 index 000000000..ecc657a36 --- /dev/null +++ b/libs/prebuilt/tests/messages.py @@ -0,0 +1,50 @@ +"""Redefined messages as a work-around for pydantic issue with AnyStr. + +The code below creates version of pydantic models +that will work in unit tests with AnyStr as id field +Please note that the `id` field is assigned AFTER the model is created +to workaround an issue with pydantic ignoring the __eq__ method on +subclassed strings. +""" + +from typing import Any + +from langchain_core.documents import Document +from langchain_core.messages import AIMessage, AIMessageChunk, HumanMessage, ToolMessage + +from tests.any_str import AnyStr + + +def _AnyIdDocument(**kwargs: Any) -> Document: + """Create a document with an id field.""" + message = Document(**kwargs) + message.id = AnyStr() + return message + + +def _AnyIdAIMessage(**kwargs: Any) -> AIMessage: + """Create ai message with an any id field.""" + message = AIMessage(**kwargs) + message.id = AnyStr() + return message + + +def _AnyIdAIMessageChunk(**kwargs: Any) -> AIMessageChunk: + """Create ai message with an any id field.""" + message = AIMessageChunk(**kwargs) + message.id = AnyStr() + return message + + +def _AnyIdHumanMessage(**kwargs: Any) -> HumanMessage: + """Create a human message with an any id field.""" + message = HumanMessage(**kwargs) + message.id = AnyStr() + return message + + +def _AnyIdToolMessage(**kwargs: Any) -> ToolMessage: + """Create a tool message with an any id field.""" + message = ToolMessage(**kwargs) + message.id = AnyStr() + return message diff --git a/libs/prebuilt/tests/model.py b/libs/prebuilt/tests/model.py new file mode 100644 index 000000000..8e9857675 --- /dev/null +++ b/libs/prebuilt/tests/model.py @@ -0,0 +1,98 @@ +from typing import ( + Any, + Callable, + Dict, + List, + Literal, + Optional, + Sequence, + Type, + Union, +) + +from langchain_core.callbacks import CallbackManagerForLLMRun +from langchain_core.language_models import BaseChatModel, LanguageModelInput +from langchain_core.messages import ( + AIMessage, + BaseMessage, + ToolCall, +) +from langchain_core.outputs import ChatGeneration, ChatResult +from langchain_core.runnables import Runnable, RunnableLambda +from langchain_core.tools import BaseTool +from pydantic import BaseModel + +from langgraph.prebuilt.chat_agent_executor import StructuredResponse + + +class FakeToolCallingModel(BaseChatModel): + tool_calls: Optional[list[list[ToolCall]]] = None + structured_response: Optional[StructuredResponse] = None + index: int = 0 + tool_style: Literal["openai", "anthropic"] = "openai" + + def _generate( + self, + messages: List[BaseMessage], + stop: Optional[List[str]] = None, + run_manager: Optional[CallbackManagerForLLMRun] = None, + **kwargs: Any, + ) -> ChatResult: + """Top Level call""" + messages_string = "-".join([m.content for m in messages]) + tool_calls = ( + self.tool_calls[self.index % len(self.tool_calls)] + if self.tool_calls + else [] + ) + message = AIMessage( + content=messages_string, id=str(self.index), tool_calls=tool_calls.copy() + ) + self.index += 1 + return ChatResult(generations=[ChatGeneration(message=message)]) + + @property + def _llm_type(self) -> str: + return "fake-tool-call-model" + + def with_structured_output( + self, schema: Type[BaseModel] + ) -> Runnable[LanguageModelInput, StructuredResponse]: + if self.structured_response is None: + raise ValueError("Structured response is not set") + + return RunnableLambda(lambda x: self.structured_response) + + def bind_tools( + self, + tools: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool]], + **kwargs: Any, + ) -> Runnable[LanguageModelInput, BaseMessage]: + if len(tools) == 0: + raise ValueError("Must provide at least one tool") + + tool_dicts = [] + for tool in tools: + if not isinstance(tool, BaseTool): + raise TypeError( + "Only BaseTool is supported by FakeToolCallingModel.bind_tools" + ) + + # NOTE: this is a simplified tool spec for testing purposes only + if self.tool_style == "openai": + tool_dicts.append( + { + "type": "function", + "function": { + "name": tool.name, + }, + } + ) + elif self.tool_style == "anthropic": + tool_dicts.append( + { + "name": tool.name, + } + ) + + return self.bind(tools=tool_dicts) diff --git a/libs/langgraph/tests/test_prebuilt.py b/libs/prebuilt/tests/test_react_agent.py similarity index 50% rename from libs/langgraph/tests/test_prebuilt.py rename to libs/prebuilt/tests/test_react_agent.py index b0a19d530..9d8b42e67 100644 --- a/libs/langgraph/tests/test_prebuilt.py +++ b/libs/prebuilt/tests/test_react_agent.py @@ -4,56 +4,45 @@ import json from functools import partial from typing import ( Annotated, - Any, - Callable, - Dict, List, - Literal, Optional, - Sequence, Type, TypeVar, Union, ) import pytest -from langchain_core.callbacks import CallbackManagerForLLMRun -from langchain_core.language_models import BaseChatModel, LanguageModelInput from langchain_core.messages import ( AIMessage, AnyMessage, - BaseMessage, HumanMessage, SystemMessage, ToolCall, ToolMessage, ) -from langchain_core.outputs import ChatGeneration, ChatResult -from langchain_core.runnables import Runnable, RunnableLambda -from langchain_core.tools import BaseTool, ToolException +from langchain_core.runnables import RunnableLambda +from langchain_core.tools import InjectedToolCallId, ToolException from langchain_core.tools import tool as dec_tool -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseModel, Field from pydantic.v1 import BaseModel as BaseModelV1 -from pydantic.v1 import ValidationError as ValidationErrorV1 from typing_extensions import TypedDict from langgraph.checkpoint.base import BaseCheckpointSaver -from langgraph.checkpoint.memory import MemorySaver -from langgraph.errors import NodeInterrupt from langgraph.graph import START, MessagesState, StateGraph, add_messages from langgraph.prebuilt import ( ToolNode, - ValidationNode, create_react_agent, tools_condition, ) from langgraph.prebuilt.chat_agent_executor import ( AgentState, - StructuredResponse, + AgentStatePydantic, + StateSchemaType, + _get_model, + _should_bind_tools, _validate_chat_history, ) from langgraph.prebuilt.tool_node import ( - TOOL_CALL_ERROR_TEMPLATE, InjectedState, InjectedStore, _get_state_args, @@ -63,6 +52,7 @@ from langgraph.store.base import BaseStore from langgraph.store.memory import InMemoryStore from langgraph.types import Command, Interrupt, interrupt from langgraph.utils.config import get_stream_writer +from tests.any_str import AnyStr from tests.conftest import ( ALL_CHECKPOINTERS_ASYNC, ALL_CHECKPOINTERS_SYNC, @@ -70,85 +60,13 @@ from tests.conftest import ( awith_checkpointer, ) from tests.messages import _AnyIdHumanMessage, _AnyIdToolMessage +from tests.model import FakeToolCallingModel pytestmark = pytest.mark.anyio REACT_TOOL_CALL_VERSIONS = ["v1", "v2"] -class FakeToolCallingModel(BaseChatModel): - tool_calls: Optional[list[list[ToolCall]]] = None - structured_response: Optional[StructuredResponse] = None - index: int = 0 - tool_style: Literal["openai", "anthropic"] = "openai" - - def _generate( - self, - messages: List[BaseMessage], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs: Any, - ) -> ChatResult: - """Top Level call""" - messages_string = "-".join([m.content for m in messages]) - tool_calls = ( - self.tool_calls[self.index % len(self.tool_calls)] - if self.tool_calls - else [] - ) - message = AIMessage( - content=messages_string, id=str(self.index), tool_calls=tool_calls.copy() - ) - self.index += 1 - return ChatResult(generations=[ChatGeneration(message=message)]) - - @property - def _llm_type(self) -> str: - return "fake-tool-call-model" - - def with_structured_output( - self, schema: Type[BaseModel] - ) -> Runnable[LanguageModelInput, StructuredResponse]: - if self.structured_response is None: - raise ValueError("Structured response is not set") - - return RunnableLambda(lambda x: self.structured_response) - - def bind_tools( - self, - tools: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool]], - **kwargs: Any, - ) -> Runnable[LanguageModelInput, BaseMessage]: - if len(tools) == 0: - raise ValueError("Must provide at least one tool") - - tool_dicts = [] - for tool in tools: - if not isinstance(tool, BaseTool): - raise TypeError( - "Only BaseTool is supported by FakeToolCallingModel.bind_tools" - ) - - # NOTE: this is a simplified tool spec for testing purposes only - if self.tool_style == "openai": - tool_dicts.append( - { - "type": "function", - "function": { - "name": tool.name, - }, - } - ) - elif self.tool_style == "anthropic": - tool_dicts.append( - { - "name": tool.name, - } - ) - - return self.bind(tools=tool_dicts) - - @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) @pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) def test_no_prompt( @@ -225,18 +143,15 @@ async def test_no_prompt_async(checkpointer_name: str) -> None: def test_passing_two_modifiers(): model = FakeToolCallingModel() - with pytest.raises(ValueError): - create_react_agent(model, [], messages_modifier="Foo", state_modifier="Bar") with pytest.raises(ValueError): - create_react_agent(model, [], messages_modifier="Foo", prompt="Bar") + create_react_agent(model, [], state_modifier="Foo", prompt="Bar") def test_system_message_prompt(): prompt = SystemMessage(content="Foo") for agent in ( create_react_agent(FakeToolCallingModel(), [], prompt=prompt), - create_react_agent(FakeToolCallingModel(), [], messages_modifier=prompt), create_react_agent(FakeToolCallingModel(), [], state_modifier=prompt), ): inputs = [HumanMessage("hi?")] @@ -251,7 +166,6 @@ def test_string_prompt(): prompt = "Foo" for agent in ( create_react_agent(FakeToolCallingModel(), [], prompt=prompt), - create_react_agent(FakeToolCallingModel(), [], messages_modifier=prompt), create_react_agent(FakeToolCallingModel(), [], state_modifier=prompt), ): inputs = [HumanMessage("hi?")] @@ -263,10 +177,6 @@ def test_string_prompt(): def test_callable_prompt(): - def messages_modifier(messages): - modified_message = f"Bar {messages[-1].content}" - return [HumanMessage(content=modified_message)] - def prompt(state): modified_message = f"Bar {state['messages'][-1].content}" return [HumanMessage(content=modified_message)] @@ -274,9 +184,6 @@ def test_callable_prompt(): for agent in ( create_react_agent(FakeToolCallingModel(), [], prompt=prompt), create_react_agent(FakeToolCallingModel(), [], state_modifier=prompt), - create_react_agent( - FakeToolCallingModel(), [], messages_modifier=messages_modifier - ), ): inputs = [HumanMessage("hi?")] response = agent.invoke({"messages": inputs}) @@ -304,9 +211,6 @@ async def test_callable_prompt_async(): def test_runnable_prompt(): - messages_modifier = RunnableLambda( - lambda messages: [HumanMessage(content=f"Baz {messages[-1].content}")] - ) prompt = RunnableLambda( lambda state: [HumanMessage(content=f"Baz {state['messages'][-1].content}")] ) @@ -314,9 +218,6 @@ def test_runnable_prompt(): for agent in ( create_react_agent(FakeToolCallingModel(), [], prompt=prompt), create_react_agent(FakeToolCallingModel(), [], state_modifier=prompt), - create_react_agent( - FakeToolCallingModel(), [], messages_modifier=messages_modifier - ), ): inputs = [HumanMessage("hi?")] response = agent.invoke({"messages": inputs}) @@ -630,1105 +531,30 @@ def test_react_agent_with_structured_response(version: str) -> None: assert response["messages"][-2].content == "The weather is sunny and 75°F." -# tools for testing ToolNode -def tool1(some_val: int, some_other_val: str) -> str: - """Tool 1 docstring.""" - if some_val == 0: - raise ValueError("Test error") - return f"{some_val} - {some_other_val}" +class CustomState(AgentState): + user_name: str -async def tool2(some_val: int, some_other_val: str) -> str: - """Tool 2 docstring.""" - if some_val == 0: - raise ToolException("Test error") - return f"tool2: {some_val} - {some_other_val}" - - -async def tool3(some_val: int, some_other_val: str) -> str: - """Tool 3 docstring.""" - return [ - {"key_1": some_val, "key_2": "foo"}, - {"key_1": some_other_val, "key_2": "baz"}, - ] - - -async def tool4(some_val: int, some_other_val: str) -> str: - """Tool 4 docstring.""" - return [ - {"type": "image_url", "image_url": {"url": "abdc"}}, - ] - - -@dec_tool -def tool5(some_val: int): - """Tool 5 docstring.""" - raise ToolException("Test error") - - -tool5.handle_tool_error = "foo" - - -async def test_tool_node(): - result = ToolNode([tool1]).invoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool1", - "args": {"some_val": 1, "some_other_val": "foo"}, - "id": "some 0", - } - ], - ) - ] - } - ) - - tool_message: ToolMessage = result["messages"][-1] - assert tool_message.type == "tool" - assert tool_message.content == "1 - foo" - assert tool_message.tool_call_id == "some 0" - - result2 = await ToolNode([tool2]).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool2", - "args": {"some_val": 2, "some_other_val": "bar"}, - "id": "some 1", - } - ], - ) - ] - } - ) - - tool_message: ToolMessage = result2["messages"][-1] - assert tool_message.type == "tool" - assert tool_message.content == "tool2: 2 - bar" - - # list of dicts tool content - result3 = await ToolNode([tool3]).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool3", - "args": {"some_val": 2, "some_other_val": "bar"}, - "id": "some 2", - } - ], - ) - ] - } - ) - tool_message: ToolMessage = result3["messages"][-1] - assert tool_message.type == "tool" - assert ( - tool_message.content - == '[{"key_1": 2, "key_2": "foo"}, {"key_1": "bar", "key_2": "baz"}]' - ) - assert tool_message.tool_call_id == "some 2" - - # list of content blocks tool content - result4 = await ToolNode([tool4]).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool4", - "args": {"some_val": 2, "some_other_val": "bar"}, - "id": "some 3", - } - ], - ) - ] - } - ) - tool_message: ToolMessage = result4["messages"][-1] - assert tool_message.type == "tool" - assert tool_message.content == [{"type": "image_url", "image_url": {"url": "abdc"}}] - assert tool_message.tool_call_id == "some 3" - - -async def test_tool_node_tool_call_input(): - # Single tool call - tool_call_1 = { - "name": "tool1", - "args": {"some_val": 1, "some_other_val": "foo"}, - "id": "some 0", - "type": "tool_call", - } - result = ToolNode([tool1]).invoke([tool_call_1]) - assert result["messages"] == [ - ToolMessage(content="1 - foo", tool_call_id="some 0", name="tool1"), - ] - - # Multiple tool calls - tool_call_2 = { - "name": "tool1", - "args": {"some_val": 2, "some_other_val": "bar"}, - "id": "some 1", - "type": "tool_call", - } - result = ToolNode([tool1]).invoke([tool_call_1, tool_call_2]) - assert result["messages"] == [ - ToolMessage(content="1 - foo", tool_call_id="some 0", name="tool1"), - ToolMessage(content="2 - bar", tool_call_id="some 1", name="tool1"), - ] - - # Test with unknown tool - tool_call_3 = tool_call_1.copy() - tool_call_3["name"] = "tool2" - result = ToolNode([tool1]).invoke([tool_call_1, tool_call_3]) - assert result["messages"] == [ - ToolMessage(content="1 - foo", tool_call_id="some 0", name="tool1"), - ToolMessage( - content="Error: tool2 is not a valid tool, try one of [tool1].", - name="tool2", - tool_call_id="some 0", - status="error", - ), - ] - - -async def test_tool_node_error_handling(): - def handle_all(e: Union[ValueError, ToolException, ValidationError]): - return TOOL_CALL_ERROR_TEMPLATE.format(error=repr(e)) - - # test catching all exceptions, via: - # - handle_tool_errors = True - # - passing a tuple of all exceptions - # - passing a callable with all exceptions in the signature - for handle_tool_errors in ( - True, - (ValueError, ToolException, ValidationError), - handle_all, - ): - result_error = await ToolNode( - [tool1, tool2, tool3], handle_tool_errors=handle_tool_errors - ).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool1", - "args": {"some_val": 0, "some_other_val": "foo"}, - "id": "some id", - }, - { - "name": "tool2", - "args": {"some_val": 0, "some_other_val": "bar"}, - "id": "some other id", - }, - { - "name": "tool3", - "args": {"some_val": 0}, - "id": "another id", - }, - ], - ) - ] - } - ) - - assert all(m.type == "tool" for m in result_error["messages"]) - assert all(m.status == "error" for m in result_error["messages"]) - assert ( - result_error["messages"][0].content - == f"Error: {repr(ValueError('Test error'))}\n Please fix your mistakes." - ) - assert ( - result_error["messages"][1].content - == f"Error: {repr(ToolException('Test error'))}\n Please fix your mistakes." - ) - assert ( - "ValidationError" in result_error["messages"][2].content - or "validation error" in result_error["messages"][2].content - ) - - assert result_error["messages"][0].tool_call_id == "some id" - assert result_error["messages"][1].tool_call_id == "some other id" - assert result_error["messages"][2].tool_call_id == "another id" - - -async def test_tool_node_error_handling_callable(): - def handle_value_error(e: ValueError): - return "Value error" - - def handle_tool_exception(e: ToolException): - return "Tool exception" - - for handle_tool_errors in ("Value error", handle_value_error): - result_error = await ToolNode( - [tool1], handle_tool_errors=handle_tool_errors - ).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool1", - "args": {"some_val": 0, "some_other_val": "foo"}, - "id": "some id", - }, - ], - ) - ] - } - ) - tool_message: ToolMessage = result_error["messages"][-1] - assert tool_message.type == "tool" - assert tool_message.status == "error" - assert tool_message.content == "Value error" - - # test raising for an unhandled exception, via: - # - passing a tuple of all exceptions - # - passing a callable with all exceptions in the signature - for handle_tool_errors in ((ValueError,), handle_value_error): - with pytest.raises(ToolException) as exc_info: - await ToolNode( - [tool1, tool2], handle_tool_errors=handle_tool_errors - ).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool1", - "args": {"some_val": 0, "some_other_val": "foo"}, - "id": "some id", - }, - { - "name": "tool2", - "args": {"some_val": 0, "some_other_val": "bar"}, - "id": "some other id", - }, - ], - ) - ] - } - ) - assert str(exc_info.value) == "Test error" - - for handle_tool_errors in ((ToolException,), handle_tool_exception): - with pytest.raises(ValueError) as exc_info: - await ToolNode( - [tool1, tool2], handle_tool_errors=handle_tool_errors - ).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool1", - "args": {"some_val": 0, "some_other_val": "foo"}, - "id": "some id", - }, - { - "name": "tool2", - "args": {"some_val": 0, "some_other_val": "bar"}, - "id": "some other id", - }, - ], - ) - ] - } - ) - assert str(exc_info.value) == "Test error" - - -async def test_tool_node_handle_tool_errors_false(): - with pytest.raises(ValueError) as exc_info: - ToolNode([tool1], handle_tool_errors=False).invoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool1", - "args": {"some_val": 0, "some_other_val": "foo"}, - "id": "some id", - } - ], - ) - ] - } - ) - - assert str(exc_info.value) == "Test error" - - with pytest.raises(ToolException): - await ToolNode([tool2], handle_tool_errors=False).ainvoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool2", - "args": {"some_val": 0, "some_other_val": "bar"}, - "id": "some id", - } - ], - ) - ] - } - ) - - assert str(exc_info.value) == "Test error" - - # test validation errors get raised if handle_tool_errors is False - with pytest.raises((ValidationError, ValidationErrorV1)): - ToolNode([tool1], handle_tool_errors=False).invoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool1", - "args": {"some_val": 0}, - "id": "some id", - } - ], - ) - ] - } - ) - - -def test_tool_node_individual_tool_error_handling(): - # test error handling on individual tools (and that it overrides overall error handling!) - result_individual_tool_error_handler = ToolNode( - [tool5], handle_tool_errors="bar" - ).invoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool5", - "args": {"some_val": 0}, - "id": "some 0", - } - ], - ) - ] - } - ) - - tool_message: ToolMessage = result_individual_tool_error_handler["messages"][-1] - assert tool_message.type == "tool" - assert tool_message.status == "error" - assert tool_message.content == "foo" - assert tool_message.tool_call_id == "some 0" - - -def test_tool_node_incorrect_tool_name(): - result_incorrect_name = ToolNode([tool1, tool2]).invoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool3", - "args": {"some_val": 1, "some_other_val": "foo"}, - "id": "some 0", - } - ], - ) - ] - } - ) - - tool_message: ToolMessage = result_incorrect_name["messages"][-1] - assert tool_message.type == "tool" - assert tool_message.status == "error" - assert ( - tool_message.content - == "Error: tool3 is not a valid tool, try one of [tool1, tool2]." - ) - assert tool_message.tool_call_id == "some 0" +class CustomStatePydantic(AgentStatePydantic): + user_name: Optional[str] = None +@pytest.mark.skipif( + not IS_LANGCHAIN_CORE_030_OR_GREATER, + reason="Langchain core 0.3.0 or greater is required", +) +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) @pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) -def test_tool_node_node_interrupt(version: str): - def tool_normal(some_val: int) -> str: - """Tool docstring.""" - return "normal" - - def tool_interrupt(some_val: int) -> str: - """Tool docstring.""" - raise NodeInterrupt("foo") - - def handle(e: NodeInterrupt): - return "handled" - - for handle_tool_errors in (True, (NodeInterrupt,), "handled", handle, False): - node = ToolNode([tool_interrupt], handle_tool_errors=handle_tool_errors) - with pytest.raises(NodeInterrupt) as exc_info: - node.invoke( - { - "messages": [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": "tool_interrupt", - "args": {"some_val": 0}, - "id": "some 0", - } - ], - ) - ] - } - ) - assert exc_info.value == "foo" - - # test inside react agent - model = FakeToolCallingModel( - tool_calls=[ - [ - ToolCall(name="tool_interrupt", args={"some_val": 0}, id="1"), - ToolCall(name="tool_normal", args={"some_val": 1}, id="2"), - ], - [], - ] +@pytest.mark.parametrize("state_schema", [CustomState, CustomStatePydantic]) +def test_react_agent_update_state( + request: pytest.FixtureRequest, + checkpointer_name: str, + version: str, + state_schema: StateSchemaType, +) -> None: + checkpointer: BaseCheckpointSaver = request.getfixturevalue( + "checkpointer_" + checkpointer_name ) - checkpointer = MemorySaver() - config = {"configurable": {"thread_id": "1"}} - agent = create_react_agent( - model, - [tool_interrupt, tool_normal], - checkpointer=checkpointer, - version=version, - ) - result = agent.invoke({"messages": [HumanMessage("hi?")]}, config) - expected_messages = [ - _AnyIdHumanMessage(content="hi?"), - AIMessage( - content="hi?", - id="0", - tool_calls=[ - { - "name": "tool_interrupt", - "args": {"some_val": 0}, - "id": "1", - "type": "tool_call", - }, - { - "name": "tool_normal", - "args": {"some_val": 1}, - "id": "2", - "type": "tool_call", - }, - ], - ), - _AnyIdToolMessage(content="normal", name="tool_normal", tool_call_id="2"), - ] - if version == "v1": - # Interrupt blocks second tool result - assert result["messages"] == expected_messages[:-1] - elif version == "v2": - assert result["messages"] == expected_messages - - state = agent.get_state(config) - assert state.next == ("tools",) - task = state.tasks[0] - assert task.name == "tools" - assert task.interrupts == (Interrupt(value="foo", when="during"),) - - -@pytest.mark.skipif( - not IS_LANGCHAIN_CORE_030_OR_GREATER, - reason="Langchain core 0.3.0 or greater is required", -) -@pytest.mark.parametrize("input_type", ["dict", "tool_calls"]) -async def test_tool_node_command(input_type: str): - from langchain_core.tools.base import InjectedToolCallId - - @dec_tool - def transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): - """Transfer to Bob""" - return Command( - update={ - "messages": [ - ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) - ] - }, - goto="bob", - graph=Command.PARENT, - ) - - @dec_tool - async def async_transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): - """Transfer to Bob""" - return Command( - update={ - "messages": [ - ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) - ] - }, - goto="bob", - graph=Command.PARENT, - ) - - class CustomToolSchema(BaseModel): - tool_call_id: Annotated[str, InjectedToolCallId] - - class MyCustomTool(BaseTool): - def _run(*args: Any, **kwargs: Any): - return Command( - update={ - "messages": [ - ToolMessage( - content="Transferred to Bob", - tool_call_id=kwargs["tool_call_id"], - ) - ] - }, - goto="bob", - graph=Command.PARENT, - ) - - async def _arun(*args: Any, **kwargs: Any): - return Command( - update={ - "messages": [ - ToolMessage( - content="Transferred to Bob", - tool_call_id=kwargs["tool_call_id"], - ) - ] - }, - goto="bob", - graph=Command.PARENT, - ) - - custom_tool = MyCustomTool( - name="custom_transfer_to_bob", - description="Transfer to bob", - args_schema=CustomToolSchema, - ) - async_custom_tool = MyCustomTool( - name="async_custom_transfer_to_bob", - description="Transfer to bob", - args_schema=CustomToolSchema, - ) - - # test mixing regular tools and tools returning commands - def add(a: int, b: int) -> int: - """Add two numbers""" - return a + b - - tool_calls = [ - {"args": {"a": 1, "b": 2}, "id": "1", "name": "add", "type": "tool_call"}, - {"args": {}, "id": "2", "name": "transfer_to_bob", "type": "tool_call"}, - ] - if input_type == "dict": - input_ = {"messages": [AIMessage("", tool_calls=tool_calls)]} - elif input_type == "tool_calls": - input_ = tool_calls - result = ToolNode([add, transfer_to_bob]).invoke(input_) - - assert result == [ - { - "messages": [ - ToolMessage( - content="3", - tool_call_id="1", - name="add", - ) - ] - }, - Command( - update={ - "messages": [ - ToolMessage( - content="Transferred to Bob", - tool_call_id="2", - name="transfer_to_bob", - ) - ] - }, - goto="bob", - graph=Command.PARENT, - ), - ] - - # test tools returning commands - - # test sync tools - for tool in [transfer_to_bob, custom_tool]: - result = ToolNode([tool]).invoke( - { - "messages": [ - AIMessage( - "", tool_calls=[{"args": {}, "id": "1", "name": tool.name}] - ) - ] - } - ) - assert result == [ - Command( - update={ - "messages": [ - ToolMessage( - content="Transferred to Bob", - tool_call_id="1", - name=tool.name, - ) - ] - }, - goto="bob", - graph=Command.PARENT, - ) - ] - - # test async tools - for tool in [async_transfer_to_bob, async_custom_tool]: - result = await ToolNode([tool]).ainvoke( - { - "messages": [ - AIMessage( - "", tool_calls=[{"args": {}, "id": "1", "name": tool.name}] - ) - ] - } - ) - assert result == [ - Command( - update={ - "messages": [ - ToolMessage( - content="Transferred to Bob", - tool_call_id="1", - name=tool.name, - ) - ] - }, - goto="bob", - graph=Command.PARENT, - ) - ] - - # test multiple commands - result = ToolNode([transfer_to_bob, custom_tool]).invoke( - { - "messages": [ - AIMessage( - "", - tool_calls=[ - {"args": {}, "id": "1", "name": "transfer_to_bob"}, - {"args": {}, "id": "2", "name": "custom_transfer_to_bob"}, - ], - ) - ] - } - ) - assert result == [ - Command( - update={ - "messages": [ - ToolMessage( - content="Transferred to Bob", - tool_call_id="1", - name="transfer_to_bob", - ) - ] - }, - goto="bob", - graph=Command.PARENT, - ), - Command( - update={ - "messages": [ - ToolMessage( - content="Transferred to Bob", - tool_call_id="2", - name="custom_transfer_to_bob", - ) - ] - }, - goto="bob", - graph=Command.PARENT, - ), - ] - - # test validation (mismatch between input type and command.update type) - with pytest.raises(ValueError): - - @dec_tool - def list_update_tool(tool_call_id: Annotated[str, InjectedToolCallId]): - """My tool""" - return Command( - update=[ToolMessage(content="foo", tool_call_id=tool_call_id)] - ) - - ToolNode([list_update_tool]).invoke( - { - "messages": [ - AIMessage( - "", - tool_calls=[ - {"args": {}, "id": "1", "name": "list_update_tool"} - ], - ) - ] - } - ) - - # test validation (missing tool message in the update for current graph) - with pytest.raises(ValueError): - - @dec_tool - def no_update_tool(): - """My tool""" - return Command(update={"messages": []}) - - ToolNode([no_update_tool]).invoke( - { - "messages": [ - AIMessage( - "", - tool_calls=[{"args": {}, "id": "1", "name": "no_update_tool"}], - ) - ] - } - ) - - # test validation (tool message with a wrong tool call ID) - with pytest.raises(ValueError): - - @dec_tool - def mismatching_tool_call_id_tool(): - """My tool""" - return Command( - update={"messages": [ToolMessage(content="foo", tool_call_id="2")]} - ) - - ToolNode([mismatching_tool_call_id_tool]).invoke( - { - "messages": [ - AIMessage( - "", - tool_calls=[ - { - "args": {}, - "id": "1", - "name": "mismatching_tool_call_id_tool", - } - ], - ) - ] - } - ) - - # test validation (missing tool message in the update for parent graph is OK) - @dec_tool - def node_update_parent_tool(): - """No update""" - return Command(update={"messages": []}, graph=Command.PARENT) - - assert ToolNode([node_update_parent_tool]).invoke( - { - "messages": [ - AIMessage( - "", - tool_calls=[ - {"args": {}, "id": "1", "name": "node_update_parent_tool"} - ], - ) - ] - } - ) == [Command(update={"messages": []}, graph=Command.PARENT)] - - -@pytest.mark.skipif( - not IS_LANGCHAIN_CORE_030_OR_GREATER, - reason="Langchain core 0.3.0 or greater is required", -) -async def test_tool_node_command_list_input(): - from langchain_core.tools.base import InjectedToolCallId - - @dec_tool - def transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): - """Transfer to Bob""" - return Command( - update=[ - ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) - ], - goto="bob", - graph=Command.PARENT, - ) - - @dec_tool - async def async_transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): - """Transfer to Bob""" - return Command( - update=[ - ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) - ], - goto="bob", - graph=Command.PARENT, - ) - - class CustomToolSchema(BaseModel): - tool_call_id: Annotated[str, InjectedToolCallId] - - class MyCustomTool(BaseTool): - def _run(*args: Any, **kwargs: Any): - return Command( - update=[ - ToolMessage( - content="Transferred to Bob", - tool_call_id=kwargs["tool_call_id"], - ) - ], - goto="bob", - graph=Command.PARENT, - ) - - async def _arun(*args: Any, **kwargs: Any): - return Command( - update=[ - ToolMessage( - content="Transferred to Bob", - tool_call_id=kwargs["tool_call_id"], - ) - ], - goto="bob", - graph=Command.PARENT, - ) - - custom_tool = MyCustomTool( - name="custom_transfer_to_bob", - description="Transfer to bob", - args_schema=CustomToolSchema, - ) - async_custom_tool = MyCustomTool( - name="async_custom_transfer_to_bob", - description="Transfer to bob", - args_schema=CustomToolSchema, - ) - - # test mixing regular tools and tools returning commands - def add(a: int, b: int) -> int: - """Add two numbers""" - return a + b - - result = ToolNode([add, transfer_to_bob]).invoke( - [ - AIMessage( - "", - tool_calls=[ - {"args": {"a": 1, "b": 2}, "id": "1", "name": "add"}, - {"args": {}, "id": "2", "name": "transfer_to_bob"}, - ], - ) - ] - ) - - assert result == [ - [ - ToolMessage( - content="3", - tool_call_id="1", - name="add", - ) - ], - Command( - update=[ - ToolMessage( - content="Transferred to Bob", - tool_call_id="2", - name="transfer_to_bob", - ) - ], - goto="bob", - graph=Command.PARENT, - ), - ] - - # test tools returning commands - - # test sync tools - for tool in [transfer_to_bob, custom_tool]: - result = ToolNode([tool]).invoke( - [AIMessage("", tool_calls=[{"args": {}, "id": "1", "name": tool.name}])] - ) - assert result == [ - Command( - update=[ - ToolMessage( - content="Transferred to Bob", - tool_call_id="1", - name=tool.name, - ) - ], - goto="bob", - graph=Command.PARENT, - ) - ] - - # test async tools - for tool in [async_transfer_to_bob, async_custom_tool]: - result = await ToolNode([tool]).ainvoke( - [AIMessage("", tool_calls=[{"args": {}, "id": "1", "name": tool.name}])] - ) - assert result == [ - Command( - update=[ - ToolMessage( - content="Transferred to Bob", - tool_call_id="1", - name=tool.name, - ) - ], - goto="bob", - graph=Command.PARENT, - ) - ] - - # test multiple commands - result = ToolNode([transfer_to_bob, custom_tool]).invoke( - [ - AIMessage( - "", - tool_calls=[ - {"args": {}, "id": "1", "name": "transfer_to_bob"}, - {"args": {}, "id": "2", "name": "custom_transfer_to_bob"}, - ], - ) - ] - ) - assert result == [ - Command( - update=[ - ToolMessage( - content="Transferred to Bob", - tool_call_id="1", - name="transfer_to_bob", - ) - ], - goto="bob", - graph=Command.PARENT, - ), - Command( - update=[ - ToolMessage( - content="Transferred to Bob", - tool_call_id="2", - name="custom_transfer_to_bob", - ) - ], - goto="bob", - graph=Command.PARENT, - ), - ] - - # test validation (mismatch between input type and command.update type) - with pytest.raises(ValueError): - - @dec_tool - def list_update_tool(tool_call_id: Annotated[str, InjectedToolCallId]): - """My tool""" - return Command( - update={ - "messages": [ToolMessage(content="foo", tool_call_id=tool_call_id)] - } - ) - - ToolNode([list_update_tool]).invoke( - [ - AIMessage( - "", - tool_calls=[{"args": {}, "id": "1", "name": "list_update_tool"}], - ) - ] - ) - - # test validation (missing tool message in the update for current graph) - with pytest.raises(ValueError): - - @dec_tool - def no_update_tool(): - """My tool""" - return Command(update=[]) - - ToolNode([no_update_tool]).invoke( - [ - AIMessage( - "", - tool_calls=[{"args": {}, "id": "1", "name": "no_update_tool"}], - ) - ] - ) - - # test validation (tool message with a wrong tool call ID) - with pytest.raises(ValueError): - - @dec_tool - def mismatching_tool_call_id_tool(): - """My tool""" - return Command(update=[ToolMessage(content="foo", tool_call_id="2")]) - - ToolNode([mismatching_tool_call_id_tool]).invoke( - [ - AIMessage( - "", - tool_calls=[ - {"args": {}, "id": "1", "name": "mismatching_tool_call_id_tool"} - ], - ) - ] - ) - - # test validation (missing tool message in the update for parent graph is OK) - @dec_tool - def node_update_parent_tool(): - """No update""" - return Command(update=[], graph=Command.PARENT) - - assert ToolNode([node_update_parent_tool]).invoke( - [ - AIMessage( - "", - tool_calls=[{"args": {}, "id": "1", "name": "node_update_parent_tool"}], - ) - ] - ) == [Command(update=[], graph=Command.PARENT)] - - -@pytest.mark.skipif( - not IS_LANGCHAIN_CORE_030_OR_GREATER, - reason="Langchain core 0.3.0 or greater is required", -) -@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) -def test_react_agent_update_state(version: str): - from langchain_core.tools.base import InjectedToolCallId - - class State(AgentState): - user_name: str @dec_tool def get_user_name(tool_call_id: Annotated[str, InjectedToolCallId]): @@ -1745,21 +571,31 @@ def test_react_agent_update_state(version: str): } ) - def prompt(state: State): - user_name = state.get("user_name") - if user_name is None: - return state["messages"] + if issubclass(state_schema, AgentStatePydantic): - system_msg = f"User name is {user_name}" - return [{"role": "system", "content": system_msg}] + state["messages"] + def prompt(state: CustomStatePydantic): + user_name = state.user_name + if user_name is None: + return state.messages + + system_msg = f"User name is {user_name}" + return [{"role": "system", "content": system_msg}] + state.messages + else: + + def prompt(state: CustomState): + user_name = state.get("user_name") + if user_name is None: + return state["messages"] + + system_msg = f"User name is {user_name}" + return [{"role": "system", "content": system_msg}] + state["messages"] - checkpointer = MemorySaver() tool_calls = [[{"args": {}, "id": "1", "name": "get_user_name"}]] model = FakeToolCallingModel(tool_calls=tool_calls) agent = create_react_agent( model, [get_user_name], - state_schema=State, + state_schema=state_schema, prompt=prompt, checkpointer=checkpointer, version=version, @@ -1782,8 +618,21 @@ def test_react_agent_update_state(version: str): not IS_LANGCHAIN_CORE_030_OR_GREATER, reason="Langchain core 0.3.0 or greater is required", ) +@pytest.mark.parametrize( + "checkpointer_name", + [ + checkpointer + for checkpointer in ALL_CHECKPOINTERS_SYNC + if "shallow" not in checkpointer + ], +) @pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) -def test_react_agent_parallel_tool_calls(version: str): +def test_react_agent_parallel_tool_calls( + request: pytest.FixtureRequest, checkpointer_name: str, version: str +) -> None: + checkpointer: BaseCheckpointSaver = request.getfixturevalue( + "checkpointer_" + checkpointer_name + ) human_assistance_execution_count = 0 @dec_tool @@ -1803,7 +652,6 @@ def test_react_agent_parallel_tool_calls(version: str): get_weather_execution_count += 1 return "It's sunny!" - checkpointer = MemorySaver() tool_calls = [ [ {"args": {"location": "sf"}, "id": "1", "name": "get_weather"}, @@ -1859,76 +707,6 @@ def test_react_agent_parallel_tool_calls(version: str): assert get_weather_execution_count == 1 -def my_function(some_val: int, some_other_val: str) -> str: - return f"{some_val} - {some_other_val}" - - -class MyModel(BaseModel): - some_val: int - some_other_val: str - - -class MyModelV1(BaseModelV1): - some_val: int - some_other_val: str - - -@dec_tool -def my_tool(some_val: int, some_other_val: str) -> str: - """Cool.""" - return f"{some_val} - {some_other_val}" - - -@pytest.mark.parametrize( - "tool_schema", - [ - my_function, - MyModel, - MyModelV1, - my_tool, - ], -) -@pytest.mark.parametrize("use_message_key", [True, False]) -async def test_validation_node(tool_schema: Any, use_message_key: bool): - validation_node = ValidationNode([tool_schema]) - tool_name = getattr(tool_schema, "name", getattr(tool_schema, "__name__", None)) - inputs = [ - AIMessage( - "hi?", - tool_calls=[ - { - "name": tool_name, - "args": {"some_val": 1, "some_other_val": "foo"}, - "id": "some 0", - }, - { - "name": tool_name, - # Wrong type for some_val - "args": {"some_val": "bar", "some_other_val": "foo"}, - "id": "some 1", - }, - ], - ), - ] - if use_message_key: - inputs = {"messages": inputs} - result = await validation_node.ainvoke(inputs) - if use_message_key: - result = result["messages"] - - def check_results(messages: list): - assert len(messages) == 2 - assert all(m.type == "tool" for m in messages) - assert not messages[0].additional_kwargs.get("is_error") - assert messages[1].additional_kwargs.get("is_error") - - check_results(result) - result_sync = validation_node.invoke(inputs) - if use_message_key: - result_sync = result_sync["messages"] - check_results(result_sync) - - class _InjectStateSchema(TypedDict): messages: list foo: str @@ -2047,23 +825,45 @@ def test_tool_node_inject_state(schema_: Type[T]) -> None: assert tool_message.content == "hi?" -@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) -def test_create_react_agent_inject_vars(version: str) -> None: - class AgentStateExtraKey(AgentState): - foo: int +class AgentStateExtraKey(AgentState): + foo: int + +class AgentStateExtraKeyPydantic(AgentStatePydantic): + foo: int + + +@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) +@pytest.mark.parametrize( + "state_schema", [AgentStateExtraKey, AgentStateExtraKeyPydantic] +) +def test_create_react_agent_inject_vars( + version: str, state_schema: StateSchemaType +) -> None: store = InMemoryStore() namespace = ("test",) store.put(namespace, "test_key", {"bar": 3}) - def tool1( - some_val: int, - state: Annotated[dict, InjectedState], - store: Annotated[BaseStore, InjectedStore()], - ) -> str: - """Tool 1 docstring.""" - store_val = store.get(namespace, "test_key").value["bar"] - return some_val + state["foo"] + store_val + if issubclass(state_schema, AgentStatePydantic): + + def tool1( + some_val: int, + state: Annotated[AgentStateExtraKeyPydantic, InjectedState], + store: Annotated[BaseStore, InjectedStore()], + ) -> str: + """Tool 1 docstring.""" + store_val = store.get(namespace, "test_key").value["bar"] + return some_val + state.foo + store_val + else: + + def tool1( + some_val: int, + state: Annotated[dict, InjectedState], + store: Annotated[BaseStore, InjectedStore()], + ) -> str: + """Tool 1 docstring.""" + store_val = store.get(namespace, "test_key").value["bar"] + return some_val + state["foo"] + store_val tool_call = { "name": "tool1", @@ -2075,7 +875,7 @@ def test_create_react_agent_inject_vars(version: str) -> None: agent = create_react_agent( model, [tool1], - state_schema=AgentStateExtraKey, + state_schema=state_schema, store=store, version=version, ) @@ -2347,7 +1147,14 @@ def test_inspect_react() -> None: @pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) -def test_react_with_subgraph_tools(version: str) -> None: +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_react_with_subgraph_tools( + request: pytest.FixtureRequest, checkpointer_name: str, version: str +) -> None: + checkpointer: BaseCheckpointSaver = request.getfixturevalue( + "checkpointer_" + checkpointer_name + ) + class State(TypedDict): a: int b: int @@ -2394,7 +1201,6 @@ def test_react_with_subgraph_tools(version: str) -> None: [], ] ) - checkpointer = MemorySaver() tool_node = ToolNode([addition, multiplication], handle_tool_errors=False) agent = create_react_agent( model, @@ -2483,3 +1289,148 @@ def test_tool_node_stream_writer() -> None: }, ), ] + + +@pytest.mark.parametrize("version", REACT_TOOL_CALL_VERSIONS) +@pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_SYNC) +def test_tool_node_node_interrupt( + request: pytest.FixtureRequest, checkpointer_name: str, version: str +) -> None: + checkpointer: BaseCheckpointSaver = request.getfixturevalue( + "checkpointer_" + checkpointer_name + ) + + def tool_normal(some_val: int) -> str: + """Tool docstring.""" + return "normal" + + def tool_interrupt(some_val: int) -> str: + """Tool docstring.""" + foo = interrupt("provide value for foo") + return foo + + # test inside react agent + model = FakeToolCallingModel( + tool_calls=[ + [ + ToolCall(name="tool_interrupt", args={"some_val": 0}, id="1"), + ToolCall(name="tool_normal", args={"some_val": 1}, id="2"), + ], + [], + ] + ) + config = {"configurable": {"thread_id": "1"}} + agent = create_react_agent( + model, + [tool_interrupt, tool_normal], + checkpointer=checkpointer, + version=version, + ) + result = agent.invoke({"messages": [HumanMessage("hi?")]}, config) + expected_messages = [ + _AnyIdHumanMessage(content="hi?"), + AIMessage( + content="hi?", + id="0", + tool_calls=[ + { + "name": "tool_interrupt", + "args": {"some_val": 0}, + "id": "1", + "type": "tool_call", + }, + { + "name": "tool_normal", + "args": {"some_val": 1}, + "id": "2", + "type": "tool_call", + }, + ], + ), + _AnyIdToolMessage(content="normal", name="tool_normal", tool_call_id="2"), + ] + if version == "v1": + # Interrupt blocks second tool result + assert result["messages"] == expected_messages[:-1] + elif version == "v2": + assert result["messages"] == expected_messages + + # TODO: figure out why this is not working w/ shallow postgres checkpointer + if "shallow" in checkpointer_name: + return + + state = agent.get_state(config) + assert state.next == ("tools",) + task = state.tasks[0] + assert task.name == "tools" + assert task.interrupts == ( + Interrupt( + value="provide value for foo", + when="during", + resumable=True, + ns=[AnyStr("tools:")], + ), + ) + + +@pytest.mark.parametrize("tool_style", ["openai", "anthropic"]) +def test_should_bind_tools(tool_style: str) -> None: + @dec_tool + def some_tool(some_val: int) -> str: + """Tool docstring.""" + return "meow" + + @dec_tool + def some_other_tool(some_val: int) -> str: + """Tool docstring.""" + return "meow" + + model = FakeToolCallingModel(tool_style=tool_style) + # should bind when a regular model + assert _should_bind_tools(model, []) + assert _should_bind_tools(model, [some_tool]) + + # should bind when a seq + seq = model | RunnableLambda(lambda message: message) + assert _should_bind_tools(seq, []) + assert _should_bind_tools(seq, [some_tool]) + + # should not bind when a model with tools + assert not _should_bind_tools(model.bind_tools([some_tool]), [some_tool]) + # should not bind when a seq with tools + seq_with_tools = model.bind_tools([some_tool]) | RunnableLambda( + lambda message: message + ) + assert not _should_bind_tools(seq_with_tools, [some_tool]) + + # should raise on invalid inputs + with pytest.raises(ValueError): + _should_bind_tools(model.bind_tools([some_tool]), []) + with pytest.raises(ValueError): + _should_bind_tools(model.bind_tools([some_tool]), [some_other_tool]) + with pytest.raises(ValueError): + _should_bind_tools(model.bind_tools([some_tool]), [some_tool, some_other_tool]) + + +def test_get_model() -> None: + model = FakeToolCallingModel(tool_calls=[]) + assert _get_model(model) == model + + @dec_tool + def some_tool(some_val: int) -> str: + """Tool docstring.""" + return "meow" + + model_with_tools = model.bind_tools([some_tool]) + assert _get_model(model_with_tools) == model + + seq = model | RunnableLambda(lambda message: message) + assert _get_model(seq) == model + + seq_with_tools = model.bind_tools([some_tool]) | RunnableLambda( + lambda message: message + ) + assert _get_model(seq_with_tools) == model + + with pytest.raises(TypeError): + _get_model(RunnableLambda(lambda message: message)) diff --git a/libs/prebuilt/tests/test_tool_node.py b/libs/prebuilt/tests/test_tool_node.py new file mode 100644 index 000000000..2dd5ef635 --- /dev/null +++ b/libs/prebuilt/tests/test_tool_node.py @@ -0,0 +1,1053 @@ +from typing import ( + Annotated, + Any, + Union, +) + +import pytest +from langchain_core.messages import ( + AIMessage, + ToolMessage, +) +from langchain_core.tools import BaseTool, ToolException +from langchain_core.tools import tool as dec_tool +from pydantic import BaseModel, ValidationError +from pydantic.v1 import ValidationError as ValidationErrorV1 + +from langgraph.errors import NodeInterrupt +from langgraph.prebuilt import ToolNode +from langgraph.prebuilt.tool_node import TOOL_CALL_ERROR_TEMPLATE +from langgraph.types import Command +from tests.conftest import IS_LANGCHAIN_CORE_030_OR_GREATER + +pytestmark = pytest.mark.anyio + + +def tool1(some_val: int, some_other_val: str) -> str: + """Tool 1 docstring.""" + if some_val == 0: + raise ValueError("Test error") + return f"{some_val} - {some_other_val}" + + +async def tool2(some_val: int, some_other_val: str) -> str: + """Tool 2 docstring.""" + if some_val == 0: + raise ToolException("Test error") + return f"tool2: {some_val} - {some_other_val}" + + +async def tool3(some_val: int, some_other_val: str) -> str: + """Tool 3 docstring.""" + return [ + {"key_1": some_val, "key_2": "foo"}, + {"key_1": some_other_val, "key_2": "baz"}, + ] + + +async def tool4(some_val: int, some_other_val: str) -> str: + """Tool 4 docstring.""" + return [ + {"type": "image_url", "image_url": {"url": "abdc"}}, + ] + + +@dec_tool +def tool5(some_val: int): + """Tool 5 docstring.""" + raise ToolException("Test error") + + +tool5.handle_tool_error = "foo" + + +async def test_tool_node(): + result = ToolNode([tool1]).invoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool1", + "args": {"some_val": 1, "some_other_val": "foo"}, + "id": "some 0", + } + ], + ) + ] + } + ) + + tool_message: ToolMessage = result["messages"][-1] + assert tool_message.type == "tool" + assert tool_message.content == "1 - foo" + assert tool_message.tool_call_id == "some 0" + + result2 = await ToolNode([tool2]).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool2", + "args": {"some_val": 2, "some_other_val": "bar"}, + "id": "some 1", + } + ], + ) + ] + } + ) + + tool_message: ToolMessage = result2["messages"][-1] + assert tool_message.type == "tool" + assert tool_message.content == "tool2: 2 - bar" + + # list of dicts tool content + result3 = await ToolNode([tool3]).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool3", + "args": {"some_val": 2, "some_other_val": "bar"}, + "id": "some 2", + } + ], + ) + ] + } + ) + tool_message: ToolMessage = result3["messages"][-1] + assert tool_message.type == "tool" + assert ( + tool_message.content + == '[{"key_1": 2, "key_2": "foo"}, {"key_1": "bar", "key_2": "baz"}]' + ) + assert tool_message.tool_call_id == "some 2" + + # list of content blocks tool content + result4 = await ToolNode([tool4]).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool4", + "args": {"some_val": 2, "some_other_val": "bar"}, + "id": "some 3", + } + ], + ) + ] + } + ) + tool_message: ToolMessage = result4["messages"][-1] + assert tool_message.type == "tool" + assert tool_message.content == [{"type": "image_url", "image_url": {"url": "abdc"}}] + assert tool_message.tool_call_id == "some 3" + + +async def test_tool_node_tool_call_input(): + # Single tool call + tool_call_1 = { + "name": "tool1", + "args": {"some_val": 1, "some_other_val": "foo"}, + "id": "some 0", + "type": "tool_call", + } + result = ToolNode([tool1]).invoke([tool_call_1]) + assert result["messages"] == [ + ToolMessage(content="1 - foo", tool_call_id="some 0", name="tool1"), + ] + + # Multiple tool calls + tool_call_2 = { + "name": "tool1", + "args": {"some_val": 2, "some_other_val": "bar"}, + "id": "some 1", + "type": "tool_call", + } + result = ToolNode([tool1]).invoke([tool_call_1, tool_call_2]) + assert result["messages"] == [ + ToolMessage(content="1 - foo", tool_call_id="some 0", name="tool1"), + ToolMessage(content="2 - bar", tool_call_id="some 1", name="tool1"), + ] + + # Test with unknown tool + tool_call_3 = tool_call_1.copy() + tool_call_3["name"] = "tool2" + result = ToolNode([tool1]).invoke([tool_call_1, tool_call_3]) + assert result["messages"] == [ + ToolMessage(content="1 - foo", tool_call_id="some 0", name="tool1"), + ToolMessage( + content="Error: tool2 is not a valid tool, try one of [tool1].", + name="tool2", + tool_call_id="some 0", + status="error", + ), + ] + + +async def test_tool_node_error_handling(): + def handle_all(e: Union[ValueError, ToolException, ValidationError]): + return TOOL_CALL_ERROR_TEMPLATE.format(error=repr(e)) + + # test catching all exceptions, via: + # - handle_tool_errors = True + # - passing a tuple of all exceptions + # - passing a callable with all exceptions in the signature + for handle_tool_errors in ( + True, + (ValueError, ToolException, ValidationError), + handle_all, + ): + result_error = await ToolNode( + [tool1, tool2, tool3], handle_tool_errors=handle_tool_errors + ).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool1", + "args": {"some_val": 0, "some_other_val": "foo"}, + "id": "some id", + }, + { + "name": "tool2", + "args": {"some_val": 0, "some_other_val": "bar"}, + "id": "some other id", + }, + { + "name": "tool3", + "args": {"some_val": 0}, + "id": "another id", + }, + ], + ) + ] + } + ) + + assert all(m.type == "tool" for m in result_error["messages"]) + assert all(m.status == "error" for m in result_error["messages"]) + assert ( + result_error["messages"][0].content + == f"Error: {repr(ValueError('Test error'))}\n Please fix your mistakes." + ) + assert ( + result_error["messages"][1].content + == f"Error: {repr(ToolException('Test error'))}\n Please fix your mistakes." + ) + assert ( + "ValidationError" in result_error["messages"][2].content + or "validation error" in result_error["messages"][2].content + ) + + assert result_error["messages"][0].tool_call_id == "some id" + assert result_error["messages"][1].tool_call_id == "some other id" + assert result_error["messages"][2].tool_call_id == "another id" + + +async def test_tool_node_error_handling_callable(): + def handle_value_error(e: ValueError): + return "Value error" + + def handle_tool_exception(e: ToolException): + return "Tool exception" + + for handle_tool_errors in ("Value error", handle_value_error): + result_error = await ToolNode( + [tool1], handle_tool_errors=handle_tool_errors + ).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool1", + "args": {"some_val": 0, "some_other_val": "foo"}, + "id": "some id", + }, + ], + ) + ] + } + ) + tool_message: ToolMessage = result_error["messages"][-1] + assert tool_message.type == "tool" + assert tool_message.status == "error" + assert tool_message.content == "Value error" + + # test raising for an unhandled exception, via: + # - passing a tuple of all exceptions + # - passing a callable with all exceptions in the signature + for handle_tool_errors in ((ValueError,), handle_value_error): + with pytest.raises(ToolException) as exc_info: + await ToolNode( + [tool1, tool2], handle_tool_errors=handle_tool_errors + ).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool1", + "args": {"some_val": 0, "some_other_val": "foo"}, + "id": "some id", + }, + { + "name": "tool2", + "args": {"some_val": 0, "some_other_val": "bar"}, + "id": "some other id", + }, + ], + ) + ] + } + ) + assert str(exc_info.value) == "Test error" + + for handle_tool_errors in ((ToolException,), handle_tool_exception): + with pytest.raises(ValueError) as exc_info: + await ToolNode( + [tool1, tool2], handle_tool_errors=handle_tool_errors + ).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool1", + "args": {"some_val": 0, "some_other_val": "foo"}, + "id": "some id", + }, + { + "name": "tool2", + "args": {"some_val": 0, "some_other_val": "bar"}, + "id": "some other id", + }, + ], + ) + ] + } + ) + assert str(exc_info.value) == "Test error" + + +async def test_tool_node_handle_tool_errors_false(): + with pytest.raises(ValueError) as exc_info: + ToolNode([tool1], handle_tool_errors=False).invoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool1", + "args": {"some_val": 0, "some_other_val": "foo"}, + "id": "some id", + } + ], + ) + ] + } + ) + + assert str(exc_info.value) == "Test error" + + with pytest.raises(ToolException): + await ToolNode([tool2], handle_tool_errors=False).ainvoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool2", + "args": {"some_val": 0, "some_other_val": "bar"}, + "id": "some id", + } + ], + ) + ] + } + ) + + assert str(exc_info.value) == "Test error" + + # test validation errors get raised if handle_tool_errors is False + with pytest.raises((ValidationError, ValidationErrorV1)): + ToolNode([tool1], handle_tool_errors=False).invoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool1", + "args": {"some_val": 0}, + "id": "some id", + } + ], + ) + ] + } + ) + + +def test_tool_node_individual_tool_error_handling(): + # test error handling on individual tools (and that it overrides overall error handling!) + result_individual_tool_error_handler = ToolNode( + [tool5], handle_tool_errors="bar" + ).invoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool5", + "args": {"some_val": 0}, + "id": "some 0", + } + ], + ) + ] + } + ) + + tool_message: ToolMessage = result_individual_tool_error_handler["messages"][-1] + assert tool_message.type == "tool" + assert tool_message.status == "error" + assert tool_message.content == "foo" + assert tool_message.tool_call_id == "some 0" + + +def test_tool_node_incorrect_tool_name(): + result_incorrect_name = ToolNode([tool1, tool2]).invoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool3", + "args": {"some_val": 1, "some_other_val": "foo"}, + "id": "some 0", + } + ], + ) + ] + } + ) + + tool_message: ToolMessage = result_incorrect_name["messages"][-1] + assert tool_message.type == "tool" + assert tool_message.status == "error" + assert ( + tool_message.content + == "Error: tool3 is not a valid tool, try one of [tool1, tool2]." + ) + assert tool_message.tool_call_id == "some 0" + + +def test_tool_node_node_interrupt(): + def tool_interrupt(some_val: int) -> str: + """Tool docstring.""" + raise NodeInterrupt("foo") + + def handle(e: NodeInterrupt): + return "handled" + + for handle_tool_errors in (True, (NodeInterrupt,), "handled", handle, False): + node = ToolNode([tool_interrupt], handle_tool_errors=handle_tool_errors) + with pytest.raises(NodeInterrupt) as exc_info: + node.invoke( + { + "messages": [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": "tool_interrupt", + "args": {"some_val": 0}, + "id": "some 0", + } + ], + ) + ] + } + ) + assert exc_info.value == "foo" + + +@pytest.mark.skipif( + not IS_LANGCHAIN_CORE_030_OR_GREATER, + reason="Langchain core 0.3.0 or greater is required", +) +@pytest.mark.parametrize("input_type", ["dict", "tool_calls"]) +async def test_tool_node_command(input_type: str): + from langchain_core.tools.base import InjectedToolCallId + + @dec_tool + def transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): + """Transfer to Bob""" + return Command( + update={ + "messages": [ + ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) + ] + }, + goto="bob", + graph=Command.PARENT, + ) + + @dec_tool + async def async_transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): + """Transfer to Bob""" + return Command( + update={ + "messages": [ + ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) + ] + }, + goto="bob", + graph=Command.PARENT, + ) + + class CustomToolSchema(BaseModel): + tool_call_id: Annotated[str, InjectedToolCallId] + + class MyCustomTool(BaseTool): + def _run(*args: Any, **kwargs: Any): + return Command( + update={ + "messages": [ + ToolMessage( + content="Transferred to Bob", + tool_call_id=kwargs["tool_call_id"], + ) + ] + }, + goto="bob", + graph=Command.PARENT, + ) + + async def _arun(*args: Any, **kwargs: Any): + return Command( + update={ + "messages": [ + ToolMessage( + content="Transferred to Bob", + tool_call_id=kwargs["tool_call_id"], + ) + ] + }, + goto="bob", + graph=Command.PARENT, + ) + + custom_tool = MyCustomTool( + name="custom_transfer_to_bob", + description="Transfer to bob", + args_schema=CustomToolSchema, + ) + async_custom_tool = MyCustomTool( + name="async_custom_transfer_to_bob", + description="Transfer to bob", + args_schema=CustomToolSchema, + ) + + # test mixing regular tools and tools returning commands + def add(a: int, b: int) -> int: + """Add two numbers""" + return a + b + + tool_calls = [ + {"args": {"a": 1, "b": 2}, "id": "1", "name": "add", "type": "tool_call"}, + {"args": {}, "id": "2", "name": "transfer_to_bob", "type": "tool_call"}, + ] + if input_type == "dict": + input_ = {"messages": [AIMessage("", tool_calls=tool_calls)]} + elif input_type == "tool_calls": + input_ = tool_calls + result = ToolNode([add, transfer_to_bob]).invoke(input_) + + assert result == [ + { + "messages": [ + ToolMessage( + content="3", + tool_call_id="1", + name="add", + ) + ] + }, + Command( + update={ + "messages": [ + ToolMessage( + content="Transferred to Bob", + tool_call_id="2", + name="transfer_to_bob", + ) + ] + }, + goto="bob", + graph=Command.PARENT, + ), + ] + + # test tools returning commands + + # test sync tools + for tool in [transfer_to_bob, custom_tool]: + result = ToolNode([tool]).invoke( + { + "messages": [ + AIMessage( + "", tool_calls=[{"args": {}, "id": "1", "name": tool.name}] + ) + ] + } + ) + assert result == [ + Command( + update={ + "messages": [ + ToolMessage( + content="Transferred to Bob", + tool_call_id="1", + name=tool.name, + ) + ] + }, + goto="bob", + graph=Command.PARENT, + ) + ] + + # test async tools + for tool in [async_transfer_to_bob, async_custom_tool]: + result = await ToolNode([tool]).ainvoke( + { + "messages": [ + AIMessage( + "", tool_calls=[{"args": {}, "id": "1", "name": tool.name}] + ) + ] + } + ) + assert result == [ + Command( + update={ + "messages": [ + ToolMessage( + content="Transferred to Bob", + tool_call_id="1", + name=tool.name, + ) + ] + }, + goto="bob", + graph=Command.PARENT, + ) + ] + + # test multiple commands + result = ToolNode([transfer_to_bob, custom_tool]).invoke( + { + "messages": [ + AIMessage( + "", + tool_calls=[ + {"args": {}, "id": "1", "name": "transfer_to_bob"}, + {"args": {}, "id": "2", "name": "custom_transfer_to_bob"}, + ], + ) + ] + } + ) + assert result == [ + Command( + update={ + "messages": [ + ToolMessage( + content="Transferred to Bob", + tool_call_id="1", + name="transfer_to_bob", + ) + ] + }, + goto="bob", + graph=Command.PARENT, + ), + Command( + update={ + "messages": [ + ToolMessage( + content="Transferred to Bob", + tool_call_id="2", + name="custom_transfer_to_bob", + ) + ] + }, + goto="bob", + graph=Command.PARENT, + ), + ] + + # test validation (mismatch between input type and command.update type) + with pytest.raises(ValueError): + + @dec_tool + def list_update_tool(tool_call_id: Annotated[str, InjectedToolCallId]): + """My tool""" + return Command( + update=[ToolMessage(content="foo", tool_call_id=tool_call_id)] + ) + + ToolNode([list_update_tool]).invoke( + { + "messages": [ + AIMessage( + "", + tool_calls=[ + {"args": {}, "id": "1", "name": "list_update_tool"} + ], + ) + ] + } + ) + + # test validation (missing tool message in the update for current graph) + with pytest.raises(ValueError): + + @dec_tool + def no_update_tool(): + """My tool""" + return Command(update={"messages": []}) + + ToolNode([no_update_tool]).invoke( + { + "messages": [ + AIMessage( + "", + tool_calls=[{"args": {}, "id": "1", "name": "no_update_tool"}], + ) + ] + } + ) + + # test validation (tool message with a wrong tool call ID) + with pytest.raises(ValueError): + + @dec_tool + def mismatching_tool_call_id_tool(): + """My tool""" + return Command( + update={"messages": [ToolMessage(content="foo", tool_call_id="2")]} + ) + + ToolNode([mismatching_tool_call_id_tool]).invoke( + { + "messages": [ + AIMessage( + "", + tool_calls=[ + { + "args": {}, + "id": "1", + "name": "mismatching_tool_call_id_tool", + } + ], + ) + ] + } + ) + + # test validation (missing tool message in the update for parent graph is OK) + @dec_tool + def node_update_parent_tool(): + """No update""" + return Command(update={"messages": []}, graph=Command.PARENT) + + assert ToolNode([node_update_parent_tool]).invoke( + { + "messages": [ + AIMessage( + "", + tool_calls=[ + {"args": {}, "id": "1", "name": "node_update_parent_tool"} + ], + ) + ] + } + ) == [Command(update={"messages": []}, graph=Command.PARENT)] + + +@pytest.mark.skipif( + not IS_LANGCHAIN_CORE_030_OR_GREATER, + reason="Langchain core 0.3.0 or greater is required", +) +async def test_tool_node_command_list_input(): + from langchain_core.tools.base import InjectedToolCallId + + @dec_tool + def transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): + """Transfer to Bob""" + return Command( + update=[ + ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) + ], + goto="bob", + graph=Command.PARENT, + ) + + @dec_tool + async def async_transfer_to_bob(tool_call_id: Annotated[str, InjectedToolCallId]): + """Transfer to Bob""" + return Command( + update=[ + ToolMessage(content="Transferred to Bob", tool_call_id=tool_call_id) + ], + goto="bob", + graph=Command.PARENT, + ) + + class CustomToolSchema(BaseModel): + tool_call_id: Annotated[str, InjectedToolCallId] + + class MyCustomTool(BaseTool): + def _run(*args: Any, **kwargs: Any): + return Command( + update=[ + ToolMessage( + content="Transferred to Bob", + tool_call_id=kwargs["tool_call_id"], + ) + ], + goto="bob", + graph=Command.PARENT, + ) + + async def _arun(*args: Any, **kwargs: Any): + return Command( + update=[ + ToolMessage( + content="Transferred to Bob", + tool_call_id=kwargs["tool_call_id"], + ) + ], + goto="bob", + graph=Command.PARENT, + ) + + custom_tool = MyCustomTool( + name="custom_transfer_to_bob", + description="Transfer to bob", + args_schema=CustomToolSchema, + ) + async_custom_tool = MyCustomTool( + name="async_custom_transfer_to_bob", + description="Transfer to bob", + args_schema=CustomToolSchema, + ) + + # test mixing regular tools and tools returning commands + def add(a: int, b: int) -> int: + """Add two numbers""" + return a + b + + result = ToolNode([add, transfer_to_bob]).invoke( + [ + AIMessage( + "", + tool_calls=[ + {"args": {"a": 1, "b": 2}, "id": "1", "name": "add"}, + {"args": {}, "id": "2", "name": "transfer_to_bob"}, + ], + ) + ] + ) + + assert result == [ + [ + ToolMessage( + content="3", + tool_call_id="1", + name="add", + ) + ], + Command( + update=[ + ToolMessage( + content="Transferred to Bob", + tool_call_id="2", + name="transfer_to_bob", + ) + ], + goto="bob", + graph=Command.PARENT, + ), + ] + + # test tools returning commands + + # test sync tools + for tool in [transfer_to_bob, custom_tool]: + result = ToolNode([tool]).invoke( + [AIMessage("", tool_calls=[{"args": {}, "id": "1", "name": tool.name}])] + ) + assert result == [ + Command( + update=[ + ToolMessage( + content="Transferred to Bob", + tool_call_id="1", + name=tool.name, + ) + ], + goto="bob", + graph=Command.PARENT, + ) + ] + + # test async tools + for tool in [async_transfer_to_bob, async_custom_tool]: + result = await ToolNode([tool]).ainvoke( + [AIMessage("", tool_calls=[{"args": {}, "id": "1", "name": tool.name}])] + ) + assert result == [ + Command( + update=[ + ToolMessage( + content="Transferred to Bob", + tool_call_id="1", + name=tool.name, + ) + ], + goto="bob", + graph=Command.PARENT, + ) + ] + + # test multiple commands + result = ToolNode([transfer_to_bob, custom_tool]).invoke( + [ + AIMessage( + "", + tool_calls=[ + {"args": {}, "id": "1", "name": "transfer_to_bob"}, + {"args": {}, "id": "2", "name": "custom_transfer_to_bob"}, + ], + ) + ] + ) + assert result == [ + Command( + update=[ + ToolMessage( + content="Transferred to Bob", + tool_call_id="1", + name="transfer_to_bob", + ) + ], + goto="bob", + graph=Command.PARENT, + ), + Command( + update=[ + ToolMessage( + content="Transferred to Bob", + tool_call_id="2", + name="custom_transfer_to_bob", + ) + ], + goto="bob", + graph=Command.PARENT, + ), + ] + + # test validation (mismatch between input type and command.update type) + with pytest.raises(ValueError): + + @dec_tool + def list_update_tool(tool_call_id: Annotated[str, InjectedToolCallId]): + """My tool""" + return Command( + update={ + "messages": [ToolMessage(content="foo", tool_call_id=tool_call_id)] + } + ) + + ToolNode([list_update_tool]).invoke( + [ + AIMessage( + "", + tool_calls=[{"args": {}, "id": "1", "name": "list_update_tool"}], + ) + ] + ) + + # test validation (missing tool message in the update for current graph) + with pytest.raises(ValueError): + + @dec_tool + def no_update_tool(): + """My tool""" + return Command(update=[]) + + ToolNode([no_update_tool]).invoke( + [ + AIMessage( + "", + tool_calls=[{"args": {}, "id": "1", "name": "no_update_tool"}], + ) + ] + ) + + # test validation (tool message with a wrong tool call ID) + with pytest.raises(ValueError): + + @dec_tool + def mismatching_tool_call_id_tool(): + """My tool""" + return Command(update=[ToolMessage(content="foo", tool_call_id="2")]) + + ToolNode([mismatching_tool_call_id_tool]).invoke( + [ + AIMessage( + "", + tool_calls=[ + {"args": {}, "id": "1", "name": "mismatching_tool_call_id_tool"} + ], + ) + ] + ) + + # test validation (missing tool message in the update for parent graph is OK) + @dec_tool + def node_update_parent_tool(): + """No update""" + return Command(update=[], graph=Command.PARENT) + + assert ToolNode([node_update_parent_tool]).invoke( + [ + AIMessage( + "", + tool_calls=[{"args": {}, "id": "1", "name": "node_update_parent_tool"}], + ) + ] + ) == [Command(update=[], graph=Command.PARENT)] diff --git a/libs/prebuilt/tests/test_validation_node.py b/libs/prebuilt/tests/test_validation_node.py new file mode 100644 index 000000000..58e670f9a --- /dev/null +++ b/libs/prebuilt/tests/test_validation_node.py @@ -0,0 +1,81 @@ +from typing import Any + +import pytest +from langchain_core.messages import AIMessage +from langchain_core.tools import tool as dec_tool +from pydantic import BaseModel +from pydantic.v1 import BaseModel as BaseModelV1 + +from langgraph.prebuilt import ValidationNode + +pytestmark = pytest.mark.anyio + + +def my_function(some_val: int, some_other_val: str) -> str: + return f"{some_val} - {some_other_val}" + + +class MyModel(BaseModel): + some_val: int + some_other_val: str + + +class MyModelV1(BaseModelV1): + some_val: int + some_other_val: str + + +@dec_tool +def my_tool(some_val: int, some_other_val: str) -> str: + """Cool.""" + return f"{some_val} - {some_other_val}" + + +@pytest.mark.parametrize( + "tool_schema", + [ + my_function, + MyModel, + MyModelV1, + my_tool, + ], +) +@pytest.mark.parametrize("use_message_key", [True, False]) +async def test_validation_node(tool_schema: Any, use_message_key: bool): + validation_node = ValidationNode([tool_schema]) + tool_name = getattr(tool_schema, "name", getattr(tool_schema, "__name__", None)) + inputs = [ + AIMessage( + "hi?", + tool_calls=[ + { + "name": tool_name, + "args": {"some_val": 1, "some_other_val": "foo"}, + "id": "some 0", + }, + { + "name": tool_name, + # Wrong type for some_val + "args": {"some_val": "bar", "some_other_val": "foo"}, + "id": "some 1", + }, + ], + ), + ] + if use_message_key: + inputs = {"messages": inputs} + result = await validation_node.ainvoke(inputs) + if use_message_key: + result = result["messages"] + + def check_results(messages: list): + assert len(messages) == 2 + assert all(m.type == "tool" for m in messages) + assert not messages[0].additional_kwargs.get("is_error") + assert messages[1].additional_kwargs.get("is_error") + + check_results(result) + result_sync = validation_node.invoke(inputs) + if use_message_key: + result_sync = result_sync["messages"] + check_results(result_sync) diff --git a/libs/sdk-js/.gitignore b/libs/sdk-js/.gitignore index 8bb855c55..128c6dc98 100644 --- a/libs/sdk-js/.gitignore +++ b/libs/sdk-js/.gitignore @@ -10,6 +10,14 @@ react.cjs react.js react.d.ts react.d.cts +react-ui.cjs +react-ui.js +react-ui.d.ts +react-ui.d.cts +react-ui/server.cjs +react-ui/server.js +react-ui/server.d.ts +react-ui/server.d.cts node_modules dist .yarn diff --git a/libs/sdk-js/langchain.config.js b/libs/sdk-js/langchain.config.js index b74696d7b..21d796c87 100644 --- a/libs/sdk-js/langchain.config.js +++ b/libs/sdk-js/langchain.config.js @@ -11,7 +11,13 @@ function abs(relativePath) { export const config = { internals: [/react/], - entrypoints: { index: "index", client: "client", react: "react/index" }, + entrypoints: { + index: "index", + client: "client", + react: "react/index", + "react-ui": "react-ui/index", + "react-ui/server": "react-ui/server/index", + }, tsConfigPath: resolve("./tsconfig.json"), cjsSource: "./dist-cjs", cjsDestination: "./dist", diff --git a/libs/sdk-js/package.json b/libs/sdk-js/package.json index b5375664a..a54ccf4c9 100644 --- a/libs/sdk-js/package.json +++ b/libs/sdk-js/package.json @@ -1,13 +1,13 @@ { "name": "@langchain/langgraph-sdk", - "version": "0.0.46", + "version": "0.0.53", "description": "Client library for interacting with the LangGraph API", "type": "module", "packageManager": "yarn@1.22.19", "scripts": { "clean": "rm -rf dist/ dist-cjs/", "build": "yarn clean && yarn lc_build --create-entrypoints --pre --tree-shaking", - "prepublish": "yarn run build", + "prepack": "yarn run build", "format": "prettier --write src", "lint": "prettier --check src && tsc --noEmit", "test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts", @@ -29,7 +29,8 @@ "@types/jest": "^29.5.12", "@types/node": "^20.12.12", "@types/uuid": "^9.0.1", - "@types/react": "18.3.2", + "@types/react": "^19.0.8", + "@types/react-dom": "^19.0.3", "concat-md": "^0.5.1", "jest": "^29.7.0", "prettier": "^3.2.5", @@ -37,7 +38,8 @@ "typedoc": "^0.27.7", "typedoc-plugin-markdown": "^4.4.2", "typescript": "^5.4.5", - "react": "^18.3.1" + "react": "^19.0.0", + "react-dom": "^19.0.0" }, "peerDependencies": { "react": "^18 || ^19", @@ -79,6 +81,24 @@ "import": "./react.js", "require": "./react.cjs" }, + "./react-ui": { + "types": { + "import": "./react-ui.d.ts", + "require": "./react-ui.d.cts", + "default": "./react-ui.d.ts" + }, + "import": "./react-ui.js", + "require": "./react-ui.cjs" + }, + "./react-ui/server": { + "types": { + "import": "./react-ui/server.d.ts", + "require": "./react-ui/server.d.cts", + "default": "./react-ui/server.d.ts" + }, + "import": "./react-ui/server.js", + "require": "./react-ui/server.cjs" + }, "./package.json": "./package.json" }, "files": [ @@ -94,6 +114,14 @@ "react.cjs", "react.js", "react.d.ts", - "react.d.cts" + "react.d.cts", + "react-ui.cjs", + "react-ui.js", + "react-ui.d.ts", + "react-ui.d.cts", + "react-ui/server.cjs", + "react-ui/server.js", + "react-ui/server.d.ts", + "react-ui/server.d.cts" ] } diff --git a/libs/sdk-js/src/client.ts b/libs/sdk-js/src/client.ts index d936f6325..27a7970dc 100644 --- a/libs/sdk-js/src/client.ts +++ b/libs/sdk-js/src/client.ts @@ -1096,12 +1096,28 @@ export class StoreClient extends BaseClient { * @param namespace A list of strings representing the namespace path. * @param key The unique identifier for the item within the namespace. * @param value A dictionary containing the item's data. + * @param options.index Controls search indexing - null (use defaults), false (disable), or list of field paths to index. + * @param options.ttl Optional time-to-live in minutes for the item, or null for no expiration. * @returns Promise + * + * @example + * ```typescript + * await client.store.putItem( + * ["documents", "user123"], + * "item456", + * { title: "My Document", content: "Hello World" }, + * { ttl: 60 } // expires in 60 minutes + * ); + * ``` */ async putItem( namespace: string[], key: string, value: Record, + options?: { + index?: false | string[] | null; + ttl?: number | null; + }, ): Promise { namespace.forEach((label) => { if (label.includes(".")) { @@ -1115,6 +1131,8 @@ export class StoreClient extends BaseClient { namespace, key, value, + index: options?.index, + ttl: options?.ttl, }; return this.fetch("/store/items", { @@ -1128,9 +1146,33 @@ export class StoreClient extends BaseClient { * * @param namespace A list of strings representing the namespace path. * @param key The unique identifier for the item. + * @param options.refreshTtl Whether to refresh the TTL on this read operation. If null, uses the store's default behavior. * @returns Promise + * + * @example + * ```typescript + * const item = await client.store.getItem( + * ["documents", "user123"], + * "item456", + * { refreshTtl: true } + * ); + * console.log(item); + * // { + * // namespace: ["documents", "user123"], + * // key: "item456", + * // value: { title: "My Document", content: "Hello World" }, + * // createdAt: "2024-07-30T12:00:00Z", + * // updatedAt: "2024-07-30T12:00:00Z" + * // } + * ``` */ - async getItem(namespace: string[], key: string): Promise { + async getItem( + namespace: string[], + key: string, + options?: { + refreshTtl?: boolean | null; + }, + ): Promise { namespace.forEach((label) => { if (label.includes(".")) { throw new Error( @@ -1139,8 +1181,17 @@ export class StoreClient extends BaseClient { } }); + const params: Record = { + namespace: namespace.join("."), + key, + }; + + if (options?.refreshTtl !== undefined) { + params.refresh_ttl = options.refreshTtl; + } + const response = await this.fetch("/store/items", { - params: { namespace: namespace.join("."), key }, + params, }); return response @@ -1182,7 +1233,33 @@ export class StoreClient extends BaseClient { * @param options.limit Maximum number of items to return (default is 10). * @param options.offset Number of items to skip before returning results (default is 0). * @param options.query Optional search query. + * @param options.refreshTtl Whether to refresh the TTL on items returned by this search. If null, uses the store's default behavior. * @returns Promise + * + * @example + * ```typescript + * const results = await client.store.searchItems( + * ["documents"], + * { + * filter: { author: "John Doe" }, + * limit: 5, + * refreshTtl: true + * } + * ); + * console.log(results); + * // { + * // items: [ + * // { + * // namespace: ["documents", "user123"], + * // key: "item789", + * // value: { title: "Another Document", author: "John Doe" }, + * // createdAt: "2024-07-30T12:00:00Z", + * // updatedAt: "2024-07-30T12:00:00Z" + * // }, + * // // ... additional items ... + * // ] + * // } + * ``` */ async searchItems( namespacePrefix: string[], @@ -1191,6 +1268,7 @@ export class StoreClient extends BaseClient { limit?: number; offset?: number; query?: string; + refreshTtl?: boolean | null; }, ): Promise { const payload = { @@ -1199,6 +1277,7 @@ export class StoreClient extends BaseClient { limit: options?.limit ?? 10, offset: options?.offset ?? 0, query: options?.query, + refresh_ttl: options?.refreshTtl, }; const response = await this.fetch( @@ -1249,6 +1328,40 @@ export class StoreClient extends BaseClient { } } +class UiClient extends BaseClient { + private static promiseCache: Record | undefined> = + {}; + + private static getOrCached(key: string, fn: () => Promise): Promise { + if (UiClient.promiseCache[key] != null) { + return UiClient.promiseCache[key] as Promise; + } + + const promise = fn(); + UiClient.promiseCache[key] = promise; + return promise; + } + + async getComponent(assistantId: string, agentName: string): Promise { + return UiClient["getOrCached"]( + `${this.apiUrl}-${assistantId}-${agentName}`, + async () => { + const response = await this.asyncCaller.fetch( + ...this.prepareFetchOptions(`/ui/${assistantId}`, { + headers: { + Accept: "text/html", + "Content-Type": "application/json", + }, + method: "POST", + json: { name: agentName }, + }), + ); + return response.text(); + }, + ); + } +} + export class Client< TStateType = DefaultValues, TUpdateType = TStateType, @@ -1279,11 +1392,18 @@ export class Client< */ public store: StoreClient; + /** + * The client for interacting with the UI. + * @internal Used by LoadExternalComponent and the API might change in the future. + */ + public "~ui": UiClient; + constructor(config?: ClientConfig) { this.assistants = new AssistantsClient(config); this.threads = new ThreadsClient(config); this.runs = new RunsClient(config); this.crons = new CronsClient(config); this.store = new StoreClient(config); + this["~ui"] = new UiClient(config); } } diff --git a/libs/sdk-js/src/index.ts b/libs/sdk-js/src/index.ts index 0626144cd..71253b679 100644 --- a/libs/sdk-js/src/index.ts +++ b/libs/sdk-js/src/index.ts @@ -1,6 +1,7 @@ export { Client } from "./client.js"; export type { + AssistantBase, Assistant, AssistantVersion, AssistantGraph, diff --git a/libs/sdk-js/src/react-ui/client.tsx b/libs/sdk-js/src/react-ui/client.tsx new file mode 100644 index 000000000..ada4b8c11 --- /dev/null +++ b/libs/sdk-js/src/react-ui/client.tsx @@ -0,0 +1,230 @@ +"use client"; + +import { useStream } from "../react/index.js"; +import type { UIMessage } from "./types.js"; + +import * as React from "react"; +import * as ReactDOM from "react-dom"; +import * as JsxRuntime from "react/jsx-runtime"; +import type { UseStream } from "../react/stream.js"; + +const UseStreamContext = React.createContext<{ + stream: ReturnType; + meta: unknown; +}>(null!); + +type BagTemplate = { + ConfigurableType?: Record; + InterruptType?: unknown; + CustomEventType?: unknown; + UpdateType?: unknown; + MetaType?: unknown; +}; + +type GetMetaType = Bag extends { MetaType: unknown } + ? Bag["MetaType"] + : unknown; + +interface UseStreamContext< + StateType extends Record = Record, + Bag extends BagTemplate = BagTemplate, +> extends UseStream { + meta?: GetMetaType; +} + +export function useStreamContext< + StateType extends Record = Record, + Bag extends { + ConfigurableType?: Record; + InterruptType?: unknown; + CustomEventType?: unknown; + UpdateType?: unknown; + MetaType?: unknown; + } = BagTemplate, +>(): UseStreamContext { + const ctx = React.useContext(UseStreamContext); + if (!ctx) { + throw new Error( + "useStreamContext must be used within a LoadExternalComponent", + ); + } + + return new Proxy(ctx, { + get(target, prop: keyof UseStreamContext) { + if (prop === "meta") return target.meta; + return target.stream[prop]; + }, + }) as unknown as UseStreamContext; +} + +interface ComponentTarget { + comp: React.FunctionComponent | React.ComponentClass; + target: HTMLElement; +} + +class ComponentStore { + private cache: Record = {}; + private boundCache: Record< + string, + { + subscribe: (onStoreChange: () => void) => () => void; + getSnapshot: () => ComponentTarget | undefined; + } + > = {}; + private callbacks: Record< + string, + (( + comp: React.FunctionComponent | React.ComponentClass, + el: HTMLElement, + ) => void)[] + > = {}; + + respond( + shadowRootId: string, + comp: React.FunctionComponent | React.ComponentClass, + targetElement: HTMLElement, + ) { + this.cache[shadowRootId] = { comp, target: targetElement }; + this.callbacks[shadowRootId]?.forEach((c) => c(comp, targetElement)); + } + + getBoundStore(shadowRootId: string) { + this.boundCache[shadowRootId] ??= { + subscribe: (onStoreChange: () => void) => { + this.callbacks[shadowRootId] ??= []; + this.callbacks[shadowRootId].push(onStoreChange); + return () => { + this.callbacks[shadowRootId] = this.callbacks[shadowRootId].filter( + (c) => c !== onStoreChange, + ); + }; + }, + getSnapshot: () => this.cache[shadowRootId], + }; + + return this.boundCache[shadowRootId]; + } +} + +const COMPONENT_STORE = new ComponentStore(); +const EXT_STORE_SYMBOL = Symbol.for("LGUI_EXT_STORE"); +const REQUIRE_SYMBOL = Symbol.for("LGUI_REQUIRE"); + +interface LoadExternalComponentProps + extends Pick, "style" | "className"> { + /** Stream of the assistant */ + stream: ReturnType; + + /** UI message to be rendered */ + message: UIMessage; + + /** Additional context to be passed to the child component */ + meta?: unknown; + + /** Fallback to be rendered when the component is loading */ + fallback?: React.ReactNode; + + /** + * Map of components that can be rendered directly without fetching the UI code + * from the server. + */ + components?: Record; +} + +export function LoadExternalComponent({ + stream, + message, + meta, + fallback, + components, + ...props +}: LoadExternalComponentProps) { + const ref = React.useRef(null); + const id = React.useId(); + const shadowRootId = `child-shadow-${id}`; + + const store = React.useMemo( + () => COMPONENT_STORE.getBoundStore(shadowRootId), + [shadowRootId], + ); + const state = React.useSyncExternalStore(store.subscribe, store.getSnapshot); + + const clientComponent = components?.[message.name]; + const hasClientComponent = clientComponent != null; + + const uiClient = stream.client["~ui"]; + React.useEffect(() => { + if (hasClientComponent) return; + uiClient.getComponent(stream.assistantId, message.name).then((html) => { + const dom = ref.current; + if (!dom) return; + const root = dom.shadowRoot ?? dom.attachShadow({ mode: "open" }); + const fragment = document + .createRange() + .createContextualFragment( + html.replace("{{shadowRootId}}", shadowRootId), + ); + root.appendChild(fragment); + }); + }, [ + uiClient, + stream.assistantId, + message.name, + shadowRootId, + hasClientComponent, + ]); + + if (hasClientComponent) { + return React.createElement(clientComponent, message.props); + } + + return ( + <> +
+ + + {state?.target != null + ? ReactDOM.createPortal( + React.createElement(state.comp, message.props), + state.target, + ) + : fallback} + + + ); +} + +declare global { + interface Window { + [EXT_STORE_SYMBOL]: ComponentStore; + [REQUIRE_SYMBOL]: (name: string) => unknown; + } +} + +export function bootstrapUiContext() { + if (typeof window === "undefined") { + console.warn( + "Attempting to bootstrap UI context outside of browser environment. " + + "Avoid importing from `@langchain/langgraph-sdk/react-ui` in server context.", + ); + return; + } + + window[EXT_STORE_SYMBOL] = COMPONENT_STORE; + window[REQUIRE_SYMBOL] = (name: string) => { + if (name === "react") return React; + if (name === "react-dom") return ReactDOM; + if (name === "react/jsx-runtime") return JsxRuntime; + if (name === "@langchain/langgraph-sdk/react") return { useStream }; + if (name === "@langchain/langgraph-sdk/react-ui") { + return { + useStreamContext, + LoadExternalComponent: () => { + throw new Error("Nesting LoadExternalComponent is not supported"); + }, + }; + } + + throw new Error(`Unknown module...: ${name}`); + }; +} diff --git a/libs/sdk-js/src/react-ui/index.ts b/libs/sdk-js/src/react-ui/index.ts new file mode 100644 index 000000000..902adecee --- /dev/null +++ b/libs/sdk-js/src/react-ui/index.ts @@ -0,0 +1,9 @@ +import { bootstrapUiContext } from "./client.js"; +bootstrapUiContext(); + +export { useStreamContext, LoadExternalComponent } from "./client.js"; +export { + uiMessageReducer, + type UIMessage, + type RemoveUIMessage, +} from "./types.js"; diff --git a/libs/sdk-js/src/react-ui/server/index.ts b/libs/sdk-js/src/react-ui/server/index.ts new file mode 100644 index 000000000..45c2c1e78 --- /dev/null +++ b/libs/sdk-js/src/react-ui/server/index.ts @@ -0,0 +1,6 @@ +export { typedUi } from "./server.js"; +export { + uiMessageReducer, + type UIMessage, + type RemoveUIMessage, +} from "../types.js"; diff --git a/libs/sdk-js/src/react-ui/server/server.ts b/libs/sdk-js/src/react-ui/server/server.ts new file mode 100644 index 000000000..cde477bc1 --- /dev/null +++ b/libs/sdk-js/src/react-ui/server/server.ts @@ -0,0 +1,62 @@ +import { v4 as uuidv4 } from "uuid"; +import type { ComponentPropsWithoutRef, ElementType } from "react"; +import type { RemoveUIMessage, UIMessage } from "../types.js"; + +interface MessageLike { + id?: string; +} + +export const typedUi = >(config: { + writer?: (chunk: unknown) => void; + runId?: string; + metadata?: Record; + tags?: string[]; + runName?: string; +}) => { + type PropMap = { [K in keyof Decl]: ComponentPropsWithoutRef }; + let items: (UIMessage | RemoveUIMessage)[] = []; + + const runId = (config.metadata?.run_id as string | undefined) ?? config.runId; + if (!runId) throw new Error("run_id is required"); + + const metadata = { + ...config.metadata, + tags: config.tags, + name: config.runName, + run_id: runId, + }; + + const handlePush = ( + message: { + id?: string; + name: K; + props: PropMap[K]; + metadata?: Record; + }, + options?: { message?: MessageLike }, + ): UIMessage => { + const evt: UIMessage = { + type: "ui" as const, + id: message?.id ?? uuidv4(), + name: message?.name, + props: message?.props, + metadata: { + ...metadata, + ...message?.metadata, + ...(options?.message ? { message_id: options.message.id } : null), + }, + }; + items.push(evt); + config.writer?.(evt); + return evt; + }; + + const handleDelete = (id: string): RemoveUIMessage => { + const evt: RemoveUIMessage = { type: "remove-ui", id }; + items.push(evt); + config.writer?.(evt); + return evt; + }; + + return { push: handlePush, delete: handleDelete, items }; +}; diff --git a/libs/sdk-js/src/react-ui/types.ts b/libs/sdk-js/src/react-ui/types.ts new file mode 100644 index 000000000..c3f52b5b8 --- /dev/null +++ b/libs/sdk-js/src/react-ui/types.ts @@ -0,0 +1,41 @@ +export interface UIMessage { + type: "ui"; + + id: string; + name: string; + props: Record; + metadata: { + run_id: string; + message_id?: string; + [key: string]: unknown; + }; +} + +export interface RemoveUIMessage { + type: "remove-ui"; + id: string; +} + +export function uiMessageReducer( + state: UIMessage[], + update: UIMessage | RemoveUIMessage | (UIMessage | RemoveUIMessage)[], +) { + const events = Array.isArray(update) ? update : [update]; + let newState = state.slice(); + + for (const event of events) { + if (event.type === "remove-ui") { + newState = newState.filter((ui) => ui.id !== event.id); + continue; + } + + const index = state.findIndex((ui) => ui.id === event.id); + if (index !== -1) { + newState[index] = event; + } else { + newState.push(event); + } + } + + return newState; +} diff --git a/libs/sdk-js/src/react/stream.tsx b/libs/sdk-js/src/react/stream.tsx index a12220f4a..09805e9f1 100644 --- a/libs/sdk-js/src/react/stream.tsx +++ b/libs/sdk-js/src/react/stream.tsx @@ -366,11 +366,11 @@ const useControllableThreadId = (options?: { onThreadIdRef.current?.(threadId); }, []); - if (typeof options?.threadId === "undefined") { + if (!options || !("threadId" in options)) { return [localThreadId, onThreadId]; } - return [options.threadId, onThreadId]; + return [options.threadId ?? null, onThreadId]; }; type BagTemplate = { @@ -424,6 +424,16 @@ interface UseStreamOptions< */ apiKey?: ClientConfig["apiKey"]; + /** + * Custom call options, such as custom fetch implementation. + */ + callerOptions?: ClientConfig["callerOptions"]; + + /** + * Default headers to send with requests. + */ + defaultHeaders?: ClientConfig["defaultHeaders"]; + /** * Specify the key within the state that contains messages. * Defaults to "messages". @@ -454,6 +464,11 @@ interface UseStreamOptions< */ onCustomEvent?: ( data: CustomStreamEvent>["data"], + options: { + mutate: ( + update: Partial | ((prev: StateType) => Partial), + ) => void; + }, ) => void; /** @@ -472,7 +487,7 @@ interface UseStreamOptions< onThreadId?: (threadId: string) => void; } -interface UseStream< +export interface UseStream< StateType extends Record = Record, Bag extends BagTemplate = BagTemplate, > { @@ -548,6 +563,16 @@ interface UseStream< message: Message, index?: number, ) => MessageMetadata | undefined; + + /** + * LangGraph SDK client used to send request and receive responses. + */ + client: Client; + + /** + * The ID of the assistant to use. + */ + assistantId: string; } type ConfigWithConfigurable> = @@ -603,9 +628,21 @@ export function useStream< messagesKey ??= "messages"; const client = useMemo( - () => new Client({ apiUrl: options.apiUrl, apiKey: options.apiKey }), - [options.apiKey, options.apiUrl], + () => + new Client({ + apiUrl: options.apiUrl, + apiKey: options.apiKey, + callerOptions: options.callerOptions, + defaultHeaders: options.defaultHeaders, + }), + [ + options.apiKey, + options.apiUrl, + options.callerOptions, + options.defaultHeaders, + ], ); + const [threadId, onThreadId] = useControllableThreadId(options); const [branch, setBranch] = useState(""); @@ -623,9 +660,12 @@ export function useStream< >([]); const trackStreamMode = useCallback( - (mode: Exclude) => { - if (!trackStreamModeRef.current.includes(mode)) - trackStreamModeRef.current.push(mode); + (...mode: Exclude[]) => { + for (const m of mode) { + if (!trackStreamModeRef.current.includes(m)) { + trackStreamModeRef.current.push(m); + } + } }, [], ); @@ -810,7 +850,18 @@ export function useStream< } if (event === "updates") options.onUpdateEvent?.(data); - if (event === "custom") options.onCustomEvent?.(data); + if (event === "custom") + options.onCustomEvent?.(data, { + mutate: (update) => + setStreamValues((prev) => { + // should not happen + if (prev == null) return prev; + return { + ...prev, + ...(typeof update === "function" ? update(prev) : update), + }; + }), + }); if (event === "metadata") options.onMetadataEvent?.(data); if (event === "values") setStreamValues(data); @@ -879,6 +930,9 @@ export function useStream< return values; }, + client, + assistantId, + error, isLoading, @@ -908,7 +962,7 @@ export function useStream< }, get messages() { - trackStreamMode("messages-tuple"); + trackStreamMode("messages-tuple", "values"); return getMessages(values); }, @@ -916,7 +970,7 @@ export function useStream< message: Message, index?: number, ): MessageMetadata | undefined { - trackStreamMode("messages-tuple"); + trackStreamMode("messages-tuple", "values"); return messageMetadata?.find( (m) => m.messageId === (message.id ?? index), ); diff --git a/libs/sdk-js/src/schema.ts b/libs/sdk-js/src/schema.ts index 84596c82c..b75d63d02 100644 --- a/libs/sdk-js/src/schema.ts +++ b/libs/sdk-js/src/schema.ts @@ -110,6 +110,9 @@ export interface AssistantBase { /** The version of the assistant. */ version: number; + + /** The name of the assistant */ + name: string; } export interface AssistantVersion extends AssistantBase {} @@ -117,9 +120,6 @@ export interface AssistantVersion extends AssistantBase {} export interface Assistant extends AssistantBase { /** The last time the assistant was updated. */ updated_at: string; - - /** The name of the assistant */ - name: string; } export interface AssistantGraph { diff --git a/libs/sdk-js/src/types.messages.ts b/libs/sdk-js/src/types.messages.ts index a2eb34a9a..62f2e6d5d 100644 --- a/libs/sdk-js/src/types.messages.ts +++ b/libs/sdk-js/src/types.messages.ts @@ -26,7 +26,7 @@ export type AIMessage = { tool_calls?: | { name: string; - args: { [x: string]: { [x: string]: any } }; + args: { [x: string]: any }; id?: string | undefined; type?: "tool_call" | undefined; }[] diff --git a/libs/sdk-js/yarn.lock b/libs/sdk-js/yarn.lock index e326638f4..db56763a9 100644 --- a/libs/sdk-js/yarn.lock +++ b/libs/sdk-js/yarn.lock @@ -10,7 +10,15 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.26.2": +"@babel/code-frame@^7.0.0": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== @@ -20,43 +28,43 @@ picocolors "^1.0.0" "@babel/compat-data@^7.26.5": - version "7.26.8" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.8.tgz#821c1d35641c355284d4a870b8a4a7b0c141e367" - integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ== + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.5.tgz#df93ac37f4417854130e21d72c66ff3d4b897fc7" + integrity sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.26.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.9.tgz#71838542a4b1e49dfed353d7acbc6eb89f4a76f2" - integrity sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw== + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" + integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.9" - "@babel/helper-compilation-targets" "^7.26.5" + "@babel/code-frame" "^7.26.0" + "@babel/generator" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" "@babel/helper-module-transforms" "^7.26.0" - "@babel/helpers" "^7.26.9" - "@babel/parser" "^7.26.9" - "@babel/template" "^7.26.9" - "@babel/traverse" "^7.26.9" - "@babel/types" "^7.26.9" + "@babel/helpers" "^7.26.0" + "@babel/parser" "^7.26.0" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.26.0" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.26.9", "@babel/generator@^7.7.2": - version "7.26.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.9.tgz#75a9482ad3d0cc7188a537aa4910bc59db67cbca" - integrity sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg== +"@babel/generator@^7.26.0", "@babel/generator@^7.26.5", "@babel/generator@^7.7.2": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.5.tgz#e44d4ab3176bbcaf78a5725da5f1dc28802a9458" + integrity sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw== dependencies: - "@babel/parser" "^7.26.9" - "@babel/types" "^7.26.9" + "@babel/parser" "^7.26.5" + "@babel/types" "^7.26.5" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^3.0.2" -"@babel/helper-compilation-targets@^7.26.5": +"@babel/helper-compilation-targets@^7.25.9": version "7.26.5" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8" integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA== @@ -94,6 +102,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + "@babel/helper-validator-identifier@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" @@ -104,20 +117,30 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== -"@babel/helpers@^7.26.9": - version "7.26.9" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.9.tgz#28f3fb45252fc88ef2dc547c8a911c255fc9fef6" - integrity sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA== +"@babel/helpers@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" + integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== dependencies: - "@babel/template" "^7.26.9" - "@babel/types" "^7.26.9" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.26.9": - version "7.26.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5" - integrity sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A== +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== dependencies: - "@babel/types" "^7.26.9" + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.5.tgz#6fec9aebddef25ca57a935c86dbb915ae2da3e1f" + integrity sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw== + dependencies: + "@babel/types" "^7.26.5" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -238,32 +261,32 @@ dependencies: "@babel/helper-plugin-utils" "^7.25.9" -"@babel/template@^7.26.9", "@babel/template@^7.3.3": - version "7.26.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2" - integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA== +"@babel/template@^7.25.9", "@babel/template@^7.3.3": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== dependencies: - "@babel/code-frame" "^7.26.2" - "@babel/parser" "^7.26.9" - "@babel/types" "^7.26.9" + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" -"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.9": - version "7.26.9" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.9.tgz#4398f2394ba66d05d988b2ad13c219a2c857461a" - integrity sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg== +"@babel/traverse@^7.25.9": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.5.tgz#6d0be3e772ff786456c1a37538208286f6e79021" + integrity sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ== dependencies: "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.9" - "@babel/parser" "^7.26.9" - "@babel/template" "^7.26.9" - "@babel/types" "^7.26.9" + "@babel/generator" "^7.26.5" + "@babel/parser" "^7.26.5" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.5" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.9", "@babel/types@^7.3.3": - version "7.26.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.9.tgz#08b43dec79ee8e682c2ac631c010bdcac54a21ce" - integrity sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.5", "@babel/types@^7.3.3": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.5.tgz#7a1e1c01d28e26d1fe7f8ec9567b3b92b9d07747" + integrity sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg== dependencies: "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" @@ -540,9 +563,9 @@ "@jridgewell/sourcemap-codec" "^1.4.14" "@langchain/core@^0.3.31": - version "0.3.40" - resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.40.tgz#e5f41f8b4288672d73aa98bcdaf6b32df0480db8" - integrity sha512-RGhJOTzJv6H+3veBAnDlH2KXuZ68CXMEg6B6DPTzL3IGDyd+vLxXG4FIttzUwjdeQKjrrFBwlXpJDl7bkoApzQ== + version "0.3.39" + resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.39.tgz#81002e0cacacb7c1011264d6612f923816a3965f" + integrity sha512-muXs4asy1A7qDtcdznxqyBfxf4N6qxofY/S0c95vbsWa0r9YAE2PttHIjcuxSy1q2jUiTkpCcgFEjNJRQRVhEw== dependencies: "@cfworker/json-schema" "^4.0.2" ansi-styles "^5.0.0" @@ -596,203 +619,197 @@ fastq "^1.6.0" "@octokit/auth-token@^5.0.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-5.1.2.tgz#68a486714d7a7fd1df56cb9bc89a860a0de866de" - integrity sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw== + version "5.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-5.1.1.tgz#3bbfe905111332a17f72d80bd0b51a3e2fa2cf07" + integrity sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA== -"@octokit/core@^6.1.4": - version "6.1.4" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-6.1.4.tgz#f5ccf911cc95b1ce9daf6de425d1664392f867db" - integrity sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg== +"@octokit/core@^6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-6.1.2.tgz#20442d0a97c411612da206411e356014d1d1bd17" + integrity sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg== dependencies: "@octokit/auth-token" "^5.0.0" - "@octokit/graphql" "^8.1.2" - "@octokit/request" "^9.2.1" - "@octokit/request-error" "^6.1.7" - "@octokit/types" "^13.6.2" + "@octokit/graphql" "^8.0.0" + "@octokit/request" "^9.0.0" + "@octokit/request-error" "^6.0.1" + "@octokit/types" "^13.0.0" before-after-hook "^3.0.2" universal-user-agent "^7.0.0" -"@octokit/endpoint@^10.1.3": - version "10.1.3" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-10.1.3.tgz#bfe8ff2ec213eb4216065e77654bfbba0fc6d4de" - integrity sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA== +"@octokit/endpoint@^10.0.0": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-10.1.1.tgz#1a9694e7aef6aa9d854dc78dd062945945869bcc" + integrity sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q== dependencies: - "@octokit/types" "^13.6.2" + "@octokit/types" "^13.0.0" universal-user-agent "^7.0.2" -"@octokit/graphql@^8.1.2": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.2.1.tgz#0cb83600e6b4009805acc1c56ae8e07e6c991b78" - integrity sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw== +"@octokit/graphql@^8.0.0": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.1.1.tgz#3cacab5f2e55d91c733e3bf481d3a3f8a5f639c4" + integrity sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg== dependencies: - "@octokit/request" "^9.2.2" - "@octokit/types" "^13.8.0" + "@octokit/request" "^9.0.0" + "@octokit/types" "^13.0.0" universal-user-agent "^7.0.0" -"@octokit/openapi-types@^23.0.1": - version "23.0.1" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-23.0.1.tgz#3721646ecd36b596ddb12650e0e89d3ebb2dd50e" - integrity sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g== +"@octokit/openapi-types@^22.2.0": + version "22.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-22.2.0.tgz#75aa7dcd440821d99def6a60b5f014207ae4968e" + integrity sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg== -"@octokit/plugin-paginate-rest@^11.4.2": - version "11.4.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.3.tgz#b5030bba2e0ecff8e6ff7501074c1b209af78ff8" - integrity sha512-tBXaAbXkqVJlRoA/zQVe9mUdb8rScmivqtpv3ovsC5xhje/a+NOCivs7eUhWBwCApJVsR4G5HMeaLbq7PxqZGA== +"@octokit/plugin-paginate-rest@^11.0.0": + version "11.3.5" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.5.tgz#a1929b3ba3dc7b63bc73bb6d3c7a3faf2a9c7649" + integrity sha512-cgwIRtKrpwhLoBi0CUNuY83DPGRMaWVjqVI/bGKsLJ4PzyWZNaEmhHroI2xlrVXkk6nFv0IsZpOp+ZWSWUS2AQ== dependencies: - "@octokit/types" "^13.7.0" + "@octokit/types" "^13.6.0" "@octokit/plugin-request-log@^5.3.1": version "5.3.1" resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz#ccb75d9705de769b2aa82bcd105cc96eb0c00f69" integrity sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw== -"@octokit/plugin-rest-endpoint-methods@^13.3.0": - version "13.3.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.1.tgz#1915976b689662f14d033a16e7d9307c22842234" - integrity sha512-o8uOBdsyR+WR8MK9Cco8dCgvG13H1RlM1nWnK/W7TEACQBFux/vPREgKucxUfuDQ5yi1T3hGf4C5ZmZXAERgwQ== +"@octokit/plugin-rest-endpoint-methods@^13.0.0": + version "13.2.6" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.6.tgz#b9d343dbe88a6cb70cc7fa16faa98f0a29ffe654" + integrity sha512-wMsdyHMjSfKjGINkdGKki06VEkgdEldIGstIEyGX0wbYHGByOwN/KiM+hAAlUwAtPkP3gvXtVQA9L3ITdV2tVw== dependencies: - "@octokit/types" "^13.8.0" + "@octokit/types" "^13.6.1" -"@octokit/request-error@^6.1.7": - version "6.1.7" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.7.tgz#44fc598f5cdf4593e0e58b5155fe2e77230ff6da" - integrity sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g== +"@octokit/request-error@^6.0.1": + version "6.1.5" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.5.tgz#907099e341c4e6179db623a0328d678024f54653" + integrity sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ== dependencies: - "@octokit/types" "^13.6.2" + "@octokit/types" "^13.0.0" -"@octokit/request@^9.2.1", "@octokit/request@^9.2.2": - version "9.2.2" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.2.2.tgz#754452ec4692d7fdc32438a14e028eba0e6b2c09" - integrity sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg== +"@octokit/request@^9.0.0": + version "9.1.3" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.1.3.tgz#42b693bc06238f43af3c037ebfd35621c6457838" + integrity sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA== dependencies: - "@octokit/endpoint" "^10.1.3" - "@octokit/request-error" "^6.1.7" - "@octokit/types" "^13.6.2" - fast-content-type-parse "^2.0.0" + "@octokit/endpoint" "^10.0.0" + "@octokit/request-error" "^6.0.1" + "@octokit/types" "^13.1.0" universal-user-agent "^7.0.2" "@octokit/rest@^21.0.2": - version "21.1.1" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-21.1.1.tgz#7a70455ca451b1d253e5b706f35178ceefb74de2" - integrity sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg== + version "21.0.2" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-21.0.2.tgz#9b767dbc1098daea8310fd8b76bf7a97215d5972" + integrity sha512-+CiLisCoyWmYicH25y1cDfCrv41kRSvTq6pPWtRroRJzhsCZWZyCqGyI8foJT5LmScADSwRAnr/xo+eewL04wQ== dependencies: - "@octokit/core" "^6.1.4" - "@octokit/plugin-paginate-rest" "^11.4.2" + "@octokit/core" "^6.1.2" + "@octokit/plugin-paginate-rest" "^11.0.0" "@octokit/plugin-request-log" "^5.3.1" - "@octokit/plugin-rest-endpoint-methods" "^13.3.0" + "@octokit/plugin-rest-endpoint-methods" "^13.0.0" -"@octokit/types@^13.6.2", "@octokit/types@^13.7.0", "@octokit/types@^13.8.0": - version "13.8.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.8.0.tgz#3815885e5abd16ed9ffeea3dced31d37ce3f8a0a" - integrity sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A== +"@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.6.0", "@octokit/types@^13.6.1": + version "13.6.1" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.6.1.tgz#432fc6c0aaae54318e5b2d3e15c22ac97fc9b15f" + integrity sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g== dependencies: - "@octokit/openapi-types" "^23.0.1" + "@octokit/openapi-types" "^22.2.0" "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@rollup/rollup-android-arm-eabi@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz#731df27dfdb77189547bcef96ada7bf166bbb2fb" - integrity sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw== +"@rollup/rollup-android-arm-eabi@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.4.tgz#c460b54c50d42f27f8254c435a4f3b3e01910bc8" + integrity sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw== -"@rollup/rollup-android-arm64@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz#4bea6db78e1f6927405df7fe0faf2f5095e01343" - integrity sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q== +"@rollup/rollup-android-arm64@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.4.tgz#96e01f3a04675d8d5973ab8d3fd6bc3be21fa5e1" + integrity sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA== -"@rollup/rollup-darwin-arm64@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz#a7aab77d44be3c44a20f946e10160f84e5450e7f" - integrity sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q== +"@rollup/rollup-darwin-arm64@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.4.tgz#9b2ec23b17b47cbb2f771b81f86ede3ac6730bce" + integrity sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ== -"@rollup/rollup-darwin-x64@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz#c572c024b57ee8ddd1b0851703ace9eb6cc0dd82" - integrity sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw== +"@rollup/rollup-darwin-x64@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.4.tgz#f30e4ee6929e048190cf10e0daa8e8ae035b6e46" + integrity sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg== -"@rollup/rollup-freebsd-arm64@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz#cf74f8113b5a83098a5c026c165742277cbfb88b" - integrity sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA== +"@rollup/rollup-freebsd-arm64@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.4.tgz#c54b2373ec5bcf71f08c4519c7ae80a0b6c8e03b" + integrity sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw== -"@rollup/rollup-freebsd-x64@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz#39561f3a2f201a4ad6a01425b1ff5928154ecd7c" - integrity sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q== +"@rollup/rollup-freebsd-x64@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.4.tgz#3bc53aa29d5a34c28ba8e00def76aa612368458e" + integrity sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g== -"@rollup/rollup-linux-arm-gnueabihf@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz#980d6061e373bfdaeb67925c46d2f8f9b3de537f" - integrity sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g== +"@rollup/rollup-linux-arm-gnueabihf@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.4.tgz#c85aedd1710c9e267ee86b6d1ce355ecf7d9e8d9" + integrity sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA== -"@rollup/rollup-linux-arm-musleabihf@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz#f91a90f30dc00d5a64ac2d9bbedc829cd3cfaa78" - integrity sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA== +"@rollup/rollup-linux-arm-musleabihf@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.4.tgz#e77313408bf13995aecde281aec0cceb08747e42" + integrity sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw== -"@rollup/rollup-linux-arm64-gnu@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz#fac700fa5c38bc13a0d5d34463133093da4c92a0" - integrity sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A== +"@rollup/rollup-linux-arm64-gnu@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.4.tgz#633f632397b3662108cfaa1abca2a80b85f51102" + integrity sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg== -"@rollup/rollup-linux-arm64-musl@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz#f50ecccf8c78841ff6df1706bc4782d7f62bf9c3" - integrity sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q== +"@rollup/rollup-linux-arm64-musl@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.4.tgz#63edd72b29c4cced93e16113a68e1be9fef88907" + integrity sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA== -"@rollup/rollup-linux-loongarch64-gnu@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz#5869dc0b28242da6553e2b52af41374f4038cd6e" - integrity sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ== +"@rollup/rollup-linux-powerpc64le-gnu@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.4.tgz#a9418a4173df80848c0d47df0426a0bf183c4e75" + integrity sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA== -"@rollup/rollup-linux-powerpc64le-gnu@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz#5cdd9f851ce1bea33d6844a69f9574de335f20b1" - integrity sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw== +"@rollup/rollup-linux-riscv64-gnu@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.4.tgz#bc9c195db036a27e5e3339b02f51526b4ce1e988" + integrity sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw== -"@rollup/rollup-linux-riscv64-gnu@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz#ef5dc37f4388f5253f0def43e1440ec012af204d" - integrity sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw== +"@rollup/rollup-linux-s390x-gnu@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.4.tgz#1651fdf8144ae89326c01da5d52c60be63e71a82" + integrity sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ== -"@rollup/rollup-linux-s390x-gnu@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz#7dbc3ccbcbcfb3e65be74538dfb6e8dd16178fde" - integrity sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA== +"@rollup/rollup-linux-x64-gnu@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.4.tgz#e473de5e4acb95fcf930a35cbb7d3e8080e57a6f" + integrity sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA== -"@rollup/rollup-linux-x64-gnu@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz#5783fc0adcab7dc069692056e8ca8d83709855ce" - integrity sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA== +"@rollup/rollup-linux-x64-musl@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.4.tgz#0af12dd2578c29af4037f0c834b4321429dd5b01" + integrity sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q== -"@rollup/rollup-linux-x64-musl@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz#00b6c29b298197a384e3c659910b47943003a678" - integrity sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ== +"@rollup/rollup-win32-arm64-msvc@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.4.tgz#e48e78cdd45313b977c1390f4bfde7ab79be8871" + integrity sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA== -"@rollup/rollup-win32-arm64-msvc@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz#cbfee01f1fe73791c35191a05397838520ca3cdd" - integrity sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ== +"@rollup/rollup-win32-ia32-msvc@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.4.tgz#a3fc8536d243fe161c796acb93eba43c250f311c" + integrity sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg== -"@rollup/rollup-win32-ia32-msvc@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz#95cdbdff48fe6c948abcf6a1d500b2bd5ce33f62" - integrity sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w== - -"@rollup/rollup-win32-x64-msvc@4.34.8": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz#4cdb2cfae69cdb7b1a3cc58778e820408075e928" - integrity sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g== +"@rollup/rollup-win32-x64-msvc@4.24.4": + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.4.tgz#e2a9d1fd56524103a6cc8a54404d9d3ebc73c454" + integrity sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg== "@rollup/wasm-node@^4.19.0": - version "4.34.8" - resolved "https://registry.yarnpkg.com/@rollup/wasm-node/-/wasm-node-4.34.8.tgz#c67f8f4f768b6eb473e091c0cd8ed08afc5a27c9" - integrity sha512-+bu9Ce1VDob+hfEQYPwC03Lds+ACDlGVwuWeLZE2fN+O52O74RZ0F5engVpv7i2YDyTyj4oU/NKO4pjSXMdn6g== + version "4.24.4" + resolved "https://registry.yarnpkg.com/@rollup/wasm-node/-/wasm-node-4.24.4.tgz#11d78f5cc85b04e81468f245c2dc0885d06d663d" + integrity sha512-WKJUdPcM8YAYujafY95+2EapqU3F/nwfBkXh9AfkBvWBwFhsvNJABA86Br6graRH2vRE4FBsiqjFvFWOtEO6wg== dependencies: "@types/estree" "1.0.6" optionalDependencies: @@ -815,9 +832,9 @@ "@types/hast" "^3.0.4" "@shikijs/vscode-textmate@^10.0.1": - version "10.0.2" - resolved "https://registry.yarnpkg.com/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz#a90ab31d0cc1dfb54c66a69e515bf624fa7b2224" - integrity sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg== + version "10.0.1" + resolved "https://registry.yarnpkg.com/@shikijs/vscode-textmate/-/vscode-textmate-10.0.1.tgz#d06d45b67ac5e9b0088e3f67ebd3f25c6c3d711a" + integrity sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg== "@sinclair/typebox@^0.27.8": version "0.27.8" @@ -869,9 +886,9 @@ path-browserify "^1.0.1" "@tsconfig/recommended@^1.0.2": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/recommended/-/recommended-1.0.8.tgz#16483d57b56bbbd32b8c3af0eff1a40c32d006fa" - integrity sha512-TotjFaaXveVUdsrXCdalyF6E5RyG6+7hHHQVZonQtdlk1rJZ1myDIvPUUKPhoYv+JAzThb2lQJh9+9ZfF46hsA== + version "1.0.6" + resolved "https://registry.yarnpkg.com/@tsconfig/recommended/-/recommended-1.0.6.tgz#217b78f9601215939d566a79d202a760ae185114" + integrity sha512-0IKu9GHYF1NGTJiYgfWwqnOQSlnE9V9R7YohHNNf0/fj/SyOZWzdd06JFr0fLpg1Mqw0kGbYg8w5xdkSqLKM9g== "@types/babel__core@^7.1.14": version "7.20.5" @@ -970,35 +987,34 @@ integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag== "@types/node@*": - version "22.13.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.5.tgz#23add1d71acddab2c6a4d31db89c0f98d330b511" - integrity sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg== + version "22.10.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.5.tgz#95af89a3fb74a2bb41ef9927f206e6472026e48b" + integrity sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ== dependencies: undici-types "~6.20.0" "@types/node@^20.12.12": - version "20.17.19" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.19.tgz#0f2869555719bef266ca6e1827fcdca903c1a697" - integrity sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A== + version "20.12.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" + integrity sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw== dependencies: - undici-types "~6.19.2" + undici-types "~5.26.4" "@types/normalize-package-data@^2.4.0": version "2.4.4" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== -"@types/prop-types@*": - version "15.7.14" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2" - integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ== +"@types/react-dom@^19.0.3": + version "19.0.3" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.3.tgz#0804dfd279a165d5a0ad8b53a5b9e65f338050a4" + integrity sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA== -"@types/react@18.3.2": - version "18.3.2" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.2.tgz#462ae4904973bc212fa910424d901e3d137dbfcd" - integrity sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w== +"@types/react@^19.0.8": + version "19.0.9" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.9.tgz#675255eb7d978bdaf71f9d08f6b740d41b0b7f32" + integrity sha512-FedNTYgmMwSZmD1Sru/W1gJKuiYCN/3SuBkmZkcxX+FpO5zL76B22A9YNfAKg4HQO3Neh/30AiynP6BELdU0qQ== dependencies: - "@types/prop-types" "*" csstype "^3.0.2" "@types/retry@0.12.0": @@ -1017,9 +1033,9 @@ integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== "@types/unist@^2", "@types/unist@^2.0.0", "@types/unist@^2.0.2": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" - integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.10.tgz#04ffa7f406ab628f7f7e97ca23e290cd8ab15efc" + integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== "@types/uuid@^10.0.0": version "10.0.0" @@ -1067,6 +1083,13 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -1104,42 +1127,38 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" - integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: - call-bound "^1.0.3" - is-array-buffer "^3.0.5" + call-bind "^1.0.5" + is-array-buffer "^3.0.4" array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -arraybuffer.prototype.slice@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" - integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== dependencies: array-buffer-byte-length "^1.0.1" - call-bind "^1.0.8" + call-bind "^1.0.5" define-properties "^1.2.1" - es-abstract "^1.23.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.6" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== -async-function@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" - integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== - async@^3.2.3: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" @@ -1158,9 +1177,9 @@ available-typed-arrays@^1.0.7: possible-typed-array-names "^1.0.0" axios@^1.6.7: - version "1.7.9" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" - integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== + version "1.8.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.2.tgz#fabe06e241dfe83071d4edfbcaa7b1c3a40f7979" + integrity sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -1300,31 +1319,16 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" - integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: + es-define-property "^1.0.0" es-errors "^1.3.0" function-bind "^1.1.2" - -call-bind@^1.0.7, call-bind@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" - integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== - dependencies: - call-bind-apply-helpers "^1.0.0" - es-define-property "^1.0.0" get-intrinsic "^1.2.4" - set-function-length "^1.2.2" - -call-bound@^1.0.2, call-bound@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" - integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== - dependencies: - call-bind-apply-helpers "^1.0.1" - get-intrinsic "^1.2.6" + set-function-length "^1.2.1" callsites@^3.0.0: version "3.1.0" @@ -1351,15 +1355,24 @@ camelcase@^5.3.1: integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== caniuse-lite@^1.0.30001688: - version "1.0.30001700" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz#26cd429cf09b4fd4e745daf4916039c794d720f6" - integrity sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ== + version "1.0.30001692" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz#4585729d95e6b95be5b439da6ab55250cd125bf9" + integrity sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A== ccount@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -1394,9 +1407,9 @@ ci-info@^3.2.0: integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" - integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== cliui@^8.0.1: version "8.0.1" @@ -1422,6 +1435,13 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -1429,6 +1449,11 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -1488,7 +1513,16 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" -cross-spawn@^7.0.3, cross-spawn@^7.0.6: +cross-spawn@^7.0.0: + version "7.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.5.tgz#910aac880ff5243da96b728bc6521a5f6c2f2f82" + integrity sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -1502,34 +1536,41 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -data-view-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" - integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== - dependencies: - call-bound "^1.0.3" - es-errors "^1.3.0" - is-data-view "^1.0.2" - -data-view-byte-length@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" - integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== - dependencies: - call-bound "^1.0.3" - es-errors "^1.3.0" - is-data-view "^1.0.2" - -data-view-byte-offset@^1.0.1: +data-view-buffer@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" - integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== dependencies: - call-bound "^1.0.2" + call-bind "^1.0.6" es-errors "^1.3.0" is-data-view "^1.0.1" -debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +debug@^4.0.0, debug@^4.3.4: + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -1568,7 +1609,7 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" -define-properties@^1.2.1: +define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -1641,15 +1682,6 @@ domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" -dunder-proto@^1.0.0, dunder-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" - integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-errors "^1.3.0" - gopd "^1.2.0" - eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -1663,9 +1695,9 @@ ejs@^3.1.10: jake "^10.8.5" electron-to-chromium@^1.5.73: - version "1.5.104" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.104.tgz#e92a1ec54f279d8fc60eb7e8cf6add9631631f38" - integrity sha512-Us9M2L4cO/zMBqVkJtnj353nQhMju9slHm62NprKTmdF3HH8wYOtNvDFq/JB2+ZRoGLzdvYDiATlMHs98XBM1g== + version "1.5.80" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.80.tgz#ca7a8361d7305f0ec9e203ce4e633cbb8a8ef1b1" + integrity sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw== emittery@^0.13.1: version "0.13.1" @@ -1709,104 +1741,105 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.23.5, es-abstract@^1.23.9: - version "1.23.9" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.9.tgz#5b45994b7de78dada5c1bebf1379646b32b9d606" - integrity sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA== +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: - array-buffer-byte-length "^1.0.2" - arraybuffer.prototype.slice "^1.0.4" + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" available-typed-arrays "^1.0.7" - call-bind "^1.0.8" - call-bound "^1.0.3" - data-view-buffer "^1.0.2" - data-view-byte-length "^1.0.2" - data-view-byte-offset "^1.0.1" - es-define-property "^1.0.1" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" es-errors "^1.3.0" es-object-atoms "^1.0.0" - es-set-tostringtag "^2.1.0" - es-to-primitive "^1.3.0" - function.prototype.name "^1.1.8" - get-intrinsic "^1.2.7" - get-proto "^1.0.0" - get-symbol-description "^1.1.0" - globalthis "^1.0.4" - gopd "^1.2.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" has-property-descriptors "^1.0.2" - has-proto "^1.2.0" - has-symbols "^1.1.0" + has-proto "^1.0.3" + has-symbols "^1.0.3" hasown "^2.0.2" - internal-slot "^1.1.0" - is-array-buffer "^3.0.5" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-data-view "^1.0.2" - is-regex "^1.2.1" - is-shared-array-buffer "^1.0.4" - is-string "^1.1.1" - is-typed-array "^1.1.15" - is-weakref "^1.1.0" - math-intrinsics "^1.1.0" - object-inspect "^1.13.3" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.7" - own-keys "^1.0.1" - regexp.prototype.flags "^1.5.3" - safe-array-concat "^1.1.3" - safe-push-apply "^1.0.0" - safe-regex-test "^1.1.0" - set-proto "^1.0.0" - string.prototype.trim "^1.2.10" - string.prototype.trimend "^1.0.9" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.3" - typed-array-byte-length "^1.0.3" - typed-array-byte-offset "^1.0.4" - typed-array-length "^1.0.7" - unbox-primitive "^1.1.0" - which-typed-array "^1.1.18" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" -es-define-property@^1.0.0, es-define-property@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" - integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" -es-errors@^1.3.0: +es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== dependencies: es-errors "^1.3.0" -es-set-tostringtag@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" - integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.6" + get-intrinsic "^1.2.4" has-tostringtag "^1.0.2" - hasown "^2.0.2" + hasown "^2.0.1" -es-to-primitive@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" - integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: - is-callable "^1.2.7" - is-date-object "^1.0.5" - is-symbol "^1.0.4" + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + escape-string-regexp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" @@ -1863,21 +1896,16 @@ extend@^3.0.0: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -fast-content-type-parse@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz#c236124534ee2cb427c8d8e5ba35a4856947847b" - integrity sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q== - fast-glob@^3.2.9, fast-glob@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" - integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.8" + micromatch "^4.0.4" fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: version "2.1.0" @@ -1885,9 +1913,9 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fastq@^1.6.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.0.tgz#a82c6b7c2bb4e44766d865f07997785fecfdcb89" - integrity sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA== + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" @@ -1933,28 +1961,27 @@ follow-redirects@^1.15.6: integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== for-each@^0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" - integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== dependencies: - is-callable "^1.2.7" + is-callable "^1.1.3" foreground-child@^3.1.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" - integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: - cross-spawn "^7.0.6" + cross-spawn "^7.0.0" signal-exit "^4.0.1" form-data@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" - integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" - es-set-tostringtag "^2.1.0" mime-types "^2.1.12" format@^0.2.0: @@ -1984,17 +2011,15 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" - integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-properties "^1.2.1" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" functions-have-names "^1.2.3" - hasown "^2.0.2" - is-callable "^1.2.7" functions-have-names@^1.2.3: version "1.2.3" @@ -2011,48 +2036,35 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7: - version "1.3.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" - integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: - call-bind-apply-helpers "^1.0.2" - es-define-property "^1.0.1" es-errors "^1.3.0" - es-object-atoms "^1.1.1" function-bind "^1.1.2" - get-proto "^1.0.1" - gopd "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - math-intrinsics "^1.1.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-proto@^1.0.0, get-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" - integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== - dependencies: - dunder-proto "^1.0.1" - es-object-atoms "^1.0.0" - get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" - integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: - call-bound "^1.0.3" + call-bind "^1.0.5" es-errors "^1.3.0" - get-intrinsic "^1.2.6" + get-intrinsic "^1.2.4" glob-parent@^5.1.2: version "5.1.2" @@ -2090,7 +2102,7 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globalthis@^1.0.4: +globalthis@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== @@ -2110,10 +2122,12 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -gopd@^1.0.1, gopd@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" - integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" graceful-fs@^4.2.9: version "4.2.11" @@ -2125,10 +2139,15 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -has-bigints@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" - integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" @@ -2142,26 +2161,24 @@ has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: dependencies: es-define-property "^1.0.0" -has-proto@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" - integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== - dependencies: - dunder-proto "^1.0.0" +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== -has-symbols@^1.0.3, has-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" - integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.2: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" -hasown@^2.0.2: +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -2201,9 +2218,9 @@ human-signals@^2.1.0: integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== ignore@^5.2.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== import-local@^3.0.2: version "3.2.0" @@ -2236,14 +2253,14 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" - integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: es-errors "^1.3.0" - hasown "^2.0.2" - side-channel "^1.1.0" + hasown "^2.0.0" + side-channel "^1.0.4" is-alphabetical@^1.0.0: version "1.0.4" @@ -2258,79 +2275,71 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" -is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" - integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - get-intrinsic "^1.2.6" + call-bind "^1.0.2" + get-intrinsic "^1.2.1" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-async-function@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" - integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== dependencies: - async-function "^1.0.0" - call-bound "^1.0.3" - get-proto "^1.0.1" - has-tostringtag "^1.0.2" - safe-regex-test "^1.1.0" + has-bigints "^1.0.1" -is-bigint@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" - integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: - has-bigints "^1.0.2" - -is-boolean-object@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" - integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== - dependencies: - call-bound "^1.0.3" - has-tostringtag "^1.0.2" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-buffer@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.2.7: +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.16.0, is-core-module@^2.5.0: +is-core-module@^2.13.0, is-core-module@^2.5.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" + integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== + dependencies: + hasown "^2.0.2" + +is-core-module@^2.16.0: version "2.16.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: hasown "^2.0.2" -is-data-view@^1.0.1, is-data-view@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" - integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== dependencies: - call-bound "^1.0.2" - get-intrinsic "^1.2.6" is-typed-array "^1.1.13" -is-date-object@^1.0.5, is-date-object@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" - integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: - call-bound "^1.0.2" - has-tostringtag "^1.0.2" + has-tostringtag "^1.0.0" is-decimal@^1.0.0: version "1.0.4" @@ -2342,13 +2351,6 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-finalizationregistry@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" - integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== - dependencies: - call-bound "^1.0.3" - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -2359,16 +2361,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.10: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" - integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== - dependencies: - call-bound "^1.0.3" - get-proto "^1.0.0" - has-tostringtag "^1.0.2" - safe-regex-test "^1.1.0" - is-glob@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -2381,18 +2373,17 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== -is-map@^2.0.3: +is-negative-zero@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" - integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== -is-number-object@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" - integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== dependencies: - call-bound "^1.0.3" - has-tostringtag "^1.0.2" + has-tostringtag "^1.0.0" is-number@^7.0.0: version "7.0.0" @@ -2409,76 +2400,53 @@ is-plain-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-regex@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" - integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: - call-bound "^1.0.2" - gopd "^1.2.0" - has-tostringtag "^1.0.2" - hasown "^2.0.2" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" -is-set@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" - integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== - -is-shared-array-buffer@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" - integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bound "^1.0.3" + call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" - integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== dependencies: - call-bound "^1.0.3" - has-tostringtag "^1.0.2" + has-tostringtag "^1.0.0" -is-symbol@^1.0.4, is-symbol@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" - integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: - call-bound "^1.0.2" - has-symbols "^1.1.0" - safe-regex-test "^1.1.0" + has-symbols "^1.0.2" -is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" - integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - which-typed-array "^1.1.16" + which-typed-array "^1.1.14" -is-weakmap@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" - integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== - -is-weakref@^1.0.2, is-weakref@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" - integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== dependencies: - call-bound "^1.0.3" - -is-weakset@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" - integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== - dependencies: - call-bound "^1.0.3" - get-intrinsic "^1.2.6" + call-bind "^1.0.2" isarray@^2.0.5: version "2.0.5" @@ -2921,13 +2889,13 @@ jest@^29.7.0: jest-cli "^29.7.0" js-tiktoken@^1.0.12: - version "1.0.19" - resolved "https://registry.yarnpkg.com/js-tiktoken/-/js-tiktoken-1.0.19.tgz#0298b584382f1d47d4b45cb93d382f11780eab78" - integrity sha512-XC63YQeEcS47Y53gg950xiZ4IWmkfMe4p2V9OSaBt26q+p47WHn18izuXzSclCI73B7yGqtfRsT6jcZQI0y08g== + version "1.0.18" + resolved "https://registry.yarnpkg.com/js-tiktoken/-/js-tiktoken-1.0.18.tgz#aaf68dda155bc693e6f0a572b9a359d569cb53df" + integrity sha512-hFYx4xYf6URgcttcGvGuOBJhTxPYZ2R5eIesqCaNRJmYH8sNmsfTeWg4yu//7u1VD/qIUkgKJTpGom9oHXmB4g== dependencies: base64-js "^1.5.1" -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -2966,9 +2934,9 @@ kleur@^3.0.3: integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== "langsmith@>=0.2.8 <0.4.0": - version "0.3.11" - resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.3.11.tgz#d18a096bf73d6b1bb3f2895f04cb48d2f5b2544c" - integrity sha512-pzA7wemfMjqCiaNY3AtUkQJ7jubIBmKRTl0dMNEUz8A4ewIqCEpB2caiTeeAwVkugEylny80cDk3u16WqL25Sw== + version "0.3.7" + resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.3.7.tgz#c29362f78ea2872252a60a680d6adb8b67e18b74" + integrity sha512-wakN1hxGkm1JR2PpAV7fiT7oC99LKcgxiuUrYGZWPbuj7Y8EPF19F7VNr4B+hA219bfaeWTa4Lxy2YrtPSKnQA== dependencies: "@types/uuid" "^10.0.0" chalk "^4.1.2" @@ -3022,13 +2990,6 @@ longest-streak@^2.0.0: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== -loose-envify@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - lru-cache@^10.2.0: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" @@ -3101,11 +3062,6 @@ markdown-table@^2.0.0: dependencies: repeat-string "^1.0.0" -math-intrinsics@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" - integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== - mdast-util-find-and-replace@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz#b7db1e873f96f66588c321f1363069abf607d1b5" @@ -3300,7 +3256,7 @@ micromark@^2.11.3, micromark@~2.11.0, micromark@~2.11.3: debug "^4.0.0" parse-entities "^2.0.0" -micromatch@^4.0.4, micromatch@^4.0.8: +micromatch@^4.0.4: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -3344,13 +3300,20 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.3, minimatch@^9.0.4, minimatch@^9.0.5: +minimatch@^9.0.3, minimatch@^9.0.5: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -3375,6 +3338,11 @@ mkdirp@^3.0.1: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -3432,26 +3400,24 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -object-inspect@^1.13.3: - version "1.13.4" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" - integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.7: - version "4.1.7" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" - integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" + call-bind "^1.0.5" define-properties "^1.2.1" - es-object-atoms "^1.0.0" - has-symbols "^1.1.0" + has-symbols "^1.0.3" object-keys "^1.1.1" once@^1.3.0: @@ -3468,15 +3434,6 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -own-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" - integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== - dependencies: - get-intrinsic "^1.2.6" - object-keys "^1.1.1" - safe-push-apply "^1.0.0" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -3596,7 +3553,12 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -picocolors@^1.0.0, picocolors@^1.1.1: +picocolors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== @@ -3619,14 +3581,14 @@ pkg-dir@^4.2.0: find-up "^4.0.0" possible-typed-array-names@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" - integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== prettier@^3.2.5: - version "3.5.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.2.tgz#d066c6053200da0234bf8fa1ef45168abed8b914" - integrity sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg== + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" @@ -3670,17 +3632,22 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +react-dom@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57" + integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ== + dependencies: + scheduler "^0.25.0" + react-is@^18.0.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -react@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" +react@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd" + integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ== read-pkg-up@^7.0.1: version "7.0.1" @@ -3714,31 +3681,15 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" - integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - call-bind "^1.0.8" - define-properties "^1.2.1" - es-abstract "^1.23.9" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.7" - get-proto "^1.0.1" - which-builtin-type "^1.2.1" - -regexp.prototype.flags@^1.5.3: - version "1.5.4" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" - integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== - dependencies: - call-bind "^1.0.8" + call-bind "^1.0.6" define-properties "^1.2.1" es-errors "^1.3.0" - get-proto "^1.0.1" - gopd "^1.2.0" - set-function-name "^2.0.2" + set-function-name "^2.0.1" remark-footnotes@^3.0.0: version "3.0.0" @@ -3798,7 +3749,16 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== -resolve@^1.10.0, resolve@^1.20.0: +resolve@^1.10.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.20.0: version "1.22.10" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== @@ -3813,9 +3773,9 @@ retry@^0.13.1: integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== reusify@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" - integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@^5.0.1: version "5.0.10" @@ -3825,31 +3785,30 @@ rimraf@^5.0.1: glob "^10.3.7" rollup@^4.5.2: - version "4.34.8" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.34.8.tgz#e859c1a51d899aba9bcf451d4eed1d11fb8e2a6e" - integrity sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ== + version "4.24.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.4.tgz#fdc76918de02213c95447c9ffff5e35dddb1d058" + integrity sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA== dependencies: "@types/estree" "1.0.6" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.34.8" - "@rollup/rollup-android-arm64" "4.34.8" - "@rollup/rollup-darwin-arm64" "4.34.8" - "@rollup/rollup-darwin-x64" "4.34.8" - "@rollup/rollup-freebsd-arm64" "4.34.8" - "@rollup/rollup-freebsd-x64" "4.34.8" - "@rollup/rollup-linux-arm-gnueabihf" "4.34.8" - "@rollup/rollup-linux-arm-musleabihf" "4.34.8" - "@rollup/rollup-linux-arm64-gnu" "4.34.8" - "@rollup/rollup-linux-arm64-musl" "4.34.8" - "@rollup/rollup-linux-loongarch64-gnu" "4.34.8" - "@rollup/rollup-linux-powerpc64le-gnu" "4.34.8" - "@rollup/rollup-linux-riscv64-gnu" "4.34.8" - "@rollup/rollup-linux-s390x-gnu" "4.34.8" - "@rollup/rollup-linux-x64-gnu" "4.34.8" - "@rollup/rollup-linux-x64-musl" "4.34.8" - "@rollup/rollup-win32-arm64-msvc" "4.34.8" - "@rollup/rollup-win32-ia32-msvc" "4.34.8" - "@rollup/rollup-win32-x64-msvc" "4.34.8" + "@rollup/rollup-android-arm-eabi" "4.24.4" + "@rollup/rollup-android-arm64" "4.24.4" + "@rollup/rollup-darwin-arm64" "4.24.4" + "@rollup/rollup-darwin-x64" "4.24.4" + "@rollup/rollup-freebsd-arm64" "4.24.4" + "@rollup/rollup-freebsd-x64" "4.24.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.24.4" + "@rollup/rollup-linux-arm-musleabihf" "4.24.4" + "@rollup/rollup-linux-arm64-gnu" "4.24.4" + "@rollup/rollup-linux-arm64-musl" "4.24.4" + "@rollup/rollup-linux-powerpc64le-gnu" "4.24.4" + "@rollup/rollup-linux-riscv64-gnu" "4.24.4" + "@rollup/rollup-linux-s390x-gnu" "4.24.4" + "@rollup/rollup-linux-x64-gnu" "4.24.4" + "@rollup/rollup-linux-x64-musl" "4.24.4" + "@rollup/rollup-win32-arm64-msvc" "4.24.4" + "@rollup/rollup-win32-ia32-msvc" "4.24.4" + "@rollup/rollup-win32-x64-msvc" "4.24.4" fsevents "~2.3.2" run-parallel@^1.1.9: @@ -3859,33 +3818,29 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-array-concat@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" - integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.8" - call-bound "^1.0.2" - get-intrinsic "^1.2.6" - has-symbols "^1.1.0" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" isarray "^2.0.5" -safe-push-apply@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" - integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: + call-bind "^1.0.6" es-errors "^1.3.0" - isarray "^2.0.5" + is-regex "^1.1.4" -safe-regex-test@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" - integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - is-regex "^1.2.1" +scheduler@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015" + integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA== "semver@2 || 3 || 4 || 5": version "5.7.2" @@ -3897,12 +3852,17 @@ semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.4, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3, semver@^7.7.1: - version "7.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" - integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== +semver@^7.3.4: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== -set-function-length@^1.2.2: +semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +set-function-length@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== @@ -3914,7 +3874,7 @@ set-function-length@^1.2.2: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-function-name@^2.0.2: +set-function-name@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== @@ -3924,15 +3884,6 @@ set-function-name@^2.0.2: functions-have-names "^1.2.3" has-property-descriptors "^1.0.2" -set-proto@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" - integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== - dependencies: - dunder-proto "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3945,45 +3896,15 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel-list@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" - integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: + call-bind "^1.0.7" es-errors "^1.3.0" - object-inspect "^1.13.3" - -side-channel-map@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" - integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - -side-channel-weakmap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" - integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - side-channel-map "^1.0.1" - -side-channel@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" - integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - side-channel-list "^1.0.0" - side-channel-map "^1.0.1" - side-channel-weakmap "^1.0.2" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" @@ -4045,9 +3966,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.21" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz#6d6e980c9df2b6fc905343a3b2d702a6239536c3" - integrity sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg== + version "3.0.18" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz#22aa922dcf2f2885a6494a261f2d8b75345d0326" + integrity sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ== sprintf-js@~1.0.2: version "1.0.3" @@ -4096,26 +4017,22 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.trim@^1.2.10: - version "1.2.10" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" - integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.8" - call-bound "^1.0.2" - define-data-property "^1.1.4" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.23.5" + es-abstract "^1.23.0" es-object-atoms "^1.0.0" - has-property-descriptors "^1.0.2" -string.prototype.trimend@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" - integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.8" - call-bound "^1.0.2" + call-bind "^1.0.7" define-properties "^1.2.1" es-object-atoms "^1.0.0" @@ -4171,6 +4088,13 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -4217,13 +4141,13 @@ transform-markdown-links@^2.0.0: integrity sha512-7HWQwQ9US+tJSMMzi1aP+KA3QwfjDs8sB4H5GBMRHFNBMQVdgoF6VfIFy2nJR/UHRTkYoGFwWh2pe+QIwSvfOA== traverse@^0.6.7: - version "0.6.11" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.11.tgz#e8daa071b101ae66767fffa6f177aa6f7110068e" - integrity sha512-vxXDZg8/+p3gblxB6BhhG5yWVn1kGRlaL8O78UDXc3wRnPizB5g83dcvWV1jpDMIPnjZjOFuxlMmE82XJ4407w== + version "0.6.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.9.tgz#76cfdbacf06382d460b76f8b735a44a6209d8b81" + integrity sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg== dependencies: - gopd "^1.2.0" - typedarray.prototype.slice "^1.0.5" - which-typed-array "^1.1.18" + gopd "^1.0.1" + typedarray.prototype.slice "^1.0.3" + which-typed-array "^1.1.15" trim-newlines@^3.0.0: version "3.0.1" @@ -4236,9 +4160,9 @@ trough@^1.0.0: integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== ts-jest@^29.1.2: - version "29.2.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.6.tgz#df53edf8b72fb89de032cfa310abf37582851d9a" - integrity sha512-yTNZVZqc8lSixm+QGVFcPe6+yj7+TWZwIesuOWvfcn4B9bz5x4NDzVCQQjOs7Hfouu36aEqfEbo9Qpo+gq8dDg== + version "29.2.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.5.tgz#591a3c108e1f5ebd013d3152142cb5472b399d63" + integrity sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA== dependencies: bs-logger "^0.2.6" ejs "^3.1.10" @@ -4247,7 +4171,7 @@ ts-jest@^29.1.2: json5 "^2.2.3" lodash.memoize "^4.1.2" make-error "^1.3.6" - semver "^7.7.1" + semver "^7.6.3" yargs-parser "^21.1.1" ts-morph@^21.0.1: @@ -4283,64 +4207,61 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -typed-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" - integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bound "^1.0.3" + call-bind "^1.0.7" es-errors "^1.3.0" - is-typed-array "^1.1.14" + is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" - integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== - dependencies: - call-bind "^1.0.8" - for-each "^0.3.3" - gopd "^1.2.0" - has-proto "^1.2.0" - is-typed-array "^1.1.14" - -typed-array-byte-offset@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" - integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.8" - for-each "^0.3.3" - gopd "^1.2.0" - has-proto "^1.2.0" - is-typed-array "^1.1.15" - reflect.getprototypeof "^1.0.9" - -typed-array-length@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" - integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" - reflect.getprototypeof "^1.0.6" -typedarray.prototype.slice@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz#a40f896968573b33cbb466a61622d3ee615a0728" - integrity sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg== +typedarray.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.3.tgz#bce2f685d3279f543239e4d595e0d021731d2d1a" + integrity sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A== dependencies: - call-bind "^1.0.8" + call-bind "^1.0.7" define-properties "^1.2.1" - es-abstract "^1.23.9" + es-abstract "^1.23.0" es-errors "^1.3.0" - get-proto "^1.0.1" - math-intrinsics "^1.1.0" - typed-array-buffer "^1.0.3" - typed-array-byte-offset "^1.0.4" + typed-array-buffer "^1.0.2" + typed-array-byte-offset "^1.0.2" typedoc-plugin-markdown@^4.4.2: version "4.4.2" @@ -4348,9 +4269,9 @@ typedoc-plugin-markdown@^4.4.2: integrity sha512-kJVkU2Wd+AXQpyL6DlYXXRrfNrHrEIUgiABWH8Z+2Lz5Sq6an4dQ/hfvP75bbokjNDUskOdFlEEm/0fSVyC7eg== typedoc@^0.27.7: - version "0.27.9" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.27.9.tgz#5e0a7bc32bfc7bd0b70a353f4f1d5cba3d667c46" - integrity sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw== + version "0.27.7" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.27.7.tgz#09047ffb5c845f45765de26c68b77260867fe967" + integrity sha512-K/JaUPX18+61W3VXek1cWC5gwmuLvYTOXJzBvD9W7jFvbPnefRnCHQCEPw7MSNrP/Hj7JJrhZtDDLKdcYm6ucg== dependencies: "@gerrit0/mini-shiki" "^1.24.0" lunr "^2.3.9" @@ -4359,34 +4280,34 @@ typedoc@^0.27.7: yaml "^2.6.1" typescript@^5.4.5: - version "5.7.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e" - integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw== + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== uc.micro@^2.0.0, uc.micro@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== -unbox-primitive@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" - integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== dependencies: - call-bound "^1.0.3" + call-bind "^1.0.2" has-bigints "^1.0.2" - has-symbols "^1.1.0" - which-boxed-primitive "^1.1.1" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" underscore@^1.13.2: - version "1.13.7" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" - integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g== + version "1.13.6" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" + integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== -undici-types@~6.19.2: - version "6.19.8" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== undici-types@~6.20.0: version "6.20.0" @@ -4495,56 +4416,26 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" - integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== - dependencies: - is-bigint "^1.1.0" - is-boolean-object "^1.2.1" - is-number-object "^1.1.1" - is-string "^1.1.1" - is-symbol "^1.1.1" - -which-builtin-type@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" - integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== - dependencies: - call-bound "^1.0.2" - function.prototype.name "^1.1.6" - has-tostringtag "^1.0.2" - is-async-function "^2.0.0" - is-date-object "^1.1.0" - is-finalizationregistry "^1.1.0" - is-generator-function "^1.0.10" - is-regex "^1.2.1" - is-weakref "^1.0.2" - isarray "^2.0.5" - which-boxed-primitive "^1.1.0" - which-collection "^1.0.2" - which-typed-array "^1.1.16" - -which-collection@^1.0.2: +which-boxed-primitive@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" - integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: - is-map "^2.0.3" - is-set "^2.0.3" - is-weakmap "^2.0.2" - is-weakset "^2.0.3" + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" -which-typed-array@^1.1.16, which-typed-array@^1.1.18: - version "1.1.18" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" - integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== +which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: available-typed-arrays "^1.0.7" - call-bind "^1.0.8" - call-bound "^1.0.3" + call-bind "^1.0.7" for-each "^0.3.3" - gopd "^1.2.0" + gopd "^1.0.1" has-tostringtag "^1.0.2" which@^2.0.1: @@ -4643,14 +4534,14 @@ yocto-queue@^0.1.0: integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zod-to-json-schema@^3.22.3: - version "3.24.3" - resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz#5958ba111d681f8d01c5b6b647425c9b8a6059e7" - integrity sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A== + version "3.24.1" + resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz#f08c6725091aadabffa820ba8d50c7ab527f227a" + integrity sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w== zod@^3.22.4: - version "3.24.2" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.2.tgz#8efa74126287c675e92f46871cfc8d15c34372b3" - integrity sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ== + version "3.24.1" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.1.tgz#27445c912738c8ad1e9de1bea0359fa44d9d35ee" + integrity sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A== zwitch@^1.0.0: version "1.0.5" diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py index c46132434..6f4583b7f 100644 --- a/libs/sdk-py/langgraph_sdk/client.py +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -388,7 +388,9 @@ class AssistantsClient: 'created_at': '2024-06-25T17:10:33.109781+00:00', 'updated_at': '2024-06-25T17:10:33.109781+00:00', 'config': {}, - 'metadata': {'created_by': 'system'} + 'metadata': {'created_by': 'system'}, + 'version': 1, + 'name': 'my_assistant' } """ # noqa: E501 @@ -742,7 +744,7 @@ class AssistantsClient: offset: The number of versions to skip. Returns: - list[Assistant]: A list of assistants. + list[AssistantVersion]: A list of assistant versions. Example Usage: @@ -1737,8 +1739,8 @@ class RunsClient: Example Usage: - await client.runs.delete( - thread_id="thread_id_to_delete", + await client.runs.list( + thread_id="thread_id", limit=5, offset=5, ) @@ -2139,6 +2141,7 @@ class StoreClient: key: str, value: dict[str, Any], index: Optional[Union[Literal[False], list[str]]] = None, + ttl: Optional[int] = None, ) -> None: """Store or update an item. @@ -2147,6 +2150,7 @@ class StoreClient: key: The unique identifier for the item within the namespace. value: A dictionary containing the item's data. index: Controls search indexing - None (use defaults), False (disable), or list of field paths to index. + ttl: Optional time-to-live in minutes for the item, or None for no expiration. Returns: None @@ -2164,15 +2168,29 @@ class StoreClient: raise ValueError( f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." ) - payload = {"namespace": namespace, "key": key, "value": value, "index": index} - await self.http.put("/store/items", json=payload) + payload = { + "namespace": namespace, + "key": key, + "value": value, + "index": index, + "ttl": ttl, + } + await self.http.put("/store/items", json=_provided_vals(payload)) - async def get_item(self, namespace: Sequence[str], /, key: str) -> Item: + async def get_item( + self, + namespace: Sequence[str], + /, + key: str, + *, + refresh_ttl: Optional[bool] = None, + ) -> Item: """Retrieve a single item. Args: key: The unique identifier for the item. namespace: Optional list of strings representing the namespace path. + refresh_ttl: Whether to refresh the TTL on this read operation. If None, uses the store's default behavior. Returns: Item: The retrieved item. @@ -2200,9 +2218,10 @@ class StoreClient: raise ValueError( f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." ) - return await self.http.get( - "/store/items", params={"namespace": ".".join(namespace), "key": key} - ) + params = {"namespace": ".".join(namespace), "key": key} + if refresh_ttl is not None: + params["refresh_ttl"] = refresh_ttl + return await self.http.get("/store/items", params=params) async def delete_item(self, namespace: Sequence[str], /, key: str) -> None: """Delete an item. @@ -2233,6 +2252,7 @@ class StoreClient: limit: int = 10, offset: int = 0, query: Optional[str] = None, + refresh_ttl: Optional[bool] = None, ) -> SearchItemsResponse: """Search for items within a namespace prefix. @@ -2242,6 +2262,7 @@ class StoreClient: limit: Maximum number of items to return (default is 10). offset: Number of items to skip before returning results (default is 0). query: Optional query for natural language search. + refresh_ttl: Whether to refresh the TTL on items returned by this search. If None, uses the store's default behavior. Returns: List[Item]: A list of items matching the search criteria. @@ -2280,6 +2301,7 @@ class StoreClient: "limit": limit, "offset": offset, "query": query, + "refresh_ttl": refresh_ttl, } return await self.http.post("/store/items/search", json=_provided_vals(payload)) @@ -2529,7 +2551,7 @@ def encode_json(json: Any) -> tuple[dict[str, str], bytes]: def decode_json(r: httpx.Response) -> Any: body = r.read() - return orjson.loads(body if body else None) + return orjson.loads(body) if body else None class SyncAssistantsClient: @@ -3893,8 +3915,8 @@ class SyncRunsClient: Example Usage: - client.runs.delete( - thread_id="thread_id_to_delete", + client.runs.list( + thread_id="thread_id", limit=5, offset=5, ) @@ -4283,6 +4305,7 @@ class SyncStoreClient: key: str, value: dict[str, Any], index: Optional[Union[Literal[False], list[str]]] = None, + ttl: Optional[int] = None, ) -> None: """Store or update an item. @@ -4291,7 +4314,7 @@ class SyncStoreClient: key: The unique identifier for the item within the namespace. value: A dictionary containing the item's data. index: Controls search indexing - None (use defaults), False (disable), or list of field paths to index. - + ttl: Optional time-to-live in minutes for the item, or None for no expiration. Returns: None @@ -4313,15 +4336,24 @@ class SyncStoreClient: "key": key, "value": value, "index": index, + "ttl": ttl, } - self.http.put("/store/items", json=payload) + self.http.put("/store/items", json=_provided_vals(payload)) - def get_item(self, namespace: Sequence[str], /, key: str) -> Item: + def get_item( + self, + namespace: Sequence[str], + /, + key: str, + *, + refresh_ttl: Optional[bool] = None, + ) -> Item: """Retrieve a single item. Args: key: The unique identifier for the item. namespace: Optional list of strings representing the namespace path. + refresh_ttl: Whether to refresh the TTL on this read operation. If None, uses the store's default behavior. Returns: Item: The retrieved item. @@ -4350,9 +4382,10 @@ class SyncStoreClient: f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." ) - return self.http.get( - "/store/items", params={"key": key, "namespace": ".".join(namespace)} - ) + params = {"key": key, "namespace": ".".join(namespace)} + if refresh_ttl is not None: + params["refresh_ttl"] = refresh_ttl + return self.http.get("/store/items", params=params) def delete_item(self, namespace: Sequence[str], /, key: str) -> None: """Delete an item. @@ -4381,6 +4414,7 @@ class SyncStoreClient: limit: int = 10, offset: int = 0, query: Optional[str] = None, + refresh_ttl: Optional[bool] = None, ) -> SearchItemsResponse: """Search for items within a namespace prefix. @@ -4390,6 +4424,7 @@ class SyncStoreClient: limit: Maximum number of items to return (default is 10). offset: Number of items to skip before returning results (default is 0). query: Optional query for natural language search. + refresh_ttl: Whether to refresh the TTL on items returned by this search. If None, uses the store's default behavior. Returns: List[Item]: A list of items matching the search criteria. @@ -4428,6 +4463,7 @@ class SyncStoreClient: "limit": limit, "offset": offset, "query": query, + "refresh_ttl": refresh_ttl, } return self.http.post("/store/items/search", json=_provided_vals(payload)) diff --git a/libs/sdk-py/langgraph_sdk/schema.py b/libs/sdk-py/langgraph_sdk/schema.py index ab5ad65f5..f6b8bb164 100644 --- a/libs/sdk-py/langgraph_sdk/schema.py +++ b/libs/sdk-py/langgraph_sdk/schema.py @@ -169,6 +169,8 @@ class AssistantBase(TypedDict): """The assistant metadata.""" version: int """The version of the assistant""" + name: str + """The name of the assistant""" class AssistantVersion(AssistantBase): @@ -182,8 +184,6 @@ class Assistant(AssistantBase): updated_at: datetime """The last time the assistant was updated.""" - name: str - """The name of the assistant""" class Interrupt(TypedDict, total=False): diff --git a/libs/sdk-py/poetry.lock b/libs/sdk-py/poetry.lock index 9c77f1417..583d001ae 100644 --- a/libs/sdk-py/poetry.lock +++ b/libs/sdk-py/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "anyio" -version = "4.8.0" +version = "4.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, - {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, + {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, + {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, ] [package.dependencies] @@ -19,29 +19,29 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2025.1.31" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, - {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "codespell" -version = "2.4.1" -description = "Fix common misspellings in text files" +version = "2.3.0" +description = "Codespell" optional = false python-versions = ">=3.8" files = [ - {file = "codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425"}, - {file = "codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5"}, + {file = "codespell-2.3.0-py3-none-any.whl", hash = "sha256:a9c7cef2501c9cfede2110fd6d4e5e62296920efe9abfb84648df866e47f58d1"}, + {file = "codespell-2.3.0.tar.gz", hash = "sha256:360c7d10f75e65f67bad720af7007e1060a5d395670ec11a7ed1fed9dd17471f"}, ] [package.extras] @@ -168,49 +168,49 @@ files = [ [[package]] name = "mypy" -version = "1.15.0" +version = "1.13.0" description = "Optional static typing for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"}, - {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"}, - {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"}, - {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"}, - {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"}, - {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"}, - {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"}, - {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"}, - {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"}, - {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"}, - {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"}, - {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"}, - {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"}, - {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"}, - {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"}, - {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"}, - {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"}, - {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"}, - {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"}, - {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"}, - {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"}, - {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"}, - {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"}, - {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"}, - {file = "mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078"}, - {file = "mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba"}, - {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5"}, - {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b"}, - {file = "mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2"}, - {file = "mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980"}, - {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"}, - {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] -mypy_extensions = ">=1.0.0" +mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing_extensions = ">=4.6.0" +typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] @@ -232,90 +232,86 @@ files = [ [[package]] name = "orjson" -version = "3.10.15" +version = "3.10.12" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e"}, - {file = "orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab"}, - {file = "orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806"}, - {file = "orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c"}, - {file = "orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e"}, - {file = "orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e"}, - {file = "orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a"}, - {file = "orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665"}, - {file = "orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa"}, - {file = "orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825"}, - {file = "orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890"}, - {file = "orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf"}, - {file = "orjson-3.10.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e8afd6200e12771467a1a44e5ad780614b86abb4b11862ec54861a82d677746"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9a18c500f19273e9e104cca8c1f0b40a6470bcccfc33afcc088045d0bf5ea6"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb00b7bfbdf5d34a13180e4805d76b4567025da19a197645ca746fc2fb536586"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33aedc3d903378e257047fee506f11e0833146ca3e57a1a1fb0ddb789876c1e1"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd0099ae6aed5eb1fc84c9eb72b95505a3df4267e6962eb93cdd5af03be71c98"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c864a80a2d467d7786274fce0e4f93ef2a7ca4ff31f7fc5634225aaa4e9e98c"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c25774c9e88a3e0013d7d1a6c8056926b607a61edd423b50eb5c88fd7f2823ae"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e78c211d0074e783d824ce7bb85bf459f93a233eb67a5b5003498232ddfb0e8a"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:43e17289ffdbbac8f39243916c893d2ae41a2ea1a9cbb060a56a4d75286351ae"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:781d54657063f361e89714293c095f506c533582ee40a426cb6489c48a637b81"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6875210307d36c94873f553786a808af2788e362bd0cf4c8e66d976791e7b528"}, - {file = "orjson-3.10.15-cp38-cp38-win32.whl", hash = "sha256:305b38b2b8f8083cc3d618927d7f424349afce5975b316d33075ef0f73576b60"}, - {file = "orjson-3.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:5dd9ef1639878cc3efffed349543cbf9372bdbd79f478615a1c633fe4e4180d1"}, - {file = "orjson-3.10.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ffe19f3e8d68111e8644d4f4e267a069ca427926855582ff01fc012496d19969"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d433bf32a363823863a96561a555227c18a522a8217a6f9400f00ddc70139ae2"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da03392674f59a95d03fa5fb9fe3a160b0511ad84b7a3914699ea5a1b3a38da2"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a63bb41559b05360ded9132032239e47983a39b151af1201f07ec9370715c82"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3766ac4702f8f795ff3fa067968e806b4344af257011858cc3d6d8721588b53f"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1c73dcc8fadbd7c55802d9aa093b36878d34a3b3222c41052ce6b0fc65f8e8"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b299383825eafe642cbab34be762ccff9fd3408d72726a6b2a4506d410a71ab3"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:abc7abecdbf67a173ef1316036ebbf54ce400ef2300b4e26a7b843bd446c2480"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3614ea508d522a621384c1d6639016a5a2e4f027f3e4a1c93a51867615d28829"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:295c70f9dc154307777ba30fe29ff15c1bcc9dfc5c48632f37d20a607e9ba85a"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:63309e3ff924c62404923c80b9e2048c1f74ba4b615e7584584389ada50ed428"}, - {file = "orjson-3.10.15-cp39-cp39-win32.whl", hash = "sha256:a2f708c62d026fb5340788ba94a55c23df4e1869fec74be455e0b2f5363b8507"}, - {file = "orjson-3.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:efcf6c735c3d22ef60c4aa27a5238f1a477df85e9b15f2142f9d669beb2d13fd"}, - {file = "orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e"}, + {file = "orjson-3.10.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ece01a7ec71d9940cc654c482907a6b65df27251255097629d0dea781f255c6d"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c34ec9aebc04f11f4b978dd6caf697a2df2dd9b47d35aa4cc606cabcb9df69d7"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd6ec8658da3480939c79b9e9e27e0db31dffcd4ba69c334e98c9976ac29140e"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17e6baf4cf01534c9de8a16c0c611f3d94925d1701bf5f4aff17003677d8ced"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6402ebb74a14ef96f94a868569f5dccf70d791de49feb73180eb3c6fda2ade56"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0000758ae7c7853e0a4a6063f534c61656ebff644391e1f81698c1b2d2fc8cd2"}, + {file = "orjson-3.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:888442dcee99fd1e5bd37a4abb94930915ca6af4db50e23e746cdf4d1e63db13"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c1f7a3ce79246aa0e92f5458d86c54f257fb5dfdc14a192651ba7ec2c00f8a05"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:802a3935f45605c66fb4a586488a38af63cb37aaad1c1d94c982c40dcc452e85"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1da1ef0113a2be19bb6c557fb0ec2d79c92ebd2fed4cfb1b26bab93f021fb885"}, + {file = "orjson-3.10.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a3273e99f367f137d5b3fecb5e9f45bcdbfac2a8b2f32fbc72129bbd48789c2"}, + {file = "orjson-3.10.12-cp310-none-win32.whl", hash = "sha256:475661bf249fd7907d9b0a2a2421b4e684355a77ceef85b8352439a9163418c3"}, + {file = "orjson-3.10.12-cp310-none-win_amd64.whl", hash = "sha256:87251dc1fb2b9e5ab91ce65d8f4caf21910d99ba8fb24b49fd0c118b2362d509"}, + {file = "orjson-3.10.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a734c62efa42e7df94926d70fe7d37621c783dea9f707a98cdea796964d4cf74"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:750f8b27259d3409eda8350c2919a58b0cfcd2054ddc1bd317a643afc646ef23"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb52c22bfffe2857e7aa13b4622afd0dd9d16ea7cc65fd2bf318d3223b1b6252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:440d9a337ac8c199ff8251e100c62e9488924c92852362cd27af0e67308c16ef"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e15c06491c69997dfa067369baab3bf094ecb74be9912bdc4339972323f252"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:362d204ad4b0b8724cf370d0cd917bb2dc913c394030da748a3bb632445ce7c4"}, + {file = "orjson-3.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b57cbb4031153db37b41622eac67329c7810e5f480fda4cfd30542186f006ae"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:165c89b53ef03ce0d7c59ca5c82fa65fe13ddf52eeb22e859e58c237d4e33b9b"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dee91b8dfd54557c1a1596eb90bcd47dbcd26b0baaed919e6861f076583e9da"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a4e1cfb72de6f905bdff061172adfb3caf7a4578ebf481d8f0530879476c07"}, + {file = "orjson-3.10.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:038d42c7bc0606443459b8fe2d1f121db474c49067d8d14c6a075bbea8bf14dd"}, + {file = "orjson-3.10.12-cp311-none-win32.whl", hash = "sha256:03b553c02ab39bed249bedd4abe37b2118324d1674e639b33fab3d1dafdf4d79"}, + {file = "orjson-3.10.12-cp311-none-win_amd64.whl", hash = "sha256:8b8713b9e46a45b2af6b96f559bfb13b1e02006f4242c156cbadef27800a55a8"}, + {file = "orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192"}, + {file = "orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be"}, + {file = "orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c"}, + {file = "orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708"}, + {file = "orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb"}, + {file = "orjson-3.10.12-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47962841b2a8aa9a258b377f5188db31ba49af47d4003a32f55d6f8b19006543"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6334730e2532e77b6054e87ca84f3072bee308a45a452ea0bffbbbc40a67e296"}, + {file = "orjson-3.10.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:accfe93f42713c899fdac2747e8d0d5c659592df2792888c6c5f829472e4f85e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7974c490c014c48810d1dede6c754c3cc46598da758c25ca3b4001ac45b703f"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3f250ce7727b0b2682f834a3facff88e310f52f07a5dcfd852d99637d386e79e"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f31422ff9486ae484f10ffc51b5ab2a60359e92d0716fcce1b3593d7bb8a9af6"}, + {file = "orjson-3.10.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5f29c5d282bb2d577c2a6bbde88d8fdcc4919c593f806aac50133f01b733846e"}, + {file = "orjson-3.10.12-cp313-none-win32.whl", hash = "sha256:f45653775f38f63dc0e6cd4f14323984c3149c05d6007b58cb154dd080ddc0dc"}, + {file = "orjson-3.10.12-cp313-none-win_amd64.whl", hash = "sha256:229994d0c376d5bdc91d92b3c9e6be2f1fbabd4cc1b59daae1443a46ee5e9825"}, + {file = "orjson-3.10.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7d69af5b54617a5fac5c8e5ed0859eb798e2ce8913262eb522590239db6c6763"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ed119ea7d2953365724a7059231a44830eb6bbb0cfead33fcbc562f5fd8f935"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5fc1238ef197e7cad5c91415f524aaa51e004be5a9b35a1b8a84ade196f73f"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43509843990439b05f848539d6f6198d4ac86ff01dd024b2f9a795c0daeeab60"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f72e27a62041cfb37a3de512247ece9f240a561e6c8662276beaf4d53d406db4"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a904f9572092bb6742ab7c16c623f0cdccbad9eeb2d14d4aa06284867bddd31"}, + {file = "orjson-3.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:855c0833999ed5dc62f64552db26f9be767434917d8348d77bacaab84f787d7b"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:897830244e2320f6184699f598df7fb9db9f5087d6f3f03666ae89d607e4f8ed"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:0b32652eaa4a7539f6f04abc6243619c56f8530c53bf9b023e1269df5f7816dd"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:36b4aa31e0f6a1aeeb6f8377769ca5d125db000f05c20e54163aef1d3fe8e833"}, + {file = "orjson-3.10.12-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5535163054d6cbf2796f93e4f0dbc800f61914c0e3c4ed8499cf6ece22b4a3da"}, + {file = "orjson-3.10.12-cp38-none-win32.whl", hash = "sha256:90a5551f6f5a5fa07010bf3d0b4ca2de21adafbbc0af6cb700b63cd767266cb9"}, + {file = "orjson-3.10.12-cp38-none-win_amd64.whl", hash = "sha256:703a2fb35a06cdd45adf5d733cf613cbc0cb3ae57643472b16bc22d325b5fb6c"}, + {file = "orjson-3.10.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f29de3ef71a42a5822765def1febfb36e0859d33abf5c2ad240acad5c6a1b78d"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de365a42acc65d74953f05e4772c974dad6c51cfc13c3240899f534d611be967"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a5a0158648a67ff0004cb0df5df7dcc55bfc9ca154d9c01597a23ad54c8d0c"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c47ce6b8d90fe9646a25b6fb52284a14ff215c9595914af63a5933a49972ce36"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0eee4c2c5bfb5c1b47a5db80d2ac7aaa7e938956ae88089f098aff2c0f35d5d8"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d3081bbe8b86587eb5c98a73b97f13d8f9fea685cf91a579beddacc0d10566"}, + {file = "orjson-3.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c23a6e90383884068bc2dba83d5222c9fcc3b99a0ed2411d38150734236755"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5472be7dc3269b4b52acba1433dac239215366f89dc1d8d0e64029abac4e714e"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7319cda750fca96ae5973efb31b17d97a5c5225ae0bc79bf5bf84df9e1ec2ab6"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:74d5ca5a255bf20b8def6a2b96b1e18ad37b4a122d59b154c458ee9494377f80"}, + {file = "orjson-3.10.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ff31d22ecc5fb85ef62c7d4afe8301d10c558d00dd24274d4bbe464380d3cd69"}, + {file = "orjson-3.10.12-cp39-none-win32.whl", hash = "sha256:c22c3ea6fba91d84fcb4cda30e64aff548fcf0c44c876e681f47d61d24b12e6b"}, + {file = "orjson-3.10.12-cp39-none-win_amd64.whl", hash = "sha256:be604f60d45ace6b0b33dd990a66b4526f1a7a186ac411c942674625456ca548"}, + {file = "orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff"}, ] [[package]] diff --git a/libs/sdk-py/pyproject.toml b/libs/sdk-py/pyproject.toml index c28b9a5e8..75e402fee 100644 --- a/libs/sdk-py/pyproject.toml +++ b/libs/sdk-py/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-sdk" -version = "0.1.54" +version = "0.1.57" description = "SDK for interacting with LangGraph API" authors = [] license = "MIT"