From 149803f096292612085bc1b0dedb2855e673c390 Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 17:59:31 -0500 Subject: [PATCH 1/9] Add LangGraph plugin samples Seven samples demonstrating the Temporal LangGraph plugin across both the Graph API and Functional API: - Human-in-the-loop: interrupt() + Temporal signals for chatbot approval - Continue-as-new: task result caching across workflow boundaries - ReAct agent: tool-calling loop with conditional edges / while loop - Control flow (Functional API only): parallel, for-loop, if/else Related SDK PR: https://github.com/temporalio/sdk-python/pull/1448 --- README.md | 1 + langgraph_plugin/README.md | 65 ++++++++++ langgraph_plugin/__init__.py | 0 langgraph_plugin/functional_api/__init__.py | 0 .../continue_as_new/__init__.py | 0 .../continue_as_new/run_worker.py | 36 ++++++ .../continue_as_new/run_workflow.py | 30 +++++ .../continue_as_new/workflow.py | 81 ++++++++++++ .../functional_api/control_flow/__init__.py | 0 .../functional_api/control_flow/run_worker.py | 36 ++++++ .../control_flow/run_workflow.py | 37 ++++++ .../functional_api/control_flow/workflow.py | 99 +++++++++++++++ .../human_in_the_loop/__init__.py | 0 .../human_in_the_loop/run_worker.py | 36 ++++++ .../human_in_the_loop/run_workflow.py | 38 ++++++ .../human_in_the_loop/workflow.py | 88 +++++++++++++ .../functional_api/react_agent/__init__.py | 0 .../functional_api/react_agent/run_worker.py | 36 ++++++ .../react_agent/run_workflow.py | 27 ++++ .../functional_api/react_agent/workflow.py | 90 ++++++++++++++ langgraph_plugin/graph_api/__init__.py | 0 .../graph_api/continue_as_new/__init__.py | 0 .../graph_api/continue_as_new/run_worker.py | 30 +++++ .../graph_api/continue_as_new/run_workflow.py | 30 +++++ .../graph_api/continue_as_new/workflow.py | 77 ++++++++++++ .../graph_api/human_in_the_loop/__init__.py | 0 .../graph_api/human_in_the_loop/run_worker.py | 30 +++++ .../human_in_the_loop/run_workflow.py | 37 ++++++ .../graph_api/human_in_the_loop/workflow.py | 75 +++++++++++ .../graph_api/react_agent/__init__.py | 0 .../graph_api/react_agent/run_worker.py | 30 +++++ .../graph_api/react_agent/run_workflow.py | 24 ++++ .../graph_api/react_agent/workflow.py | 116 ++++++++++++++++++ pyproject.toml | 7 ++ 34 files changed, 1156 insertions(+) create mode 100644 langgraph_plugin/README.md create mode 100644 langgraph_plugin/__init__.py create mode 100644 langgraph_plugin/functional_api/__init__.py create mode 100644 langgraph_plugin/functional_api/continue_as_new/__init__.py create mode 100644 langgraph_plugin/functional_api/continue_as_new/run_worker.py create mode 100644 langgraph_plugin/functional_api/continue_as_new/run_workflow.py create mode 100644 langgraph_plugin/functional_api/continue_as_new/workflow.py create mode 100644 langgraph_plugin/functional_api/control_flow/__init__.py create mode 100644 langgraph_plugin/functional_api/control_flow/run_worker.py create mode 100644 langgraph_plugin/functional_api/control_flow/run_workflow.py create mode 100644 langgraph_plugin/functional_api/control_flow/workflow.py create mode 100644 langgraph_plugin/functional_api/human_in_the_loop/__init__.py create mode 100644 langgraph_plugin/functional_api/human_in_the_loop/run_worker.py create mode 100644 langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py create mode 100644 langgraph_plugin/functional_api/human_in_the_loop/workflow.py create mode 100644 langgraph_plugin/functional_api/react_agent/__init__.py create mode 100644 langgraph_plugin/functional_api/react_agent/run_worker.py create mode 100644 langgraph_plugin/functional_api/react_agent/run_workflow.py create mode 100644 langgraph_plugin/functional_api/react_agent/workflow.py create mode 100644 langgraph_plugin/graph_api/__init__.py create mode 100644 langgraph_plugin/graph_api/continue_as_new/__init__.py create mode 100644 langgraph_plugin/graph_api/continue_as_new/run_worker.py create mode 100644 langgraph_plugin/graph_api/continue_as_new/run_workflow.py create mode 100644 langgraph_plugin/graph_api/continue_as_new/workflow.py create mode 100644 langgraph_plugin/graph_api/human_in_the_loop/__init__.py create mode 100644 langgraph_plugin/graph_api/human_in_the_loop/run_worker.py create mode 100644 langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py create mode 100644 langgraph_plugin/graph_api/human_in_the_loop/workflow.py create mode 100644 langgraph_plugin/graph_api/react_agent/__init__.py create mode 100644 langgraph_plugin/graph_api/react_agent/run_worker.py create mode 100644 langgraph_plugin/graph_api/react_agent/run_workflow.py create mode 100644 langgraph_plugin/graph_api/react_agent/workflow.py diff --git a/README.md b/README.md index d4d6a61b..a94d7b7f 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Some examples require extra dependencies. See each sample's directory for specif * [gevent_async](gevent_async) - Combine gevent and Temporal. * [hello_standalone_activity](hello_standalone_activity) - Use activities without using a workflow. * [langchain](langchain) - Orchestrate workflows for LangChain. +* [langgraph_plugin](langgraph_plugin) - Run LangGraph workflows as durable Temporal workflows (Graph API and Functional API). * [message_passing/introduction](message_passing/introduction/) - Introduction to queries, signals, and updates. * [message_passing/safe_message_handlers](message_passing/safe_message_handlers/) - Safely handling updates and signals. * [message_passing/update_with_start/lazy_initialization](message_passing/update_with_start/lazy_initialization/) - Use update-with-start to update a Shopping Cart, starting it if it does not exist. diff --git a/langgraph_plugin/README.md b/langgraph_plugin/README.md new file mode 100644 index 00000000..55c19d72 --- /dev/null +++ b/langgraph_plugin/README.md @@ -0,0 +1,65 @@ +# LangGraph Plugin Samples + +These samples demonstrate the [Temporal LangGraph plugin](https://github.com/temporalio/sdk-python/pull/1448), which runs LangGraph workflows as durable Temporal workflows. Each LangGraph graph node (Graph API) or `@task` (Functional API) executes as a Temporal activity with automatic retries, timeouts, and crash recovery. + +Samples are organized by API style: + +- **Graph API** (`graph_api/`) -- Define workflows as `StateGraph` with nodes and edges. +- **Functional API** (`functional_api/`) -- Define workflows with `@task` and `@entrypoint` decorators for an imperative programming style. + +## Samples + +| Sample | Graph API | Functional API | Description | +|--------|:---------:|:--------------:|-------------| +| **Human-in-the-loop** | [graph_api/human_in_the_loop](graph_api/human_in_the_loop) | [functional_api/human_in_the_loop](functional_api/human_in_the_loop) | Chatbot that uses `interrupt()` to pause for human approval, Temporal signals to receive feedback, and queries to expose the pending draft. | +| **Continue-as-new** | [graph_api/continue_as_new](graph_api/continue_as_new) | [functional_api/continue_as_new](functional_api/continue_as_new) | Multi-stage data pipeline that uses `continue-as-new` with task result caching so previously-completed stages are not re-executed. | +| **ReAct Agent** | [graph_api/react_agent](graph_api/react_agent) | [functional_api/react_agent](functional_api/react_agent) | Tool-calling agent loop. Graph API uses conditional edges; Functional API uses a `while` loop. | +| **Control Flow** | -- | [functional_api/control_flow](functional_api/control_flow) | Demonstrates parallel task execution, `for` loops, and `if/else` branching -- patterns that are natural in the Functional API. | + +## Prerequisites + +1. Install dependencies: + + ```bash + uv sync --group langgraph + ``` + +2. Start a [Temporal dev server](https://docs.temporal.io/cli#start-dev-server): + + ```bash + temporal server start-dev + ``` + +## Running a Sample + +Each sample has two scripts -- start the worker first, then the workflow starter in a separate terminal. + +```bash +# Terminal 1: start the worker +uv run langgraph_plugin///run_worker.py + +# Terminal 2: start the workflow +uv run langgraph_plugin///run_workflow.py +``` + +For example, to run the Graph API human-in-the-loop chatbot: + +```bash +# Terminal 1 +uv run langgraph_plugin/graph_api/human_in_the_loop/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py +``` + +## Key Features Demonstrated + +- **Durable execution** -- Every graph node / `@task` runs as a Temporal activity with configurable timeouts and retry policies. +- **Human-in-the-loop** -- LangGraph's `interrupt()` pauses the graph; Temporal signals deliver human input; queries expose pending state to UIs. +- **Continue-as-new with caching** -- `get_cache()` captures completed task results; passing the cache to the next execution avoids re-running them. +- **Conditional routing** -- Graph API's `add_conditional_edges` and Functional API's native `if/else`/`while` for agent loops. +- **Parallel execution** -- Functional API launches multiple tasks concurrently by creating futures before awaiting them. + +## Related + +- [SDK PR: LangGraph plugin](https://github.com/temporalio/sdk-python/pull/1448) diff --git a/langgraph_plugin/__init__.py b/langgraph_plugin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/functional_api/__init__.py b/langgraph_plugin/functional_api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/functional_api/continue_as_new/__init__.py b/langgraph_plugin/functional_api/continue_as_new/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/functional_api/continue_as_new/run_worker.py b/langgraph_plugin/functional_api/continue_as_new/run_worker.py new file mode 100644 index 00000000..aa15ca6a --- /dev/null +++ b/langgraph_plugin/functional_api/continue_as_new/run_worker.py @@ -0,0 +1,36 @@ +"""Worker for the continue-as-new pipeline (Functional API).""" + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.continue_as_new.workflow import ( + PipelineFunctionalWorkflow, + activity_options, + all_tasks, + pipeline_entrypoint, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + plugin = LangGraphPlugin( + entrypoints={"pipeline": pipeline_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + worker = Worker( + client, + task_queue="langgraph-pipeline-functional", + workflows=[PipelineFunctionalWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/continue_as_new/run_workflow.py b/langgraph_plugin/functional_api/continue_as_new/run_workflow.py new file mode 100644 index 00000000..bfbe8c4e --- /dev/null +++ b/langgraph_plugin/functional_api/continue_as_new/run_workflow.py @@ -0,0 +1,30 @@ +"""Start the continue-as-new pipeline workflow (Functional API).""" + +import asyncio +from datetime import timedelta + +from temporalio.client import Client + +from langgraph_plugin.functional_api.continue_as_new.workflow import ( + PipelineFunctionalWorkflow, + PipelineInput, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + result = await client.execute_workflow( + PipelineFunctionalWorkflow.run, + PipelineInput(data=10), + id="pipeline-functional-workflow", + task_queue="langgraph-pipeline-functional", + execution_timeout=timedelta(seconds=60), + ) + + # 10*2=20 -> 20+50=70 -> 70*3=210 + print(f"Pipeline result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/continue_as_new/workflow.py b/langgraph_plugin/functional_api/continue_as_new/workflow.py new file mode 100644 index 00000000..7e5dd221 --- /dev/null +++ b/langgraph_plugin/functional_api/continue_as_new/workflow.py @@ -0,0 +1,81 @@ +"""Continue-as-new with caching using the LangGraph Functional API with Temporal. + +Same pattern as the Graph API version, but using @task and @entrypoint decorators. +""" + +from dataclasses import dataclass +from datetime import timedelta +from typing import Any + +from langgraph.func import entrypoint as lg_entrypoint +from langgraph.func import task +from temporalio import workflow +from temporalio.contrib.langgraph import entrypoint, get_cache + + +@task +def extract(data: int) -> int: + """Stage 1: Extract -- simulate data extraction by doubling the input.""" + return data * 2 + + +@task +def transform(data: int) -> int: + """Stage 2: Transform -- simulate transformation by adding 50.""" + return data + 50 + + +@task +def load(data: int) -> int: + """Stage 3: Load -- simulate loading by tripling the result.""" + return data * 3 + + +@lg_entrypoint() +async def pipeline_entrypoint(data: int) -> dict: + """Run the 3-stage pipeline: extract -> transform -> load.""" + extracted = await extract(data) + transformed = await transform(extracted) + loaded = await load(transformed) + return {"result": loaded} + + +all_tasks = [extract, transform, load] + +activity_options = { + t.func.__name__: {"start_to_close_timeout": timedelta(seconds=30)} + for t in all_tasks +} + + +@dataclass +class PipelineInput: + data: int + cache: dict[str, Any] | None = None + phase: int = 1 + + +@workflow.defn +class PipelineFunctionalWorkflow: + """Runs the pipeline, continuing-as-new after each phase. + + Input 10: 10*2=20 -> 20+50=70 -> 70*3=210 + Each task executes once; phases 2 and 3 use cached results. + """ + + @workflow.run + async def run(self, input_data: PipelineInput) -> dict[str, Any]: + result = await entrypoint( + "pipeline", cache=input_data.cache + ).ainvoke(input_data.data) + + if input_data.phase < 3: + workflow.continue_as_new( + PipelineInput( + data=input_data.data, + cache=get_cache(), + phase=input_data.phase + 1, + ) + ) + + return result diff --git a/langgraph_plugin/functional_api/control_flow/__init__.py b/langgraph_plugin/functional_api/control_flow/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/functional_api/control_flow/run_worker.py b/langgraph_plugin/functional_api/control_flow/run_worker.py new file mode 100644 index 00000000..cf08a7c5 --- /dev/null +++ b/langgraph_plugin/functional_api/control_flow/run_worker.py @@ -0,0 +1,36 @@ +"""Worker for the control flow pipeline (Functional API).""" + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.control_flow.workflow import ( + ControlFlowWorkflow, + activity_options, + all_tasks, + control_flow_pipeline, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + plugin = LangGraphPlugin( + entrypoints={"control_flow": control_flow_pipeline}, + tasks=all_tasks, + activity_options=activity_options, + ) + + worker = Worker( + client, + task_queue="langgraph-control-flow", + workflows=[ControlFlowWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/control_flow/run_workflow.py b/langgraph_plugin/functional_api/control_flow/run_workflow.py new file mode 100644 index 00000000..ae88d0d8 --- /dev/null +++ b/langgraph_plugin/functional_api/control_flow/run_workflow.py @@ -0,0 +1,37 @@ +"""Start the control flow pipeline workflow (Functional API).""" + +import asyncio + +from temporalio.client import Client + +from langgraph_plugin.functional_api.control_flow.workflow import ( + ControlFlowWorkflow, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + items = [ + "Fix login bug", + "URGENT: Production outage in payments", + "Update README", + "INVALID:", + "Urgent: Security patch needed", + "Refactor test suite", + ] + + result = await client.execute_workflow( + ControlFlowWorkflow.run, + items, + id="control-flow-workflow", + task_queue="langgraph-control-flow", + ) + + print(f"Summary: {result['summary']}") + for r in result["results"]: + print(f" {r}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/control_flow/workflow.py b/langgraph_plugin/functional_api/control_flow/workflow.py new file mode 100644 index 00000000..b15ec1bd --- /dev/null +++ b/langgraph_plugin/functional_api/control_flow/workflow.py @@ -0,0 +1,99 @@ +"""Control flow sample using the LangGraph Functional API with Temporal. + +Demonstrates the Functional API's advantage for complex control flow: + - Parallel task execution (launch multiple tasks concurrently) + - Sequential for-loop processing + - Conditional if/else branching based on intermediate results +""" + +from datetime import timedelta + +from langgraph.func import entrypoint as lg_entrypoint +from langgraph.func import task +from temporalio import workflow +from temporalio.contrib.langgraph import entrypoint + + +@task +def validate_item(item: str) -> bool: + """Validate an item. Returns True if the item is non-empty and well-formed.""" + return len(item.strip()) > 0 and not item.startswith("INVALID:") + + +@task +def classify_item(item: str) -> str: + """Classify an item as 'urgent' or 'normal' based on its content.""" + return "urgent" if "urgent" in item.lower() else "normal" + + +@task +def process_urgent(item: str) -> str: + """Process an urgent item with priority handling.""" + return f"[PRIORITY] Processed: {item}" + + +@task +def process_normal(item: str) -> str: + """Process a normal item with standard handling.""" + return f"[STANDARD] Processed: {item}" + + +@task +def summarize(results: list[str]) -> str: + """Produce a summary of all processed results.""" + urgent_count = sum(1 for r in results if r.startswith("[PRIORITY]")) + normal_count = sum(1 for r in results if r.startswith("[STANDARD]")) + return ( + f"Processed {len(results)} items " + f"({urgent_count} urgent, {normal_count} normal)" + ) + + +@lg_entrypoint() +async def control_flow_pipeline(items: list[str]) -> dict: + """Process a batch of items with parallel validation, sequential + classification, and conditional routing. + """ + # PARALLEL: Validate all items concurrently. + # Creating task futures without awaiting launches them in parallel. + validation_futures = [validate_item(item) for item in items] + valid_flags = [await f for f in validation_futures] + valid_items = [ + item for item, is_valid in zip(items, valid_flags) if is_valid + ] + + # SEQUENTIAL + CONDITIONAL: Process each valid item + results = [] + for item in valid_items: + category = await classify_item(item) + if category == "urgent": + result = await process_urgent(item) + else: + result = await process_normal(item) + results.append(result) + + # Aggregate all results + summary_text = await summarize(results) + + return {"results": results, "summary": summary_text, "total": len(results)} + + +all_tasks = [ + validate_item, + classify_item, + process_urgent, + process_normal, + summarize, +] + +activity_options = { + t.func.__name__: {"start_to_close_timeout": timedelta(seconds=30)} + for t in all_tasks +} + + +@workflow.defn +class ControlFlowWorkflow: + @workflow.run + async def run(self, items: list[str]) -> dict: + return await entrypoint("control_flow").ainvoke(items) diff --git a/langgraph_plugin/functional_api/human_in_the_loop/__init__.py b/langgraph_plugin/functional_api/human_in_the_loop/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/functional_api/human_in_the_loop/run_worker.py b/langgraph_plugin/functional_api/human_in_the_loop/run_worker.py new file mode 100644 index 00000000..2d59bc58 --- /dev/null +++ b/langgraph_plugin/functional_api/human_in_the_loop/run_worker.py @@ -0,0 +1,36 @@ +"""Worker for the human-in-the-loop chatbot (Functional API).""" + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.human_in_the_loop.workflow import ( + ChatbotFunctionalWorkflow, + activity_options, + all_tasks, + chatbot_entrypoint, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + plugin = LangGraphPlugin( + entrypoints={"chatbot": chatbot_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + worker = Worker( + client, + task_queue="langgraph-chatbot-functional", + workflows=[ChatbotFunctionalWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py b/langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py new file mode 100644 index 00000000..164bde9d --- /dev/null +++ b/langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py @@ -0,0 +1,38 @@ +"""Start the human-in-the-loop chatbot workflow (Functional API).""" + +import asyncio + +from temporalio.client import Client + +from langgraph_plugin.functional_api.human_in_the_loop.workflow import ( + ChatbotFunctionalWorkflow, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + handle = await client.start_workflow( + ChatbotFunctionalWorkflow.run, + "What is the meaning of life?", + id="chatbot-functional-workflow", + task_queue="langgraph-chatbot-functional", + ) + + # Poll until the draft is ready for review + draft = None + while draft is None: + await asyncio.sleep(0.5) + draft = await handle.query(ChatbotFunctionalWorkflow.get_draft) + + print(f"Draft for review: {draft}") + + # Send approval via signal + await handle.signal(ChatbotFunctionalWorkflow.provide_feedback, "approve") + + result = await handle.result() + print(f"Final response: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/human_in_the_loop/workflow.py b/langgraph_plugin/functional_api/human_in_the_loop/workflow.py new file mode 100644 index 00000000..273cacaa --- /dev/null +++ b/langgraph_plugin/functional_api/human_in_the_loop/workflow.py @@ -0,0 +1,88 @@ +"""Human-in-the-loop chatbot using the LangGraph Functional API with Temporal. + +Same pattern as the Graph API version, but using @task and @entrypoint decorators. +""" + +from datetime import timedelta +from typing import Any + +from langgraph.checkpoint.memory import InMemorySaver +from langgraph.func import entrypoint as lg_entrypoint +from langgraph.func import task +from langgraph.types import Command, interrupt +from langchain_core.runnables import RunnableConfig +from temporalio import workflow +from temporalio.contrib.langgraph import entrypoint + + +@task +def generate_draft(message: str) -> str: + """Generate a draft response. Replace with an LLM call in production.""" + return ( + f"Here's my response to '{message}': " + "The answer is 42. Let me know if this helps!" + ) + + +@task +def request_human_review(draft: str) -> str: + """Pause execution to request human review of the draft.""" + feedback = interrupt(draft) + if feedback == "approve": + return draft + return f"[Revised] {draft} (incorporating feedback: {feedback})" + + +@lg_entrypoint() +async def chatbot_entrypoint(user_message: str) -> dict: + """Chatbot entrypoint: generate a draft, get human review, return result.""" + draft = await generate_draft(user_message) + final_response = await request_human_review(draft) + return {"response": final_response} + + +all_tasks = [generate_draft, request_human_review] + +activity_options = { + t.func.__name__: {"start_to_close_timeout": timedelta(seconds=30)} + for t in all_tasks +} + + +@workflow.defn +class ChatbotFunctionalWorkflow: + def __init__(self) -> None: + self._human_input: str | None = None + self._draft: str | None = None + + @workflow.signal + async def provide_feedback(self, feedback: str) -> None: + """Signal handler: receives human feedback.""" + self._human_input = feedback + + @workflow.query + def get_draft(self) -> str | None: + """Query handler: returns the pending draft for review, or None.""" + return self._draft + + @workflow.run + async def run(self, user_message: str) -> dict[str, Any]: + app = entrypoint("chatbot") + app.checkpointer = InMemorySaver() + config = RunnableConfig( + {"configurable": {"thread_id": workflow.info().workflow_id}} + ) + + # First invocation: runs until interrupt() pauses for human review + result = await app.ainvoke(user_message, config, version="v2") + + self._draft = result.interrupts[0].value + + # Wait for human feedback via Temporal signal + await workflow.wait_condition(lambda: self._human_input is not None) + + # Resume with the human's feedback + resumed = await app.ainvoke( + Command(resume=self._human_input), config, version="v2" + ) + return resumed.value diff --git a/langgraph_plugin/functional_api/react_agent/__init__.py b/langgraph_plugin/functional_api/react_agent/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/functional_api/react_agent/run_worker.py b/langgraph_plugin/functional_api/react_agent/run_worker.py new file mode 100644 index 00000000..0a4293ba --- /dev/null +++ b/langgraph_plugin/functional_api/react_agent/run_worker.py @@ -0,0 +1,36 @@ +"""Worker for the ReAct agent (Functional API).""" + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.react_agent.workflow import ( + ReactAgentFunctionalWorkflow, + activity_options, + all_tasks, + react_agent_entrypoint, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + plugin = LangGraphPlugin( + entrypoints={"react-agent": react_agent_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + worker = Worker( + client, + task_queue="langgraph-react-agent-functional", + workflows=[ReactAgentFunctionalWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/react_agent/run_workflow.py b/langgraph_plugin/functional_api/react_agent/run_workflow.py new file mode 100644 index 00000000..f652d165 --- /dev/null +++ b/langgraph_plugin/functional_api/react_agent/run_workflow.py @@ -0,0 +1,27 @@ +"""Start the ReAct agent workflow (Functional API).""" + +import asyncio + +from temporalio.client import Client + +from langgraph_plugin.functional_api.react_agent.workflow import ( + ReactAgentFunctionalWorkflow, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + result = await client.execute_workflow( + ReactAgentFunctionalWorkflow.run, + "Tell me about San Francisco", + id="react-agent-functional-workflow", + task_queue="langgraph-react-agent-functional", + ) + + print(f"Agent answer: {result['answer']}") + print(f"Tool calls made: {result['steps']}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/react_agent/workflow.py b/langgraph_plugin/functional_api/react_agent/workflow.py new file mode 100644 index 00000000..fd7b9ed6 --- /dev/null +++ b/langgraph_plugin/functional_api/react_agent/workflow.py @@ -0,0 +1,90 @@ +"""ReAct agent using the LangGraph Functional API with Temporal. + +Same pattern as the Graph API version, but using @task and @entrypoint. +The Functional API naturally expresses the ReAct loop as a while loop, +making the control flow explicit and easy to extend. +""" + +from datetime import timedelta + +from langgraph.func import entrypoint as lg_entrypoint +from langgraph.func import task +from temporalio import workflow +from temporalio.contrib.langgraph import entrypoint + + +@task +def agent_think(query: str, history: list[str]) -> dict: + """The agent decides the next action based on query and tool history. + + In production, replace this with an LLM call (e.g., Claude with tools). + """ + tool_results = [h for h in history if h.startswith("[Tool]")] + + if len(tool_results) == 0: + return { + "action": "tool", + "tool_name": "get_weather", + "tool_input": "San Francisco", + } + elif len(tool_results) == 1: + return { + "action": "tool", + "tool_name": "get_population", + "tool_input": "San Francisco", + } + else: + facts = "; ".join(tool_results) + return { + "action": "final", + "answer": ( + f"Here's what I found about San Francisco: {facts}" + ), + } + + +@task +def execute_tool(tool_name: str, tool_input: str) -> str: + """Execute a tool by name. In production, dispatch to real implementations.""" + tool_registry = { + "get_weather": lambda inp: f"[Tool] Weather in {inp}: 72°F and sunny.", + "get_population": lambda inp: ( + f"[Tool] {inp} population: ~870,000 residents." + ), + } + handler = tool_registry.get(tool_name) + if handler: + return handler(tool_input) + return f"[Tool] Unknown tool: {tool_name}" + + +@lg_entrypoint() +async def react_agent_entrypoint(query: str) -> dict: + """ReAct agent loop: think -> act -> observe -> repeat.""" + history: list[str] = [] + + while True: + decision = await agent_think(query, history) + + if decision["action"] == "final": + return {"answer": decision["answer"], "steps": len(history)} + + result = await execute_tool( + decision["tool_name"], decision["tool_input"] + ) + history.append(result) + + +all_tasks = [agent_think, execute_tool] + +activity_options = { + t.func.__name__: {"start_to_close_timeout": timedelta(seconds=30)} + for t in all_tasks +} + + +@workflow.defn +class ReactAgentFunctionalWorkflow: + @workflow.run + async def run(self, query: str) -> dict: + return await entrypoint("react-agent").ainvoke(query) diff --git a/langgraph_plugin/graph_api/__init__.py b/langgraph_plugin/graph_api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/graph_api/continue_as_new/__init__.py b/langgraph_plugin/graph_api/continue_as_new/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/graph_api/continue_as_new/run_worker.py b/langgraph_plugin/graph_api/continue_as_new/run_worker.py new file mode 100644 index 00000000..68e0003a --- /dev/null +++ b/langgraph_plugin/graph_api/continue_as_new/run_worker.py @@ -0,0 +1,30 @@ +"""Worker for the continue-as-new pipeline (Graph API).""" + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.continue_as_new.workflow import ( + PipelineWorkflow, + build_graph, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + plugin = LangGraphPlugin(graphs={"pipeline": build_graph()}) + + worker = Worker( + client, + task_queue="langgraph-pipeline", + workflows=[PipelineWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/continue_as_new/run_workflow.py b/langgraph_plugin/graph_api/continue_as_new/run_workflow.py new file mode 100644 index 00000000..29e06cba --- /dev/null +++ b/langgraph_plugin/graph_api/continue_as_new/run_workflow.py @@ -0,0 +1,30 @@ +"""Start the continue-as-new pipeline workflow (Graph API).""" + +import asyncio +from datetime import timedelta + +from temporalio.client import Client + +from langgraph_plugin.graph_api.continue_as_new.workflow import ( + PipelineInput, + PipelineWorkflow, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + result = await client.execute_workflow( + PipelineWorkflow.run, + PipelineInput(data=10), + id="pipeline-workflow", + task_queue="langgraph-pipeline", + execution_timeout=timedelta(seconds=60), + ) + + # 10*2=20 -> 20+50=70 -> 70*3=210 + print(f"Pipeline result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/continue_as_new/workflow.py b/langgraph_plugin/graph_api/continue_as_new/workflow.py new file mode 100644 index 00000000..67cd29d4 --- /dev/null +++ b/langgraph_plugin/graph_api/continue_as_new/workflow.py @@ -0,0 +1,77 @@ +"""Continue-as-new with caching using the LangGraph Graph API with Temporal. + +Demonstrates how to use Temporal's continue-as-new with LangGraph's task result +caching to avoid re-executing already-completed graph nodes across workflow +boundaries. +""" + +from dataclasses import dataclass +from datetime import timedelta +from typing import Any + +from langgraph.graph import START, StateGraph +from temporalio import workflow +from temporalio.contrib.langgraph import get_cache, graph + + +async def extract(data: int) -> int: + """Stage 1: Extract -- simulate data extraction by doubling the input.""" + return data * 2 + + +async def transform(data: int) -> int: + """Stage 2: Transform -- simulate transformation by adding 50.""" + return data + 50 + + +async def load(data: int) -> int: + """Stage 3: Load -- simulate loading by tripling the result.""" + return data * 3 + + +def build_graph() -> StateGraph: + """Construct the pipeline graph: extract -> transform -> load.""" + timeout = {"start_to_close_timeout": timedelta(seconds=30)} + g = StateGraph(int) + g.add_node("extract", extract, metadata=timeout) + g.add_node("transform", transform, metadata=timeout) + g.add_node("load", load, metadata=timeout) + g.add_edge(START, "extract") + g.add_edge("extract", "transform") + g.add_edge("transform", "load") + return g + + +@dataclass +class PipelineInput: + data: int + cache: dict[str, Any] | None = None + phase: int = 1 # continues-as-new after phases 1 and 2 + + +@workflow.defn +class PipelineWorkflow: + """Runs a 3-stage pipeline, continuing-as-new after each phase. + + Phase 1: all 3 stages execute, continues-as-new with cache. + Phase 2: all 3 stages cached (instant), continues-as-new. + Phase 3: all 3 stages cached (instant), returns final result. + + Input 10: 10*2=20 -> 20+50=70 -> 70*3=210 + """ + + @workflow.run + async def run(self, input_data: PipelineInput) -> int: + g = graph("pipeline", cache=input_data.cache).compile() + result = await g.ainvoke(input_data.data) + + if input_data.phase < 3: + workflow.continue_as_new( + PipelineInput( + data=input_data.data, + cache=get_cache(), + phase=input_data.phase + 1, + ) + ) + + return result diff --git a/langgraph_plugin/graph_api/human_in_the_loop/__init__.py b/langgraph_plugin/graph_api/human_in_the_loop/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/graph_api/human_in_the_loop/run_worker.py b/langgraph_plugin/graph_api/human_in_the_loop/run_worker.py new file mode 100644 index 00000000..122eeef5 --- /dev/null +++ b/langgraph_plugin/graph_api/human_in_the_loop/run_worker.py @@ -0,0 +1,30 @@ +"""Worker for the human-in-the-loop chatbot (Graph API).""" + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.human_in_the_loop.workflow import ( + ChatbotWorkflow, + build_graph, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + plugin = LangGraphPlugin(graphs={"chatbot": build_graph()}) + + worker = Worker( + client, + task_queue="langgraph-chatbot", + workflows=[ChatbotWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py b/langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py new file mode 100644 index 00000000..d7af5606 --- /dev/null +++ b/langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py @@ -0,0 +1,37 @@ +"""Start the human-in-the-loop chatbot workflow (Graph API).""" + +import asyncio + +from temporalio.client import Client + +from langgraph_plugin.graph_api.human_in_the_loop.workflow import ChatbotWorkflow + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + handle = await client.start_workflow( + ChatbotWorkflow.run, + "What is the meaning of life?", + id="chatbot-workflow", + task_queue="langgraph-chatbot", + ) + + # Poll until the draft is ready for review. + # In a real app, a UI would call this query endpoint. + draft = None + while draft is None: + await asyncio.sleep(0.5) + draft = await handle.query(ChatbotWorkflow.get_draft) + + print(f"Draft for review: {draft}") + + # Send approval via signal (a UI would trigger this) + await handle.signal(ChatbotWorkflow.provide_feedback, "approve") + + result = await handle.result() + print(f"Final response: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/human_in_the_loop/workflow.py b/langgraph_plugin/graph_api/human_in_the_loop/workflow.py new file mode 100644 index 00000000..b7737db5 --- /dev/null +++ b/langgraph_plugin/graph_api/human_in_the_loop/workflow.py @@ -0,0 +1,75 @@ +"""Human-in-the-loop chatbot using the LangGraph Graph API with Temporal. + +Demonstrates using LangGraph's interrupt() to pause a workflow for human input, +combined with Temporal signals to receive the input asynchronously. +""" + +from datetime import timedelta + +from langgraph.checkpoint.memory import InMemorySaver +from langgraph.graph import START, StateGraph +from langgraph.types import Command, interrupt +from langchain_core.runnables import RunnableConfig +from temporalio import workflow +from temporalio.contrib.langgraph import graph + + +async def generate_draft(message: str) -> str: + """Generate a draft response. Replace with an LLM call in production.""" + return ( + f"Here's my response to '{message}': " + "The answer is 42. Let me know if this helps!" + ) + + +async def human_review(draft: str) -> str: + """Present draft to human for review via interrupt.""" + feedback = interrupt(draft) + if feedback == "approve": + return draft + return f"[Revised] {draft} (incorporating feedback: {feedback})" + + +def build_graph() -> StateGraph: + """Construct the chatbot graph: generate_draft -> human_review.""" + timeout = {"start_to_close_timeout": timedelta(seconds=30)} + g = StateGraph(str) + g.add_node("generate_draft", generate_draft, metadata=timeout) + g.add_node("human_review", human_review, metadata=timeout) + g.add_edge(START, "generate_draft") + g.add_edge("generate_draft", "human_review") + return g + + +@workflow.defn +class ChatbotWorkflow: + def __init__(self) -> None: + self._human_input: str | None = None + self._draft: str | None = None + + @workflow.signal + async def provide_feedback(self, feedback: str) -> None: + """Signal handler: receives human feedback (approval or revision).""" + self._human_input = feedback + + @workflow.query + def get_draft(self) -> str | None: + """Query handler: returns the pending draft for review, or None.""" + return self._draft + + @workflow.run + async def run(self, user_message: str) -> str: + g = graph("chatbot").compile(checkpointer=InMemorySaver()) + config = RunnableConfig({"configurable": {"thread_id": "1"}}) + + # First invocation: runs generate_draft, then pauses at interrupt() + result = await g.ainvoke(user_message, config, version="v2") + + # Store the draft from the interrupt for the query handler + self._draft = result.interrupts[0].value + + # Wait for human feedback via Temporal signal + await workflow.wait_condition(lambda: self._human_input is not None) + + # Resume the graph with the human's feedback + return await g.ainvoke(Command(resume=self._human_input), config) diff --git a/langgraph_plugin/graph_api/react_agent/__init__.py b/langgraph_plugin/graph_api/react_agent/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/langgraph_plugin/graph_api/react_agent/run_worker.py b/langgraph_plugin/graph_api/react_agent/run_worker.py new file mode 100644 index 00000000..29bbc8b9 --- /dev/null +++ b/langgraph_plugin/graph_api/react_agent/run_worker.py @@ -0,0 +1,30 @@ +"""Worker for the ReAct agent (Graph API).""" + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.react_agent.workflow import ( + ReactAgentWorkflow, + build_graph, +) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + plugin = LangGraphPlugin(graphs={"react-agent": build_graph()}) + + worker = Worker( + client, + task_queue="langgraph-react-agent", + workflows=[ReactAgentWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/react_agent/run_workflow.py b/langgraph_plugin/graph_api/react_agent/run_workflow.py new file mode 100644 index 00000000..d188407a --- /dev/null +++ b/langgraph_plugin/graph_api/react_agent/run_workflow.py @@ -0,0 +1,24 @@ +"""Start the ReAct agent workflow (Graph API).""" + +import asyncio + +from temporalio.client import Client + +from langgraph_plugin.graph_api.react_agent.workflow import ReactAgentWorkflow + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + result = await client.execute_workflow( + ReactAgentWorkflow.run, + "Tell me about San Francisco", + id="react-agent-workflow", + task_queue="langgraph-react-agent", + ) + + print(f"Agent answer: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/react_agent/workflow.py b/langgraph_plugin/graph_api/react_agent/workflow.py new file mode 100644 index 00000000..455eb4b4 --- /dev/null +++ b/langgraph_plugin/graph_api/react_agent/workflow.py @@ -0,0 +1,116 @@ +"""ReAct agent using the LangGraph Graph API with Temporal. + +Demonstrates the most common LangGraph pattern: a tool-calling agent that loops +between "thinking" (deciding the next action) and "acting" (executing a tool), +using conditional edges to control the loop. + +Graph topology: + START -> agent -> (tools -> agent)* -> END +""" + +import operator +from datetime import timedelta +from typing import Annotated, Any, TypedDict + +from langgraph.graph import END, START, StateGraph +from temporalio import workflow +from temporalio.contrib.langgraph import graph + + +class AgentState(TypedDict): + """State for the ReAct agent. + + 'messages' uses operator.add so each node appends to the list rather + than replacing it, accumulating the full conversation history. + """ + + input: str + messages: Annotated[list[str], operator.add] + final_answer: str + + +async def agent(state: AgentState) -> dict[str, Any]: + """The agent decides what to do next based on the conversation history. + + In production, replace this with an LLM call (e.g., Claude with tools). + This stub simulates a 2-step research process. + """ + messages = state.get("messages", []) + tool_results = [m for m in messages if m.startswith("[Tool]")] + + if len(tool_results) == 0: + return { + "messages": [ + "[Agent] I need weather data. " + "Calling get_weather for San Francisco." + ] + } + elif len(tool_results) == 1: + return { + "messages": [ + "[Agent] Now I need population data. " + "Calling get_population for San Francisco." + ] + } + else: + facts = "; ".join(tool_results) + return { + "messages": ["[Agent] I have all the information I need."], + "final_answer": ( + f"Here's what I found about San Francisco: {facts}" + ), + } + + +async def tools(state: AgentState) -> dict[str, Any]: + """Execute the tool requested by the agent.""" + last_msg = state["messages"][-1] + + if "get_weather" in last_msg: + return { + "messages": ["[Tool] Weather in San Francisco: 72°F and sunny."] + } + elif "get_population" in last_msg: + return { + "messages": [ + "[Tool] San Francisco population: ~870,000 residents." + ] + } + else: + return {"messages": ["[Tool] Unknown tool requested."]} + + +async def should_continue(state: AgentState) -> str: + """Route: if the agent requested a tool, go to 'tools'. Otherwise, end. + + Must be async to avoid run_in_executor inside Temporal's workflow sandbox. + """ + last_msg = state["messages"][-1] + if last_msg.startswith("[Agent]") and "Calling" in last_msg: + return "tools" + return END + + +def build_graph() -> StateGraph: + """Construct the ReAct agent graph with conditional edges.""" + timeout = {"start_to_close_timeout": timedelta(seconds=30)} + g = StateGraph(AgentState) + g.add_node("agent", agent, metadata=timeout) + g.add_node("tools", tools, metadata=timeout) + g.add_edge(START, "agent") + g.add_conditional_edges("agent", should_continue) + g.add_edge("tools", "agent") + return g + + +@workflow.defn +class ReactAgentWorkflow: + @workflow.run + async def run(self, query: str) -> str: + initial_state: AgentState = { + "input": query, + "messages": [], + "final_answer": "", + } + result = await graph("react-agent").compile().ainvoke(initial_state) + return result["final_answer"] diff --git a/pyproject.toml b/pyproject.toml index caae123c..67fece35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,12 @@ langchain = [ "tqdm>=4.62.0,<5", "uvicorn[standard]>=0.24.0.post1,<0.25", ] +langgraph = [ + "langchain>=1.2.14", + "langchain-anthropic>=1.4.0", + "langgraph>=1.1.3", + "temporalio[langgraph]>=1.25", +] nexus = ["nexus-rpc>=1.1.0,<2"] open-telemetry = [ "temporalio[opentelemetry]", @@ -80,6 +86,7 @@ packages = [ "gevent_async", "hello", "langchain", + "langgraph_plugin", "message_passing", "nexus", "open_telemetry", From 8a260c603b63ceb6dd932518ff5dbd8f69a72abb Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 18:17:34 -0500 Subject: [PATCH 2/9] Remove explicit langchain deps from langgraph group to avoid conflict --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 67fece35..8dffee40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,8 +40,6 @@ langchain = [ "uvicorn[standard]>=0.24.0.post1,<0.25", ] langgraph = [ - "langchain>=1.2.14", - "langchain-anthropic>=1.4.0", "langgraph>=1.1.3", "temporalio[langgraph]>=1.25", ] From 042a51f46a05e73ca66a18f1036ac7b674fe4520 Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 18:19:15 -0500 Subject: [PATCH 3/9] Declare langchain and langgraph as conflicting dependency groups --- pyproject.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 8dffee40..f5fcf6b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,6 +125,14 @@ lint = [ lint-types = "uv run --all-groups mypy --check-untyped-defs --namespace-packages ." test = "uv run --all-groups pytest" +[tool.uv] +conflicts = [ + [ + { group = "langchain" }, + { group = "langgraph" }, + ], +] + [tool.pytest.ini_options] asyncio_mode = "auto" log_cli = true From 3e7f91bfaf2bdc44a8a14fe0d731d130ec3999c1 Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 18:22:53 -0500 Subject: [PATCH 4/9] Fix import sorting and formatting --- .../functional_api/continue_as_new/workflow.py | 6 +++--- .../functional_api/control_flow/workflow.py | 7 ++----- .../human_in_the_loop/workflow.py | 2 +- .../functional_api/react_agent/workflow.py | 12 +++--------- .../graph_api/human_in_the_loop/workflow.py | 2 +- .../graph_api/react_agent/workflow.py | 17 ++++------------- 6 files changed, 14 insertions(+), 32 deletions(-) diff --git a/langgraph_plugin/functional_api/continue_as_new/workflow.py b/langgraph_plugin/functional_api/continue_as_new/workflow.py index 7e5dd221..b1c5db1e 100644 --- a/langgraph_plugin/functional_api/continue_as_new/workflow.py +++ b/langgraph_plugin/functional_api/continue_as_new/workflow.py @@ -65,9 +65,9 @@ class PipelineFunctionalWorkflow: @workflow.run async def run(self, input_data: PipelineInput) -> dict[str, Any]: - result = await entrypoint( - "pipeline", cache=input_data.cache - ).ainvoke(input_data.data) + result = await entrypoint("pipeline", cache=input_data.cache).ainvoke( + input_data.data + ) if input_data.phase < 3: workflow.continue_as_new( diff --git a/langgraph_plugin/functional_api/control_flow/workflow.py b/langgraph_plugin/functional_api/control_flow/workflow.py index b15ec1bd..7eaa2175 100644 --- a/langgraph_plugin/functional_api/control_flow/workflow.py +++ b/langgraph_plugin/functional_api/control_flow/workflow.py @@ -44,8 +44,7 @@ def summarize(results: list[str]) -> str: urgent_count = sum(1 for r in results if r.startswith("[PRIORITY]")) normal_count = sum(1 for r in results if r.startswith("[STANDARD]")) return ( - f"Processed {len(results)} items " - f"({urgent_count} urgent, {normal_count} normal)" + f"Processed {len(results)} items ({urgent_count} urgent, {normal_count} normal)" ) @@ -58,9 +57,7 @@ async def control_flow_pipeline(items: list[str]) -> dict: # Creating task futures without awaiting launches them in parallel. validation_futures = [validate_item(item) for item in items] valid_flags = [await f for f in validation_futures] - valid_items = [ - item for item, is_valid in zip(items, valid_flags) if is_valid - ] + valid_items = [item for item, is_valid in zip(items, valid_flags) if is_valid] # SEQUENTIAL + CONDITIONAL: Process each valid item results = [] diff --git a/langgraph_plugin/functional_api/human_in_the_loop/workflow.py b/langgraph_plugin/functional_api/human_in_the_loop/workflow.py index 273cacaa..e21108a0 100644 --- a/langgraph_plugin/functional_api/human_in_the_loop/workflow.py +++ b/langgraph_plugin/functional_api/human_in_the_loop/workflow.py @@ -6,11 +6,11 @@ from datetime import timedelta from typing import Any +from langchain_core.runnables import RunnableConfig from langgraph.checkpoint.memory import InMemorySaver from langgraph.func import entrypoint as lg_entrypoint from langgraph.func import task from langgraph.types import Command, interrupt -from langchain_core.runnables import RunnableConfig from temporalio import workflow from temporalio.contrib.langgraph import entrypoint diff --git a/langgraph_plugin/functional_api/react_agent/workflow.py b/langgraph_plugin/functional_api/react_agent/workflow.py index fd7b9ed6..4cadcd79 100644 --- a/langgraph_plugin/functional_api/react_agent/workflow.py +++ b/langgraph_plugin/functional_api/react_agent/workflow.py @@ -37,9 +37,7 @@ def agent_think(query: str, history: list[str]) -> dict: facts = "; ".join(tool_results) return { "action": "final", - "answer": ( - f"Here's what I found about San Francisco: {facts}" - ), + "answer": (f"Here's what I found about San Francisco: {facts}"), } @@ -48,9 +46,7 @@ def execute_tool(tool_name: str, tool_input: str) -> str: """Execute a tool by name. In production, dispatch to real implementations.""" tool_registry = { "get_weather": lambda inp: f"[Tool] Weather in {inp}: 72°F and sunny.", - "get_population": lambda inp: ( - f"[Tool] {inp} population: ~870,000 residents." - ), + "get_population": lambda inp: f"[Tool] {inp} population: ~870,000 residents.", } handler = tool_registry.get(tool_name) if handler: @@ -69,9 +65,7 @@ async def react_agent_entrypoint(query: str) -> dict: if decision["action"] == "final": return {"answer": decision["answer"], "steps": len(history)} - result = await execute_tool( - decision["tool_name"], decision["tool_input"] - ) + result = await execute_tool(decision["tool_name"], decision["tool_input"]) history.append(result) diff --git a/langgraph_plugin/graph_api/human_in_the_loop/workflow.py b/langgraph_plugin/graph_api/human_in_the_loop/workflow.py index b7737db5..7ffca5e8 100644 --- a/langgraph_plugin/graph_api/human_in_the_loop/workflow.py +++ b/langgraph_plugin/graph_api/human_in_the_loop/workflow.py @@ -6,10 +6,10 @@ from datetime import timedelta +from langchain_core.runnables import RunnableConfig from langgraph.checkpoint.memory import InMemorySaver from langgraph.graph import START, StateGraph from langgraph.types import Command, interrupt -from langchain_core.runnables import RunnableConfig from temporalio import workflow from temporalio.contrib.langgraph import graph diff --git a/langgraph_plugin/graph_api/react_agent/workflow.py b/langgraph_plugin/graph_api/react_agent/workflow.py index 455eb4b4..4cc3550f 100644 --- a/langgraph_plugin/graph_api/react_agent/workflow.py +++ b/langgraph_plugin/graph_api/react_agent/workflow.py @@ -41,8 +41,7 @@ async def agent(state: AgentState) -> dict[str, Any]: if len(tool_results) == 0: return { "messages": [ - "[Agent] I need weather data. " - "Calling get_weather for San Francisco." + "[Agent] I need weather data. Calling get_weather for San Francisco." ] } elif len(tool_results) == 1: @@ -56,9 +55,7 @@ async def agent(state: AgentState) -> dict[str, Any]: facts = "; ".join(tool_results) return { "messages": ["[Agent] I have all the information I need."], - "final_answer": ( - f"Here's what I found about San Francisco: {facts}" - ), + "final_answer": (f"Here's what I found about San Francisco: {facts}"), } @@ -67,15 +64,9 @@ async def tools(state: AgentState) -> dict[str, Any]: last_msg = state["messages"][-1] if "get_weather" in last_msg: - return { - "messages": ["[Tool] Weather in San Francisco: 72°F and sunny."] - } + return {"messages": ["[Tool] Weather in San Francisco: 72°F and sunny."]} elif "get_population" in last_msg: - return { - "messages": [ - "[Tool] San Francisco population: ~870,000 residents." - ] - } + return {"messages": ["[Tool] San Francisco population: ~870,000 residents."]} else: return {"messages": ["[Tool] Unknown tool requested."]} From 0505fd1b816e29da9c9938520f32cc9b2276ecc9 Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 19:38:02 -0500 Subject: [PATCH 5/9] Update dependencies and lint config (temporarily - waiting for SDK PR merge) so that CI otherwise passes --- pyproject.toml | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f5fcf6b5..209b58e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,9 +31,9 @@ dsl = ["pyyaml>=6.0.1,<7", "types-pyyaml>=6.0.12,<7", "dacite>=1.8.1,<2"] encryption = ["cryptography>=38.0.1,<39", "aiohttp>=3.8.1,<4"] gevent = ["gevent>=25.4.2 ; python_version >= '3.8'"] langchain = [ - "langchain>=0.1.7,<0.2 ; python_version >= '3.8.1' and python_version < '4.0'", - "langchain-openai>=0.0.6,<0.0.7 ; python_version >= '3.8.1' and python_version < '4.0'", - "langsmith>=0.1.22,<0.2 ; python_version >= '3.8.1' and python_version < '4.0'", + "langchain>=0.3.0", + "langchain-openai>=0.3.0", + "langsmith>=0.1.22", "openai>=1.4.0,<2", "fastapi>=0.115.12", "tqdm>=4.62.0,<5", @@ -122,16 +122,8 @@ lint = [ { cmd = "uv run ruff format --check" }, { ref = "lint-types" }, ] -lint-types = "uv run --all-groups mypy --check-untyped-defs --namespace-packages ." -test = "uv run --all-groups pytest" - -[tool.uv] -conflicts = [ - [ - { group = "langchain" }, - { group = "langgraph" }, - ], -] +lint-types = "uv run --all-groups --no-group langgraph --no-group cloud-export-to-parquet mypy --check-untyped-defs --namespace-packages ." +test = "uv run --all-groups --no-group langgraph --no-group cloud-export-to-parquet pytest" [tool.pytest.ini_options] asyncio_mode = "auto" @@ -150,6 +142,10 @@ namespace_packages = true module = "aiohttp.*" ignore_errors = true +[[tool.mypy.overrides]] +module = "langgraph_plugin.*" +ignore_errors = true + [[tool.mypy.overrides]] module = "opentelemetry.*" ignore_errors = true From ee781cd6c32095e27746c18358a86431cb0af344 Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 21:21:41 -0500 Subject: [PATCH 6/9] Add hello_world samples, per-sample READMEs, tests, __init__ docstrings, and configurable client --- langgraph_plugin/README.md | 1 + langgraph_plugin/__init__.py | 1 + langgraph_plugin/functional_api/__init__.py | 1 + .../functional_api/continue_as_new/README.md | 36 + .../continue_as_new/__init__.py | 1 + .../continue_as_new/run_worker.py | 3 +- .../continue_as_new/run_workflow.py | 3 +- .../functional_api/control_flow/README.md | 37 + .../functional_api/control_flow/__init__.py | 1 + .../functional_api/control_flow/run_worker.py | 3 +- .../control_flow/run_workflow.py | 3 +- .../functional_api/hello_world/README.md | 29 + .../functional_api/hello_world/__init__.py | 1 + .../functional_api/hello_world/run_worker.py | 37 + .../hello_world/run_workflow.py | 27 + .../functional_api/hello_world/workflow.py | 39 + .../human_in_the_loop/README.md | 37 + .../human_in_the_loop/__init__.py | 1 + .../human_in_the_loop/run_worker.py | 3 +- .../human_in_the_loop/run_workflow.py | 3 +- .../functional_api/react_agent/README.md | 44 + .../functional_api/react_agent/__init__.py | 1 + .../functional_api/react_agent/run_worker.py | 3 +- .../react_agent/run_workflow.py | 3 +- langgraph_plugin/graph_api/__init__.py | 1 + .../graph_api/continue_as_new/README.md | 37 + .../graph_api/continue_as_new/__init__.py | 1 + .../graph_api/continue_as_new/run_worker.py | 3 +- .../graph_api/continue_as_new/run_workflow.py | 3 +- .../graph_api/hello_world/README.md | 29 + .../graph_api/hello_world/__init__.py | 1 + .../graph_api/hello_world/run_worker.py | 31 + .../graph_api/hello_world/run_workflow.py | 25 + .../graph_api/hello_world/workflow.py | 34 + .../graph_api/human_in_the_loop/README.md | 38 + .../graph_api/human_in_the_loop/__init__.py | 1 + .../graph_api/human_in_the_loop/run_worker.py | 3 +- .../human_in_the_loop/run_workflow.py | 3 +- .../graph_api/react_agent/README.md | 42 + .../graph_api/react_agent/__init__.py | 1 + .../graph_api/react_agent/run_worker.py | 3 +- .../graph_api/react_agent/run_workflow.py | 3 +- tests/langgraph_plugin/__init__.py | 1 + .../langgraph_plugin/continue_as_new_test.py | 34 + .../functional_continue_as_new_test.py | 40 + .../functional_control_flow_test.py | 52 ++ .../functional_hello_world_test.py | 37 + .../functional_human_in_the_loop_test.py | 51 ++ .../functional_react_agent_test.py | 37 + tests/langgraph_plugin/hello_world_test.py | 51 ++ .../human_in_the_loop_test.py | 79 ++ tests/langgraph_plugin/react_agent_test.py | 32 + uv.lock | 799 ++++++++++++------ 53 files changed, 1495 insertions(+), 295 deletions(-) create mode 100644 langgraph_plugin/functional_api/continue_as_new/README.md create mode 100644 langgraph_plugin/functional_api/control_flow/README.md create mode 100644 langgraph_plugin/functional_api/hello_world/README.md create mode 100644 langgraph_plugin/functional_api/hello_world/__init__.py create mode 100644 langgraph_plugin/functional_api/hello_world/run_worker.py create mode 100644 langgraph_plugin/functional_api/hello_world/run_workflow.py create mode 100644 langgraph_plugin/functional_api/hello_world/workflow.py create mode 100644 langgraph_plugin/functional_api/human_in_the_loop/README.md create mode 100644 langgraph_plugin/functional_api/react_agent/README.md create mode 100644 langgraph_plugin/graph_api/continue_as_new/README.md create mode 100644 langgraph_plugin/graph_api/hello_world/README.md create mode 100644 langgraph_plugin/graph_api/hello_world/__init__.py create mode 100644 langgraph_plugin/graph_api/hello_world/run_worker.py create mode 100644 langgraph_plugin/graph_api/hello_world/run_workflow.py create mode 100644 langgraph_plugin/graph_api/hello_world/workflow.py create mode 100644 langgraph_plugin/graph_api/human_in_the_loop/README.md create mode 100644 langgraph_plugin/graph_api/react_agent/README.md create mode 100644 tests/langgraph_plugin/__init__.py create mode 100644 tests/langgraph_plugin/continue_as_new_test.py create mode 100644 tests/langgraph_plugin/functional_continue_as_new_test.py create mode 100644 tests/langgraph_plugin/functional_control_flow_test.py create mode 100644 tests/langgraph_plugin/functional_hello_world_test.py create mode 100644 tests/langgraph_plugin/functional_human_in_the_loop_test.py create mode 100644 tests/langgraph_plugin/functional_react_agent_test.py create mode 100644 tests/langgraph_plugin/hello_world_test.py create mode 100644 tests/langgraph_plugin/human_in_the_loop_test.py create mode 100644 tests/langgraph_plugin/react_agent_test.py diff --git a/langgraph_plugin/README.md b/langgraph_plugin/README.md index 55c19d72..e13a7b9a 100644 --- a/langgraph_plugin/README.md +++ b/langgraph_plugin/README.md @@ -11,6 +11,7 @@ Samples are organized by API style: | Sample | Graph API | Functional API | Description | |--------|:---------:|:--------------:|-------------| +| **Hello World** | [graph_api/hello_world](graph_api/hello_world) | [functional_api/hello_world](functional_api/hello_world) | Minimal sample -- single node/task that processes a query string. Start here. | | **Human-in-the-loop** | [graph_api/human_in_the_loop](graph_api/human_in_the_loop) | [functional_api/human_in_the_loop](functional_api/human_in_the_loop) | Chatbot that uses `interrupt()` to pause for human approval, Temporal signals to receive feedback, and queries to expose the pending draft. | | **Continue-as-new** | [graph_api/continue_as_new](graph_api/continue_as_new) | [functional_api/continue_as_new](functional_api/continue_as_new) | Multi-stage data pipeline that uses `continue-as-new` with task result caching so previously-completed stages are not re-executed. | | **ReAct Agent** | [graph_api/react_agent](graph_api/react_agent) | [functional_api/react_agent](functional_api/react_agent) | Tool-calling agent loop. Graph API uses conditional edges; Functional API uses a `while` loop. | diff --git a/langgraph_plugin/__init__.py b/langgraph_plugin/__init__.py index e69de29b..a8523185 100644 --- a/langgraph_plugin/__init__.py +++ b/langgraph_plugin/__init__.py @@ -0,0 +1 @@ +"""Temporal LangGraph plugin samples.""" diff --git a/langgraph_plugin/functional_api/__init__.py b/langgraph_plugin/functional_api/__init__.py index e69de29b..6caae83e 100644 --- a/langgraph_plugin/functional_api/__init__.py +++ b/langgraph_plugin/functional_api/__init__.py @@ -0,0 +1 @@ +"""LangGraph Functional API samples using @task and @entrypoint.""" diff --git a/langgraph_plugin/functional_api/continue_as_new/README.md b/langgraph_plugin/functional_api/continue_as_new/README.md new file mode 100644 index 00000000..a26fa288 --- /dev/null +++ b/langgraph_plugin/functional_api/continue_as_new/README.md @@ -0,0 +1,36 @@ +# Continue-as-New with Caching (Functional API) + +Same pattern as the Graph API version, using `@task` and `@entrypoint` decorators. + +## What This Sample Demonstrates + +- Task result caching across continue-as-new boundaries with `get_cache()` +- Restoring cached results with `entrypoint(name, cache=...)` +- Each `@task` executes exactly once despite multiple workflow invocations + +## How It Works + +1. Three tasks run sequentially: `extract` (x2) -> `transform` (+50) -> `load` (x3). +2. After the first invocation, the workflow continues-as-new with the cache. +3. On subsequent invocations, all tasks return cached results instantly. +4. Input 10 -> 20 -> 70 -> 210. + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/functional_api/continue_as_new/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/functional_api/continue_as_new/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `@task` functions, `@entrypoint`, `PipelineInput`, and `PipelineFunctionalWorkflow` | +| `run_worker.py` | Registers tasks and entrypoint with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Executes the pipeline workflow and prints the result | diff --git a/langgraph_plugin/functional_api/continue_as_new/__init__.py b/langgraph_plugin/functional_api/continue_as_new/__init__.py index e69de29b..5b90703e 100644 --- a/langgraph_plugin/functional_api/continue_as_new/__init__.py +++ b/langgraph_plugin/functional_api/continue_as_new/__init__.py @@ -0,0 +1 @@ +"""Continue-as-new pipeline with task result caching.""" diff --git a/langgraph_plugin/functional_api/continue_as_new/run_worker.py b/langgraph_plugin/functional_api/continue_as_new/run_worker.py index aa15ca6a..a6b6a9d7 100644 --- a/langgraph_plugin/functional_api/continue_as_new/run_worker.py +++ b/langgraph_plugin/functional_api/continue_as_new/run_worker.py @@ -1,6 +1,7 @@ """Worker for the continue-as-new pipeline (Functional API).""" import asyncio +import os from temporalio.client import Client from temporalio.contrib.langgraph import LangGraphPlugin @@ -15,7 +16,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) plugin = LangGraphPlugin( entrypoints={"pipeline": pipeline_entrypoint}, tasks=all_tasks, diff --git a/langgraph_plugin/functional_api/continue_as_new/run_workflow.py b/langgraph_plugin/functional_api/continue_as_new/run_workflow.py index bfbe8c4e..563aaba6 100644 --- a/langgraph_plugin/functional_api/continue_as_new/run_workflow.py +++ b/langgraph_plugin/functional_api/continue_as_new/run_workflow.py @@ -1,6 +1,7 @@ """Start the continue-as-new pipeline workflow (Functional API).""" import asyncio +import os from datetime import timedelta from temporalio.client import Client @@ -12,7 +13,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) result = await client.execute_workflow( PipelineFunctionalWorkflow.run, diff --git a/langgraph_plugin/functional_api/control_flow/README.md b/langgraph_plugin/functional_api/control_flow/README.md new file mode 100644 index 00000000..9e47a095 --- /dev/null +++ b/langgraph_plugin/functional_api/control_flow/README.md @@ -0,0 +1,37 @@ +# Control Flow (Functional API) + +Demonstrates the Functional API's strength for complex control flow: parallel execution, sequential loops, and conditional branching — all as natural Python code. + +## What This Sample Demonstrates + +- **Parallel execution**: launching multiple tasks concurrently by creating futures before awaiting +- **For loops**: processing items sequentially with `for item in items` +- **If/else branching**: routing items based on classification results +- Why the Functional API is ideal for programmatic composition patterns + +## How It Works + +1. A batch of items is validated **in parallel** — all `validate_item` tasks launch concurrently. +2. Valid items are processed **sequentially** in a for loop. +3. Each item is classified, then routed via **if/else** to `process_urgent` or `process_normal`. +4. Results are aggregated with a `summarize` task. + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/functional_api/control_flow/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/functional_api/control_flow/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `@task` functions (validate, classify, process, summarize), `@entrypoint`, and `ControlFlowWorkflow` | +| `run_worker.py` | Registers tasks and entrypoint with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Sends a batch of items and prints processing results | diff --git a/langgraph_plugin/functional_api/control_flow/__init__.py b/langgraph_plugin/functional_api/control_flow/__init__.py index e69de29b..e78d3ea4 100644 --- a/langgraph_plugin/functional_api/control_flow/__init__.py +++ b/langgraph_plugin/functional_api/control_flow/__init__.py @@ -0,0 +1 @@ +"""Control flow: parallel execution, for loops, and if/else branching.""" diff --git a/langgraph_plugin/functional_api/control_flow/run_worker.py b/langgraph_plugin/functional_api/control_flow/run_worker.py index cf08a7c5..183be9b7 100644 --- a/langgraph_plugin/functional_api/control_flow/run_worker.py +++ b/langgraph_plugin/functional_api/control_flow/run_worker.py @@ -1,6 +1,7 @@ """Worker for the control flow pipeline (Functional API).""" import asyncio +import os from temporalio.client import Client from temporalio.contrib.langgraph import LangGraphPlugin @@ -15,7 +16,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) plugin = LangGraphPlugin( entrypoints={"control_flow": control_flow_pipeline}, tasks=all_tasks, diff --git a/langgraph_plugin/functional_api/control_flow/run_workflow.py b/langgraph_plugin/functional_api/control_flow/run_workflow.py index ae88d0d8..2784415b 100644 --- a/langgraph_plugin/functional_api/control_flow/run_workflow.py +++ b/langgraph_plugin/functional_api/control_flow/run_workflow.py @@ -1,6 +1,7 @@ """Start the control flow pipeline workflow (Functional API).""" import asyncio +import os from temporalio.client import Client @@ -10,7 +11,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) items = [ "Fix login bug", diff --git a/langgraph_plugin/functional_api/hello_world/README.md b/langgraph_plugin/functional_api/hello_world/README.md new file mode 100644 index 00000000..62252c90 --- /dev/null +++ b/langgraph_plugin/functional_api/hello_world/README.md @@ -0,0 +1,29 @@ +# Hello World (Functional API) + +The simplest possible LangGraph Functional API + Temporal sample: a single `@task` called from an `@entrypoint`. + +## What This Sample Demonstrates + +- Defining a `@task` and `@entrypoint` +- Wrapping them with `LangGraphPlugin` so the task runs as a Temporal activity +- Invoking the entrypoint from a Temporal workflow + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/functional_api/hello_world/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/functional_api/hello_world/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `process_query` task, `hello_entrypoint`, and `HelloWorldFunctionalWorkflow` | +| `run_worker.py` | Registers task and entrypoint with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Executes the workflow and prints the result | diff --git a/langgraph_plugin/functional_api/hello_world/__init__.py b/langgraph_plugin/functional_api/hello_world/__init__.py new file mode 100644 index 00000000..97766011 --- /dev/null +++ b/langgraph_plugin/functional_api/hello_world/__init__.py @@ -0,0 +1 @@ +"""Minimal hello world — @task and @entrypoint.""" diff --git a/langgraph_plugin/functional_api/hello_world/run_worker.py b/langgraph_plugin/functional_api/hello_world/run_worker.py new file mode 100644 index 00000000..7039ee02 --- /dev/null +++ b/langgraph_plugin/functional_api/hello_world/run_worker.py @@ -0,0 +1,37 @@ +"""Worker for the hello world sample (Functional API).""" + +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.hello_world.workflow import ( + HelloWorldFunctionalWorkflow, + activity_options, + all_tasks, + hello_entrypoint, +) + + +async def main() -> None: + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) + plugin = LangGraphPlugin( + entrypoints={"hello-world": hello_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + worker = Worker( + client, + task_queue="langgraph-hello-world-functional", + workflows=[HelloWorldFunctionalWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/hello_world/run_workflow.py b/langgraph_plugin/functional_api/hello_world/run_workflow.py new file mode 100644 index 00000000..77cc92fb --- /dev/null +++ b/langgraph_plugin/functional_api/hello_world/run_workflow.py @@ -0,0 +1,27 @@ +"""Start the hello world workflow (Functional API).""" + +import asyncio +import os + +from temporalio.client import Client + +from langgraph_plugin.functional_api.hello_world.workflow import ( + HelloWorldFunctionalWorkflow, +) + + +async def main() -> None: + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) + + result = await client.execute_workflow( + HelloWorldFunctionalWorkflow.run, + "Hello, Temporal + LangGraph!", + id="hello-world-functional-workflow", + task_queue="langgraph-hello-world-functional", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/hello_world/workflow.py b/langgraph_plugin/functional_api/hello_world/workflow.py new file mode 100644 index 00000000..6d621d3d --- /dev/null +++ b/langgraph_plugin/functional_api/hello_world/workflow.py @@ -0,0 +1,39 @@ +"""Hello world using the LangGraph Functional API with Temporal. + +The simplest possible sample: a single task called from an entrypoint. +""" + +from datetime import timedelta + +from langgraph.func import entrypoint as lg_entrypoint +from langgraph.func import task +from temporalio import workflow +from temporalio.contrib.langgraph import entrypoint + + +@task +def process_query(query: str) -> str: + """Process a query and return a response.""" + return f"Processed: {query}" + + +@lg_entrypoint() +async def hello_entrypoint(query: str) -> dict: + """Process the query and return it in a result dict.""" + result = await process_query(query) + return {"result": result} + + +all_tasks = [process_query] + +activity_options = { + t.func.__name__: {"start_to_close_timeout": timedelta(seconds=10)} + for t in all_tasks +} + + +@workflow.defn +class HelloWorldFunctionalWorkflow: + @workflow.run + async def run(self, query: str) -> dict: + return await entrypoint("hello-world").ainvoke(query) diff --git a/langgraph_plugin/functional_api/human_in_the_loop/README.md b/langgraph_plugin/functional_api/human_in_the_loop/README.md new file mode 100644 index 00000000..1a00b411 --- /dev/null +++ b/langgraph_plugin/functional_api/human_in_the_loop/README.md @@ -0,0 +1,37 @@ +# Human-in-the-Loop Chatbot (Functional API) + +Same pattern as the Graph API version, but using `@task` and `@entrypoint` decorators for an imperative programming style. + +## What This Sample Demonstrates + +- Using `interrupt()` inside a `@task` to pause for human input +- Temporal signals and queries for asynchronous human feedback +- Resuming with `Command(resume=...)` via the v2 API +- Setting a checkpointer on the entrypoint for interrupt/resume support + +## How It Works + +1. The `generate_draft` task produces a draft response. +2. The `request_human_review` task calls `interrupt(draft)`, pausing the entrypoint. +3. The workflow stores the draft and waits for a signal. +4. After receiving feedback, the entrypoint resumes and returns the result. + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/functional_api/human_in_the_loop/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `@task` functions, `@entrypoint`, and `ChatbotFunctionalWorkflow` | +| `run_worker.py` | Registers tasks and entrypoint with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Starts workflow, polls draft via query, sends approval via signal | diff --git a/langgraph_plugin/functional_api/human_in_the_loop/__init__.py b/langgraph_plugin/functional_api/human_in_the_loop/__init__.py index e69de29b..72da02f8 100644 --- a/langgraph_plugin/functional_api/human_in_the_loop/__init__.py +++ b/langgraph_plugin/functional_api/human_in_the_loop/__init__.py @@ -0,0 +1 @@ +"""Human-in-the-loop chatbot using interrupt() and Temporal signals.""" diff --git a/langgraph_plugin/functional_api/human_in_the_loop/run_worker.py b/langgraph_plugin/functional_api/human_in_the_loop/run_worker.py index 2d59bc58..c8f84b49 100644 --- a/langgraph_plugin/functional_api/human_in_the_loop/run_worker.py +++ b/langgraph_plugin/functional_api/human_in_the_loop/run_worker.py @@ -1,6 +1,7 @@ """Worker for the human-in-the-loop chatbot (Functional API).""" import asyncio +import os from temporalio.client import Client from temporalio.contrib.langgraph import LangGraphPlugin @@ -15,7 +16,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) plugin = LangGraphPlugin( entrypoints={"chatbot": chatbot_entrypoint}, tasks=all_tasks, diff --git a/langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py b/langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py index 164bde9d..5074b937 100644 --- a/langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py +++ b/langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py @@ -1,6 +1,7 @@ """Start the human-in-the-loop chatbot workflow (Functional API).""" import asyncio +import os from temporalio.client import Client @@ -10,7 +11,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) handle = await client.start_workflow( ChatbotFunctionalWorkflow.run, diff --git a/langgraph_plugin/functional_api/react_agent/README.md b/langgraph_plugin/functional_api/react_agent/README.md new file mode 100644 index 00000000..5ff3fbe8 --- /dev/null +++ b/langgraph_plugin/functional_api/react_agent/README.md @@ -0,0 +1,44 @@ +# ReAct Agent (Functional API) + +Same agent pattern as the Graph API version, but using a `while` loop instead of conditional edges — making the control flow explicit. + +## What This Sample Demonstrates + +- The ReAct loop as a natural `while True` loop in Python +- `@task` functions for agent thinking and tool execution +- How the Functional API makes agent loops readable and extensible + +## How It Works + +1. The `agent_think` task examines the query and tool history, deciding the next action. +2. If a tool is needed, `execute_tool` runs it and the result is appended to history. +3. The loop continues until `agent_think` returns a final answer. + +```python +while True: + decision = await agent_think(query, history) + if decision["action"] == "final": + return decision["answer"] + result = await execute_tool(decision["tool_name"], decision["tool_input"]) + history.append(result) +``` + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/functional_api/react_agent/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/functional_api/react_agent/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `@task` functions (agent_think, execute_tool), `@entrypoint`, and `ReactAgentFunctionalWorkflow` | +| `run_worker.py` | Registers tasks and entrypoint with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Executes the agent workflow and prints the answer | diff --git a/langgraph_plugin/functional_api/react_agent/__init__.py b/langgraph_plugin/functional_api/react_agent/__init__.py index e69de29b..bd34ac2e 100644 --- a/langgraph_plugin/functional_api/react_agent/__init__.py +++ b/langgraph_plugin/functional_api/react_agent/__init__.py @@ -0,0 +1 @@ +"""ReAct agent with while-loop tool dispatch.""" diff --git a/langgraph_plugin/functional_api/react_agent/run_worker.py b/langgraph_plugin/functional_api/react_agent/run_worker.py index 0a4293ba..465e90ad 100644 --- a/langgraph_plugin/functional_api/react_agent/run_worker.py +++ b/langgraph_plugin/functional_api/react_agent/run_worker.py @@ -1,6 +1,7 @@ """Worker for the ReAct agent (Functional API).""" import asyncio +import os from temporalio.client import Client from temporalio.contrib.langgraph import LangGraphPlugin @@ -15,7 +16,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) plugin = LangGraphPlugin( entrypoints={"react-agent": react_agent_entrypoint}, tasks=all_tasks, diff --git a/langgraph_plugin/functional_api/react_agent/run_workflow.py b/langgraph_plugin/functional_api/react_agent/run_workflow.py index f652d165..8888cbd1 100644 --- a/langgraph_plugin/functional_api/react_agent/run_workflow.py +++ b/langgraph_plugin/functional_api/react_agent/run_workflow.py @@ -1,6 +1,7 @@ """Start the ReAct agent workflow (Functional API).""" import asyncio +import os from temporalio.client import Client @@ -10,7 +11,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) result = await client.execute_workflow( ReactAgentFunctionalWorkflow.run, diff --git a/langgraph_plugin/graph_api/__init__.py b/langgraph_plugin/graph_api/__init__.py index e69de29b..579887b6 100644 --- a/langgraph_plugin/graph_api/__init__.py +++ b/langgraph_plugin/graph_api/__init__.py @@ -0,0 +1 @@ +"""LangGraph Graph API samples using StateGraph.""" diff --git a/langgraph_plugin/graph_api/continue_as_new/README.md b/langgraph_plugin/graph_api/continue_as_new/README.md new file mode 100644 index 00000000..755a6da5 --- /dev/null +++ b/langgraph_plugin/graph_api/continue_as_new/README.md @@ -0,0 +1,37 @@ +# Continue-as-New with Caching (Graph API) + +Demonstrates Temporal's continue-as-new with LangGraph's task result caching to avoid re-executing completed graph nodes across workflow boundaries. + +## What This Sample Demonstrates + +- Using `workflow.continue_as_new()` to reset event history for long-running pipelines +- Capturing task results with `get_cache()` before continuing +- Restoring cached results with `graph(name, cache=...)` so completed nodes are skipped +- Each node executes exactly once despite multiple workflow invocations + +## How It Works + +1. A 3-stage pipeline runs: `extract` (x2) -> `transform` (+50) -> `load` (x3). +2. After the first invocation, the workflow continues-as-new with the cached results. +3. On the second and third invocations, all three nodes return cached results instantly. +4. The final result is returned: input 10 -> 20 -> 70 -> 210. + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/graph_api/continue_as_new/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/graph_api/continue_as_new/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | Pipeline node functions, `build_graph()`, `PipelineInput`, and `PipelineWorkflow` | +| `run_worker.py` | Builds graph, registers with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Executes the pipeline workflow and prints the result | diff --git a/langgraph_plugin/graph_api/continue_as_new/__init__.py b/langgraph_plugin/graph_api/continue_as_new/__init__.py index e69de29b..5b90703e 100644 --- a/langgraph_plugin/graph_api/continue_as_new/__init__.py +++ b/langgraph_plugin/graph_api/continue_as_new/__init__.py @@ -0,0 +1 @@ +"""Continue-as-new pipeline with task result caching.""" diff --git a/langgraph_plugin/graph_api/continue_as_new/run_worker.py b/langgraph_plugin/graph_api/continue_as_new/run_worker.py index 68e0003a..017472b1 100644 --- a/langgraph_plugin/graph_api/continue_as_new/run_worker.py +++ b/langgraph_plugin/graph_api/continue_as_new/run_worker.py @@ -1,6 +1,7 @@ """Worker for the continue-as-new pipeline (Graph API).""" import asyncio +import os from temporalio.client import Client from temporalio.contrib.langgraph import LangGraphPlugin @@ -13,7 +14,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) plugin = LangGraphPlugin(graphs={"pipeline": build_graph()}) worker = Worker( diff --git a/langgraph_plugin/graph_api/continue_as_new/run_workflow.py b/langgraph_plugin/graph_api/continue_as_new/run_workflow.py index 29e06cba..a52d1716 100644 --- a/langgraph_plugin/graph_api/continue_as_new/run_workflow.py +++ b/langgraph_plugin/graph_api/continue_as_new/run_workflow.py @@ -1,6 +1,7 @@ """Start the continue-as-new pipeline workflow (Graph API).""" import asyncio +import os from datetime import timedelta from temporalio.client import Client @@ -12,7 +13,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) result = await client.execute_workflow( PipelineWorkflow.run, diff --git a/langgraph_plugin/graph_api/hello_world/README.md b/langgraph_plugin/graph_api/hello_world/README.md new file mode 100644 index 00000000..ecd6fc06 --- /dev/null +++ b/langgraph_plugin/graph_api/hello_world/README.md @@ -0,0 +1,29 @@ +# Hello World (Graph API) + +The simplest possible LangGraph + Temporal sample: a single-node graph that processes a query string. + +## What This Sample Demonstrates + +- Defining a `StateGraph` with a single node +- Wrapping it with `LangGraphPlugin` so the node runs as a Temporal activity +- Invoking the graph from a Temporal workflow + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/graph_api/hello_world/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/graph_api/hello_world/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `process_query` node, `build_graph()`, and `HelloWorldWorkflow` | +| `run_worker.py` | Registers graph with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Executes the workflow and prints the result | diff --git a/langgraph_plugin/graph_api/hello_world/__init__.py b/langgraph_plugin/graph_api/hello_world/__init__.py new file mode 100644 index 00000000..166b2c69 --- /dev/null +++ b/langgraph_plugin/graph_api/hello_world/__init__.py @@ -0,0 +1 @@ +"""Minimal hello world — single-node StateGraph.""" diff --git a/langgraph_plugin/graph_api/hello_world/run_worker.py b/langgraph_plugin/graph_api/hello_world/run_worker.py new file mode 100644 index 00000000..3fcffa5a --- /dev/null +++ b/langgraph_plugin/graph_api/hello_world/run_worker.py @@ -0,0 +1,31 @@ +"""Worker for the hello world sample (Graph API).""" + +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.hello_world.workflow import ( + HelloWorldWorkflow, + build_graph, +) + + +async def main() -> None: + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) + plugin = LangGraphPlugin(graphs={"hello-world": build_graph()}) + + worker = Worker( + client, + task_queue="langgraph-hello-world", + workflows=[HelloWorldWorkflow], + plugins=[plugin], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/hello_world/run_workflow.py b/langgraph_plugin/graph_api/hello_world/run_workflow.py new file mode 100644 index 00000000..e1a02a43 --- /dev/null +++ b/langgraph_plugin/graph_api/hello_world/run_workflow.py @@ -0,0 +1,25 @@ +"""Start the hello world workflow (Graph API).""" + +import asyncio +import os + +from temporalio.client import Client + +from langgraph_plugin.graph_api.hello_world.workflow import HelloWorldWorkflow + + +async def main() -> None: + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) + + result = await client.execute_workflow( + HelloWorldWorkflow.run, + "Hello, Temporal + LangGraph!", + id="hello-world-workflow", + task_queue="langgraph-hello-world", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/hello_world/workflow.py b/langgraph_plugin/graph_api/hello_world/workflow.py new file mode 100644 index 00000000..573e4b10 --- /dev/null +++ b/langgraph_plugin/graph_api/hello_world/workflow.py @@ -0,0 +1,34 @@ +"""Hello world using the LangGraph Graph API with Temporal. + +The simplest possible sample: a single-node graph that processes a query string. +""" + +from datetime import timedelta + +from langgraph.graph import START, StateGraph +from temporalio import workflow +from temporalio.contrib.langgraph import graph + + +async def process_query(query: str) -> str: + """Process a query and return a response.""" + return f"Processed: {query}" + + +def build_graph() -> StateGraph: + """Construct a single-node graph.""" + g = StateGraph(str) + g.add_node( + "process_query", + process_query, + metadata={"start_to_close_timeout": timedelta(seconds=10)}, + ) + g.add_edge(START, "process_query") + return g + + +@workflow.defn +class HelloWorldWorkflow: + @workflow.run + async def run(self, query: str) -> str: + return await graph("hello-world").compile().ainvoke(query) diff --git a/langgraph_plugin/graph_api/human_in_the_loop/README.md b/langgraph_plugin/graph_api/human_in_the_loop/README.md new file mode 100644 index 00000000..7220f351 --- /dev/null +++ b/langgraph_plugin/graph_api/human_in_the_loop/README.md @@ -0,0 +1,38 @@ +# Human-in-the-Loop Chatbot (Graph API) + +Demonstrates using LangGraph's `interrupt()` to pause a workflow for human review, combined with Temporal signals and queries for asynchronous feedback. + +## What This Sample Demonstrates + +- Pausing a graph mid-execution with `interrupt()` to wait for human input +- Using Temporal **signals** to deliver human feedback to a running workflow +- Using Temporal **queries** to expose pending review state to external UIs +- Resuming the graph with `Command(resume=...)` after receiving input + +## How It Works + +1. The workflow starts and the `generate_draft` node produces a response. +2. The `human_review` node calls `interrupt(draft)`, pausing execution. +3. The workflow exposes the draft via a query and waits for a signal. +4. An external process (UI, CLI, etc.) queries the draft and sends approval via signal. +5. The graph resumes — `interrupt()` returns the signal value and the node completes. + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1: start the worker +uv run langgraph_plugin/graph_api/human_in_the_loop/run_worker.py + +# Terminal 2: start the workflow (polls for draft, then auto-approves) +uv run langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | Graph node functions, `build_graph()`, and `ChatbotWorkflow` definition | +| `run_worker.py` | Builds graph, registers with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Starts workflow, polls draft via query, sends approval via signal | diff --git a/langgraph_plugin/graph_api/human_in_the_loop/__init__.py b/langgraph_plugin/graph_api/human_in_the_loop/__init__.py index e69de29b..72da02f8 100644 --- a/langgraph_plugin/graph_api/human_in_the_loop/__init__.py +++ b/langgraph_plugin/graph_api/human_in_the_loop/__init__.py @@ -0,0 +1 @@ +"""Human-in-the-loop chatbot using interrupt() and Temporal signals.""" diff --git a/langgraph_plugin/graph_api/human_in_the_loop/run_worker.py b/langgraph_plugin/graph_api/human_in_the_loop/run_worker.py index 122eeef5..224caa7b 100644 --- a/langgraph_plugin/graph_api/human_in_the_loop/run_worker.py +++ b/langgraph_plugin/graph_api/human_in_the_loop/run_worker.py @@ -1,6 +1,7 @@ """Worker for the human-in-the-loop chatbot (Graph API).""" import asyncio +import os from temporalio.client import Client from temporalio.contrib.langgraph import LangGraphPlugin @@ -13,7 +14,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) plugin = LangGraphPlugin(graphs={"chatbot": build_graph()}) worker = Worker( diff --git a/langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py b/langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py index d7af5606..7abfcdcf 100644 --- a/langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py +++ b/langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py @@ -1,6 +1,7 @@ """Start the human-in-the-loop chatbot workflow (Graph API).""" import asyncio +import os from temporalio.client import Client @@ -8,7 +9,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) handle = await client.start_workflow( ChatbotWorkflow.run, diff --git a/langgraph_plugin/graph_api/react_agent/README.md b/langgraph_plugin/graph_api/react_agent/README.md new file mode 100644 index 00000000..7d43c940 --- /dev/null +++ b/langgraph_plugin/graph_api/react_agent/README.md @@ -0,0 +1,42 @@ +# ReAct Agent (Graph API) + +Demonstrates the most common LangGraph pattern: a tool-calling agent that loops between deciding and acting, using conditional edges for routing. + +## What This Sample Demonstrates + +- Defining a `StateGraph` with an agent->tools loop +- Using `add_conditional_edges` for conditional routing (call tool or finish) +- Accumulating conversation history with `Annotated[list, operator.add]` +- The full ReAct cycle: think -> act -> observe -> repeat + +## How It Works + +1. The `agent` node examines the conversation history and decides the next action. +2. If a tool is needed, `should_continue` routes to the `tools` node. +3. The `tools` node executes the tool and appends the result to history. +4. Control returns to `agent`, which decides again — loop or finish. +5. When the agent has enough information, `should_continue` routes to `END`. + +``` +START -> agent -> tools -> agent -> tools -> agent -> END +``` + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +# Terminal 1 +uv run langgraph_plugin/graph_api/react_agent/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/graph_api/react_agent/run_workflow.py +``` + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `AgentState`, node functions, `should_continue` router, `build_graph()`, and `ReactAgentWorkflow` | +| `run_worker.py` | Builds graph, registers with `LangGraphPlugin`, starts worker | +| `run_workflow.py` | Executes the agent workflow and prints the answer | diff --git a/langgraph_plugin/graph_api/react_agent/__init__.py b/langgraph_plugin/graph_api/react_agent/__init__.py index e69de29b..64c24c36 100644 --- a/langgraph_plugin/graph_api/react_agent/__init__.py +++ b/langgraph_plugin/graph_api/react_agent/__init__.py @@ -0,0 +1 @@ +"""ReAct agent with conditional edges and tool-calling loop.""" diff --git a/langgraph_plugin/graph_api/react_agent/run_worker.py b/langgraph_plugin/graph_api/react_agent/run_worker.py index 29bbc8b9..9c44df65 100644 --- a/langgraph_plugin/graph_api/react_agent/run_worker.py +++ b/langgraph_plugin/graph_api/react_agent/run_worker.py @@ -1,6 +1,7 @@ """Worker for the ReAct agent (Graph API).""" import asyncio +import os from temporalio.client import Client from temporalio.contrib.langgraph import LangGraphPlugin @@ -13,7 +14,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) plugin = LangGraphPlugin(graphs={"react-agent": build_graph()}) worker = Worker( diff --git a/langgraph_plugin/graph_api/react_agent/run_workflow.py b/langgraph_plugin/graph_api/react_agent/run_workflow.py index d188407a..d4649f1e 100644 --- a/langgraph_plugin/graph_api/react_agent/run_workflow.py +++ b/langgraph_plugin/graph_api/react_agent/run_workflow.py @@ -1,6 +1,7 @@ """Start the ReAct agent workflow (Graph API).""" import asyncio +import os from temporalio.client import Client @@ -8,7 +9,7 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + client = await Client.connect(os.environ.get("TEMPORAL_ADDRESS", "localhost:7233")) result = await client.execute_workflow( ReactAgentWorkflow.run, diff --git a/tests/langgraph_plugin/__init__.py b/tests/langgraph_plugin/__init__.py new file mode 100644 index 00000000..133a43fd --- /dev/null +++ b/tests/langgraph_plugin/__init__.py @@ -0,0 +1 @@ +"""LangGraph plugin sample tests.""" diff --git a/tests/langgraph_plugin/continue_as_new_test.py b/tests/langgraph_plugin/continue_as_new_test.py new file mode 100644 index 00000000..6171e51a --- /dev/null +++ b/tests/langgraph_plugin/continue_as_new_test.py @@ -0,0 +1,34 @@ +import uuid +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.continue_as_new.workflow import ( + PipelineInput, + PipelineWorkflow, + build_graph, +) + + +async def test_continue_as_new_graph_api(client: Client) -> None: + """Input 10: 10*2=20 -> 20+50=70 -> 70*3=210.""" + task_queue = f"continue-as-new-test-{uuid.uuid4()}" + plugin = LangGraphPlugin(graphs={"pipeline": build_graph()}) + + async with Worker( + client, + task_queue=task_queue, + workflows=[PipelineWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + PipelineWorkflow.run, + PipelineInput(data=10), + id=f"continue-as-new-{uuid.uuid4()}", + task_queue=task_queue, + execution_timeout=timedelta(seconds=60), + ) + + assert result == 210 diff --git a/tests/langgraph_plugin/functional_continue_as_new_test.py b/tests/langgraph_plugin/functional_continue_as_new_test.py new file mode 100644 index 00000000..0ee88068 --- /dev/null +++ b/tests/langgraph_plugin/functional_continue_as_new_test.py @@ -0,0 +1,40 @@ +import uuid +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.continue_as_new.workflow import ( + PipelineFunctionalWorkflow, + PipelineInput, + activity_options, + all_tasks, + pipeline_entrypoint, +) + + +async def test_functional_continue_as_new(client: Client) -> None: + """Input 10: 10*2=20 -> 20+50=70 -> 70*3=210.""" + task_queue = f"functional-continue-test-{uuid.uuid4()}" + plugin = LangGraphPlugin( + entrypoints={"pipeline": pipeline_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + async with Worker( + client, + task_queue=task_queue, + workflows=[PipelineFunctionalWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + PipelineFunctionalWorkflow.run, + PipelineInput(data=10), + id=f"functional-continue-{uuid.uuid4()}", + task_queue=task_queue, + execution_timeout=timedelta(seconds=60), + ) + + assert result == {"result": 210} diff --git a/tests/langgraph_plugin/functional_control_flow_test.py b/tests/langgraph_plugin/functional_control_flow_test.py new file mode 100644 index 00000000..3048ecf1 --- /dev/null +++ b/tests/langgraph_plugin/functional_control_flow_test.py @@ -0,0 +1,52 @@ +import uuid + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.control_flow.workflow import ( + ControlFlowWorkflow, + activity_options, + all_tasks, + control_flow_pipeline, +) + + +async def test_functional_control_flow(client: Client) -> None: + task_queue = f"functional-control-flow-test-{uuid.uuid4()}" + plugin = LangGraphPlugin( + entrypoints={"control_flow": control_flow_pipeline}, + tasks=all_tasks, + activity_options=activity_options, + ) + + items = [ + "Fix login bug", + "URGENT: Production outage", + "Update README", + "INVALID:", + "Urgent: Security patch", + ] + + async with Worker( + client, + task_queue=task_queue, + workflows=[ControlFlowWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + ControlFlowWorkflow.run, + items, + id=f"functional-control-flow-{uuid.uuid4()}", + task_queue=task_queue, + ) + + # "INVALID:" should be filtered out + assert result["total"] == 4 + # Check urgent vs normal routing + urgent = [r for r in result["results"] if r.startswith("[PRIORITY]")] + normal = [r for r in result["results"] if r.startswith("[STANDARD]")] + assert len(urgent) == 2 + assert len(normal) == 2 + assert "2 urgent" in result["summary"] + assert "2 normal" in result["summary"] diff --git a/tests/langgraph_plugin/functional_hello_world_test.py b/tests/langgraph_plugin/functional_hello_world_test.py new file mode 100644 index 00000000..e0d38a51 --- /dev/null +++ b/tests/langgraph_plugin/functional_hello_world_test.py @@ -0,0 +1,37 @@ +import uuid +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.hello_world.workflow import ( + HelloWorldFunctionalWorkflow, + activity_options, + all_tasks, + hello_entrypoint, +) + + +async def test_functional_hello_world(client: Client) -> None: + task_queue = f"functional-hello-test-{uuid.uuid4()}" + plugin = LangGraphPlugin( + entrypoints={"hello-world": hello_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + async with Worker( + client, + task_queue=task_queue, + workflows=[HelloWorldFunctionalWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + HelloWorldFunctionalWorkflow.run, + "test query", + id=f"functional-hello-{uuid.uuid4()}", + task_queue=task_queue, + ) + + assert result == {"result": "Processed: test query"} diff --git a/tests/langgraph_plugin/functional_human_in_the_loop_test.py b/tests/langgraph_plugin/functional_human_in_the_loop_test.py new file mode 100644 index 00000000..36393e17 --- /dev/null +++ b/tests/langgraph_plugin/functional_human_in_the_loop_test.py @@ -0,0 +1,51 @@ +import asyncio +import uuid + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.human_in_the_loop.workflow import ( + ChatbotFunctionalWorkflow, + activity_options, + all_tasks, + chatbot_entrypoint, +) + + +async def test_functional_human_in_the_loop_approve(client: Client) -> None: + task_queue = f"functional-hitl-test-{uuid.uuid4()}" + plugin = LangGraphPlugin( + entrypoints={"chatbot": chatbot_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + async with Worker( + client, + task_queue=task_queue, + workflows=[ChatbotFunctionalWorkflow], + plugins=[plugin], + ): + handle = await client.start_workflow( + ChatbotFunctionalWorkflow.run, + "test message", + id=f"functional-hitl-{uuid.uuid4()}", + task_queue=task_queue, + ) + + # Poll for draft to be ready + draft = None + for _ in range(40): + await asyncio.sleep(0.25) + draft = await handle.query(ChatbotFunctionalWorkflow.get_draft) + if draft is not None: + break + assert draft is not None + assert "test message" in draft + + # Approve + await handle.signal(ChatbotFunctionalWorkflow.provide_feedback, "approve") + result = await handle.result() + + assert result["response"] == draft diff --git a/tests/langgraph_plugin/functional_react_agent_test.py b/tests/langgraph_plugin/functional_react_agent_test.py new file mode 100644 index 00000000..3954ffb8 --- /dev/null +++ b/tests/langgraph_plugin/functional_react_agent_test.py @@ -0,0 +1,37 @@ +import uuid + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.react_agent.workflow import ( + ReactAgentFunctionalWorkflow, + activity_options, + all_tasks, + react_agent_entrypoint, +) + + +async def test_functional_react_agent(client: Client) -> None: + task_queue = f"functional-react-agent-test-{uuid.uuid4()}" + plugin = LangGraphPlugin( + entrypoints={"react-agent": react_agent_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + + async with Worker( + client, + task_queue=task_queue, + workflows=[ReactAgentFunctionalWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + ReactAgentFunctionalWorkflow.run, + "Tell me about San Francisco", + id=f"functional-react-agent-{uuid.uuid4()}", + task_queue=task_queue, + ) + + assert "San Francisco" in result["answer"] + assert result["steps"] == 2 # two tool calls diff --git a/tests/langgraph_plugin/hello_world_test.py b/tests/langgraph_plugin/hello_world_test.py new file mode 100644 index 00000000..90eb901e --- /dev/null +++ b/tests/langgraph_plugin/hello_world_test.py @@ -0,0 +1,51 @@ +import uuid +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.hello_world.workflow import ( + HelloWorldWorkflow, + build_graph, +) + + +async def test_hello_world_graph_api(client: Client) -> None: + task_queue = f"hello-world-test-{uuid.uuid4()}" + plugin = LangGraphPlugin(graphs={"hello-world": build_graph()}) + + async with Worker( + client, + task_queue=task_queue, + workflows=[HelloWorldWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + HelloWorldWorkflow.run, + "test query", + id=f"hello-world-{uuid.uuid4()}", + task_queue=task_queue, + ) + + assert result == "Processed: test query" + + +async def test_hello_world_empty_string(client: Client) -> None: + task_queue = f"hello-world-empty-test-{uuid.uuid4()}" + plugin = LangGraphPlugin(graphs={"hello-world": build_graph()}) + + async with Worker( + client, + task_queue=task_queue, + workflows=[HelloWorldWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + HelloWorldWorkflow.run, + "", + id=f"hello-world-empty-{uuid.uuid4()}", + task_queue=task_queue, + ) + + assert result == "Processed: " diff --git a/tests/langgraph_plugin/human_in_the_loop_test.py b/tests/langgraph_plugin/human_in_the_loop_test.py new file mode 100644 index 00000000..620bdc5b --- /dev/null +++ b/tests/langgraph_plugin/human_in_the_loop_test.py @@ -0,0 +1,79 @@ +import asyncio +import uuid + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.human_in_the_loop.workflow import ( + ChatbotWorkflow, + build_graph, +) + + +async def test_human_in_the_loop_approve(client: Client) -> None: + task_queue = f"hitl-test-{uuid.uuid4()}" + plugin = LangGraphPlugin(graphs={"chatbot": build_graph()}) + + async with Worker( + client, + task_queue=task_queue, + workflows=[ChatbotWorkflow], + plugins=[plugin], + ): + handle = await client.start_workflow( + ChatbotWorkflow.run, + "test message", + id=f"hitl-{uuid.uuid4()}", + task_queue=task_queue, + ) + + # Poll for draft to be ready + draft = None + for _ in range(40): + await asyncio.sleep(0.25) + draft = await handle.query(ChatbotWorkflow.get_draft) + if draft is not None: + break + assert draft is not None + assert "test message" in draft + + # Approve + await handle.signal(ChatbotWorkflow.provide_feedback, "approve") + result = await handle.result() + + assert result == draft # approved draft returned as-is + + +async def test_human_in_the_loop_revise(client: Client) -> None: + task_queue = f"hitl-revise-test-{uuid.uuid4()}" + plugin = LangGraphPlugin(graphs={"chatbot": build_graph()}) + + async with Worker( + client, + task_queue=task_queue, + workflows=[ChatbotWorkflow], + plugins=[plugin], + ): + handle = await client.start_workflow( + ChatbotWorkflow.run, + "test message", + id=f"hitl-revise-{uuid.uuid4()}", + task_queue=task_queue, + ) + + # Poll for draft + draft = None + for _ in range(40): + await asyncio.sleep(0.25) + draft = await handle.query(ChatbotWorkflow.get_draft) + if draft is not None: + break + assert draft is not None + + # Send revision feedback + await handle.signal(ChatbotWorkflow.provide_feedback, "please be more concise") + result = await handle.result() + + assert "[Revised]" in result + assert "please be more concise" in result diff --git a/tests/langgraph_plugin/react_agent_test.py b/tests/langgraph_plugin/react_agent_test.py new file mode 100644 index 00000000..bfeddc57 --- /dev/null +++ b/tests/langgraph_plugin/react_agent_test.py @@ -0,0 +1,32 @@ +import uuid + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.react_agent.workflow import ( + ReactAgentWorkflow, + build_graph, +) + + +async def test_react_agent_graph_api(client: Client) -> None: + task_queue = f"react-agent-test-{uuid.uuid4()}" + plugin = LangGraphPlugin(graphs={"react-agent": build_graph()}) + + async with Worker( + client, + task_queue=task_queue, + workflows=[ReactAgentWorkflow], + plugins=[plugin], + ): + result = await client.execute_workflow( + ReactAgentWorkflow.run, + "Tell me about San Francisco", + id=f"react-agent-{uuid.uuid4()}", + task_queue=task_queue, + ) + + assert "San Francisco" in result + assert "72" in result or "weather" in result.lower() + assert "870,000" in result or "population" in result.lower() diff --git a/uv.lock b/uv.lock index dd39daa7..4bbd6ba5 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -176,7 +176,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -190,7 +190,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -199,7 +199,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] @@ -256,7 +256,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -317,7 +317,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -329,7 +329,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, @@ -338,7 +338,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] @@ -361,29 +361,16 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, ] -[[package]] -name = "dataclasses-json" -version = "0.6.7" -source = { registry = "https://pypi.org/simple/" } -dependencies = [ - { name = "marshmallow" }, - { name = "typing-inspect" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227, upload-time = "2024-06-09T16:20:19.103Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, -] - [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, @@ -392,7 +379,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -404,7 +391,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -418,7 +405,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -427,7 +414,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -521,7 +508,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8b/02/0835e6ab9cfc03916fe3f78c0956cfcdb6ff2669ffa6651065d5ebf7fc98/fsspec-2025.7.0.tar.gz", hash = "sha256:786120687ffa54b8283d942929540d8bc5ccfa820deb555a2b5d0ed2b737bf58", size = 304432, upload-time = "2025-07-15T16:05:21.19Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl", hash = "sha256:8b012e39f63c7d5f10474de957f3ab793b47b45ae7d39f2fb735f8bbe25c0e21", size = 199597, upload-time = "2025-07-15T16:05:19.529Z" }, @@ -530,7 +517,7 @@ wheels = [ [[package]] name = "gevent" version = "25.9.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -582,7 +569,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -594,7 +581,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -645,7 +632,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, ] @@ -657,7 +644,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.76.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -718,7 +705,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, @@ -727,7 +714,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -742,7 +729,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -755,7 +742,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -791,7 +778,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -806,7 +793,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6e/fa/66bd985dd0b7c109a3bcb89272ee0bfb7e2b4d06309ad7b38ff866734b2a/httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e", size = 12998, upload-time = "2025-06-24T13:21:05.71Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/25/0a/6269e3473b09aed2dab8aa1a600c70f31f00ae1349bee30658f7e358a159/httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37", size = 8054, upload-time = "2025-06-24T13:21:04.772Z" }, @@ -815,7 +802,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -834,7 +821,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, @@ -843,7 +830,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] @@ -855,7 +842,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, @@ -864,7 +851,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] @@ -876,7 +863,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ee/9d/ae7ddb4b8ab3fb1b51faf4deb36cb48a4fbbd7cb36bad6a5fca4741306f7/jiter-0.10.0.tar.gz", hash = "sha256:07a7142c38aacc85194391108dc91b5b57093c978a9932bd86a36862759d9500", size = 162759, upload-time = "2025-05-18T19:04:59.73Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -948,7 +935,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -957,7 +944,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpointer" }, ] @@ -969,7 +956,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -978,7 +965,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -993,7 +980,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] @@ -1004,112 +991,131 @@ wheels = [ [[package]] name = "langchain" -version = "0.1.20" -source = { registry = "https://pypi.org/simple/" } +version = "1.2.15" +source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "dataclasses-json" }, - { name = "langchain-community" }, { name = "langchain-core" }, - { name = "langchain-text-splitters" }, + { name = "langgraph" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/3f/888a7099d2bd2917f8b0c3ffc7e347f1e664cf64267820b0b923c4f339fc/langchain-1.2.15.tar.gz", hash = "sha256:1717b6719daefae90b2728314a5e2a117ff916291e2862595b6c3d6fba33d652", size = 574732, upload-time = "2026-04-03T14:26:03.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/e8/a3b8cb0005553f6a876865073c81ef93bd7c5b18381bcb9ba4013af96ebc/langchain-1.2.15-py3-none-any.whl", hash = "sha256:e349db349cb3e9550c4044077cf90a1717691756cc236438404b23500e615874", size = 112714, upload-time = "2026-04-03T14:26:02.557Z" }, +] + +[[package]] +name = "langchain-core" +version = "1.2.29" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpatch" }, { name = "langsmith" }, - { name = "numpy" }, + { name = "packaging" }, { name = "pydantic" }, { name = "pyyaml" }, - { name = "requests" }, - { name = "sqlalchemy" }, { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/88/94/8d917da143b30c3088be9f51719634827ab19207cb290a51de3859747783/langchain-0.1.20.tar.gz", hash = "sha256:f35c95eed8c8375e02dce95a34f2fd4856a4c98269d6dc34547a23dba5beab7e", size = 420688, upload-time = "2024-05-10T21:59:40.736Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/d8/7bdf30e4bfc5175609201806e399506a0a78a48e14367dc8b776a9b4c89c/langchain_core-1.2.29.tar.gz", hash = "sha256:cfb89c92bca81ad083eafcdfe6ec40f9803c9abf7dd166d0f8a8de1d2de03ca6", size = 846121, upload-time = "2026-04-14T20:44:58.117Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl", hash = "sha256:09991999fbd6c3421a12db3c7d1f52d55601fc41d9b2a3ef51aab2e0e9c38da9", size = 1014619, upload-time = "2024-05-10T21:59:36.417Z" }, + { url = "https://files.pythonhosted.org/packages/72/37/fed31f80436b1d7bb222f1f2345300a77a88215416acf8d1cb7c8fda7388/langchain_core-1.2.29-py3-none-any.whl", hash = "sha256:11f02e57ee1c24e6e0e6577acbd35df77b205d4692a3df956b03b5389cbe44a0", size = 508733, upload-time = "2026-04-14T20:44:56.712Z" }, ] [[package]] -name = "langchain-community" -version = "0.0.38" -source = { registry = "https://pypi.org/simple/" } +name = "langchain-openai" +version = "1.1.9" +source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp" }, - { name = "dataclasses-json" }, { name = "langchain-core" }, - { name = "langsmith" }, - { name = "numpy" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "sqlalchemy" }, - { name = "tenacity" }, + { name = "openai" }, + { name = "tiktoken" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/b7/c20502452183d27b8c0466febb227fae3213f77e9a13683de685e7227f39/langchain_community-0.0.38.tar.gz", hash = "sha256:127fc4b75bc67b62fe827c66c02e715a730fef8fe69bd2023d466bab06b5810d", size = 1373468, upload-time = "2024-05-08T22:44:26.295Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/ae/1dbeb49ab8f098f78ec52e21627e705e5d7c684dc8826c2c34cc2746233a/langchain_openai-1.1.9.tar.gz", hash = "sha256:fdee25dcf4b0685d8e2f59856f4d5405431ef9e04ab53afe19e2e8360fed8234", size = 1004828, upload-time = "2026-02-10T21:03:21.615Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl", hash = "sha256:ecb48660a70a08c90229be46b0cc5f6bc9f38f2833ee44c57dfab9bf3a2c121a", size = 2028164, upload-time = "2024-05-08T22:44:23.434Z" }, + { url = "https://files.pythonhosted.org/packages/52/a1/8a20d19f69d022c10d34afa42d972cc50f971b880d0eb4a828cf3dd824a8/langchain_openai-1.1.9-py3-none-any.whl", hash = "sha256:ca2482b136c45fb67c0db84a9817de675e0eb8fb2203a33914c1b7a96f273940", size = 85769, upload-time = "2026-02-10T21:03:20.333Z" }, ] [[package]] -name = "langchain-core" -version = "0.1.53" -source = { registry = "https://pypi.org/simple/" } +name = "langgraph" +version = "1.1.6" +source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jsonpatch" }, - { name = "langsmith" }, - { name = "packaging" }, + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, + { name = "langgraph-prebuilt" }, + { name = "langgraph-sdk" }, { name = "pydantic" }, - { name = "pyyaml" }, - { name = "tenacity" }, + { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/65/3aaff91481b9d629a31630a40000d403bff24b3c62d9abc87dc998298cce/langchain_core-0.1.53.tar.gz", hash = "sha256:df3773a553b5335eb645827b99a61a7018cea4b11dc45efa2613fde156441cec", size = 236665, upload-time = "2024-11-02T00:27:25.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/e5/d3f72ead3c7f15769d5a9c07e373628f1fbaf6cbe7735694d7085859acf6/langgraph-1.1.6.tar.gz", hash = "sha256:1783f764b08a607e9f288dbcf6da61caeb0dd40b337e5c9fb8b412341fbc0b60", size = 549634, upload-time = "2026-04-03T19:01:32.561Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl", hash = "sha256:02a88a21e3bd294441b5b741625fa4b53b1c684fd58ba6e5d9028e53cbe8542f", size = 303059, upload-time = "2024-11-02T00:27:23.144Z" }, + { url = "https://files.pythonhosted.org/packages/71/e6/b36ecdb3ff4ba9a290708d514bae89ebbe2f554b6abbe4642acf3fddbe51/langgraph-1.1.6-py3-none-any.whl", hash = "sha256:fdbf5f54fa5a5a4c4b09b7b5e537f1b2fa283d2f0f610d3457ddeecb479458b9", size = 169755, upload-time = "2026-04-03T19:01:30.686Z" }, ] [[package]] -name = "langchain-openai" -version = "0.0.6" -source = { registry = "https://pypi.org/simple/" } +name = "langgraph-checkpoint" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, - { name = "numpy" }, - { name = "openai" }, - { name = "tiktoken" }, + { name = "ormsgpack" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/bd/2963a5b9f7dcf5759144bbe590984730daccfd8ced01d9de5cbf23072ac5/langchain_openai-0.0.6.tar.gz", hash = "sha256:f5c4ebe46f2c8635c8f0c26cc8df27700aacafea025410e418d5a080039974dd", size = 22653, upload-time = "2024-02-13T21:20:07.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/44/a8df45d1e8b4637e29789fa8bae1db022c953cc7ac80093cfc52e923547e/langgraph_checkpoint-4.0.1.tar.gz", hash = "sha256:b433123735df11ade28829e40ce25b9be614930cd50245ff2af60629234befd9", size = 158135, upload-time = "2026-02-27T21:06:16.092Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/48/84e1840c25592bb76deea48d187d9fc8f864c9c82ddf3f084da4c9b8a15b/langchain_openai-0.0.6-py3-none-any.whl", hash = "sha256:2ef040e4447a26a9d3bd45dfac9cefa00797ea58555a3d91ab4f88699eb3a005", size = 29200, upload-time = "2024-02-13T21:20:04.664Z" }, + { url = "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl", hash = "sha256:e3adcd7a0e0166f3b48b8cf508ce0ea366e7420b5a73aa81289888727769b034", size = 50453, upload-time = "2026-02-27T21:06:14.293Z" }, ] [[package]] -name = "langchain-text-splitters" -version = "0.0.2" -source = { registry = "https://pypi.org/simple/" } +name = "langgraph-prebuilt" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e8/fa/88d65b0f696d8d4f37037f1418f89bc1078cd74d20054623bb7fffcecaf1/langchain_text_splitters-0.0.2.tar.gz", hash = "sha256:ac8927dc0ba08eba702f6961c9ed7df7cead8de19a9f7101ab2b5ea34201b3c1", size = 18638, upload-time = "2024-05-16T03:16:36.815Z" } +sdist = { url = "https://files.pythonhosted.org/packages/99/4c/06dac899f4945bedb0c3a1583c19484c2cc894114ea30d9a538dd270086e/langgraph_prebuilt-1.0.9.tar.gz", hash = "sha256:93de7512e9caade4b77ead92428f6215c521fdb71b8ffda8cd55f0ad814e64de", size = 165850, upload-time = "2026-04-03T14:06:37.721Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl", hash = "sha256:13887f32705862c1e1454213cb7834a63aae57c26fcd80346703a1d09c46168d", size = 23539, upload-time = "2024-05-16T03:16:35.727Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a2/8368ac187b75e7f9d938ca075d34f116683f5cfc48d924029ee79aea147b/langgraph_prebuilt-1.0.9-py3-none-any.whl", hash = "sha256:776c8e3154a5aef5ad0e5bf3f263f2dcaab3983786cc20014b7f955d99d2d1b2", size = 35958, upload-time = "2026-04-03T14:06:36.58Z" }, +] + +[[package]] +name = "langgraph-sdk" +version = "0.3.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/ec/477fa8b408f948b145d90fd935c0a9f37945fa5ec1dfabfc71e7cafba6d8/langgraph_sdk-0.3.6.tar.gz", hash = "sha256:7650f607f89c1586db5bee391b1a8754cbe1fc83b721ff2f1450f8906e790bd7", size = 182666, upload-time = "2026-02-14T19:46:03.752Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/61/12508e12652edd1874327271a5a8834c728a605f53a1a1c945f13ab69664/langgraph_sdk-0.3.6-py3-none-any.whl", hash = "sha256:7df2fd552ad7262d0baf8e1f849dce1d62186e76dcdd36db9dc5bdfa5c3fc20f", size = 88277, upload-time = "2026-02-14T19:46:02.48Z" }, ] [[package]] name = "langsmith" -version = "0.1.147" -source = { registry = "https://pypi.org/simple/" } +version = "0.7.31" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, + { name = "packaging" }, { name = "pydantic" }, { name = "requests" }, { name = "requests-toolbelt" }, + { name = "uuid-utils" }, + { name = "xxhash" }, + { name = "zstandard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6c/56/201dd94d492ae47c1bf9b50cacc1985113dc2288d8f15857e1f4a6818376/langsmith-0.1.147.tar.gz", hash = "sha256:2e933220318a4e73034657103b3b1a3a6109cc5db3566a7e8e03be8d6d7def7a", size = 300453, upload-time = "2024-11-27T17:32:41.297Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/11/696019490992db5c87774dc20515529ef42a01e1d770fb754ed6d9b12fb0/langsmith-0.7.31.tar.gz", hash = "sha256:331ee4f7c26bb5be4022b9859b7d7b122cbf8c9d01d9f530114c1914b0349ffb", size = 1178480, upload-time = "2026-04-14T17:55:41.242Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15", size = 311812, upload-time = "2024-11-27T17:32:39.569Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a1/a013cf458c301cda86a213dd153ce0a01c93f1ab5833f951e6a44c9763ce/langsmith-0.7.31-py3-none-any.whl", hash = "sha256:0291d49203f6e80dda011af1afda61eb0595a4d697adb684590a8805e1d61fb6", size = 373276, upload-time = "2026-04-14T17:55:39.677Z" }, ] [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1131,7 +1137,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] @@ -1143,7 +1149,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1198,22 +1204,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, ] -[[package]] -name = "marshmallow" -version = "3.26.1" -source = { registry = "https://pypi.org/simple/" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/5e53d26b42ab75491cda89b871dab9e97c840bf12c63ec58a1919710cd06/marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6", size = 221825, upload-time = "2025-02-03T15:32:25.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/75/51952c7b2d3873b44a0028b1bd26a25078c18f92f256608e8d1dc61b39fd/marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c", size = 50878, upload-time = "2025-02-03T15:32:22.295Z" }, -] - [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1235,7 +1229,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, @@ -1244,7 +1238,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1346,7 +1340,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1385,7 +1379,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, @@ -1393,20 +1387,20 @@ wheels = [ [[package]] name = "nexus-rpc" -version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/f2/d54f5c03d8f4672ccc0875787a385f53dcb61f98a8ae594b5620e85b9cb3/nexus_rpc-1.3.0.tar.gz", hash = "sha256:e56d3b57b60d707ce7a72f83f23f106b86eca1043aa658e44582ab5ff30ab9ad", size = 75650, upload-time = "2025-12-08T22:59:13.002Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/d5/cd1ffb202b76ebc1b33c1332a3416e55a39929006982adc2b1eb069aaa9b/nexus_rpc-1.4.0.tar.gz", hash = "sha256:3b8b373d4865671789cc43623e3dc0bcbf192562e40e13727e17f1c149050fba", size = 82367, upload-time = "2026-02-25T22:01:34.053Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/74/0afd841de3199c148146c1d43b4bfb5605b2f1dc4c9a9087fe395091ea5a/nexus_rpc-1.3.0-py3-none-any.whl", hash = "sha256:aee0707b4861b22d8124ecb3f27d62dafbe8777dc50c66c91e49c006f971b92d", size = 28873, upload-time = "2025-12-08T22:59:12.024Z" }, + { url = "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl", hash = "sha256:14c953d3519113f8ccec533a9efdb6b10c28afef75d11cdd6d422640c40b3a49", size = 29645, upload-time = "2026-02-25T22:01:33.122Z" }, ] [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1415,7 +1409,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1446,8 +1440,8 @@ wheels = [ [[package]] name = "openai" -version = "1.108.1" -source = { registry = "https://pypi.org/simple/" } +version = "1.109.1" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "distro" }, @@ -1458,15 +1452,15 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/7a/3f2fbdf82a22d48405c1872f7c3176a705eee80ff2d2715d29472089171f/openai-1.108.1.tar.gz", hash = "sha256:6648468c1aec4eacfa554001e933a9fa075f57bacfc27588c2e34456cee9fef9", size = 563735, upload-time = "2025-09-19T16:52:20.399Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133, upload-time = "2025-09-24T13:00:53.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/87/6ad18ce0e7b910e3706480451df48ff9e0af3b55e5db565adafd68a0706a/openai-1.108.1-py3-none-any.whl", hash = "sha256:952fc027e300b2ac23be92b064eac136a2bc58274cec16f5d2906c361340d59b", size = 948394, upload-time = "2025-09-19T16:52:18.369Z" }, + { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627, upload-time = "2025-09-24T13:00:50.754Z" }, ] [[package]] name = "openai-agents" version = "0.3.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "griffe" }, { name = "mcp" }, @@ -1489,7 +1483,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1502,7 +1496,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1514,7 +1508,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1532,7 +1526,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -1544,7 +1538,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1558,7 +1552,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1571,7 +1565,7 @@ wheels = [ [[package]] name = "orjson" version = "3.11.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870, upload-time = "2025-10-24T15:48:28.908Z" }, @@ -1649,10 +1643,66 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1a/bf/def5e25d4d8bfce296a9a7c8248109bf58622c21618b590678f945a2c59c/orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d", size = 126151, upload-time = "2025-10-24T15:50:15.878Z" }, ] +[[package]] +name = "ormsgpack" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/0c/f1761e21486942ab9bb6feaebc610fa074f7c5e496e6962dea5873348077/ormsgpack-1.12.2.tar.gz", hash = "sha256:944a2233640273bee67521795a73cf1e959538e0dfb7ac635505010455e53b33", size = 39031, upload-time = "2026-01-18T20:55:28.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/fa/a91f70829ebccf6387c4946e0a1a109f6ba0d6a28d65f628bedfad94b890/ormsgpack-1.12.2-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c1429217f8f4d7fcb053523bbbac6bed5e981af0b85ba616e6df7cce53c19657", size = 378262, upload-time = "2026-01-18T20:55:22.284Z" }, + { url = "https://files.pythonhosted.org/packages/5f/62/3698a9a0c487252b5c6a91926e5654e79e665708ea61f67a8bdeceb022bf/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f13034dc6c84a6280c6c33db7ac420253852ea233fc3ee27c8875f8dd651163", size = 203034, upload-time = "2026-01-18T20:55:53.324Z" }, + { url = "https://files.pythonhosted.org/packages/66/3a/f716f64edc4aec2744e817660b317e2f9bb8de372338a95a96198efa1ac1/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:59f5da97000c12bc2d50e988bdc8576b21f6ab4e608489879d35b2c07a8ab51a", size = 210538, upload-time = "2026-01-18T20:55:20.097Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/a436be9ce27d693d4e19fa94900028067133779f09fc45776db3f689c822/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e4459c3f27066beadb2b81ea48a076a417aafffff7df1d3c11c519190ed44f2", size = 212401, upload-time = "2026-01-18T20:55:46.447Z" }, + { url = "https://files.pythonhosted.org/packages/10/c5/cde98300fd33fee84ca71de4751b19aeeca675f0cf3c0ec4b043f40f3b76/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a1c460655d7288407ffa09065e322a7231997c0d62ce914bf3a96ad2dc6dedd", size = 387080, upload-time = "2026-01-18T20:56:00.884Z" }, + { url = "https://files.pythonhosted.org/packages/6a/31/30bf445ef827546747c10889dd254b3d84f92b591300efe4979d792f4c41/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:458e4568be13d311ef7d8877275e7ccbe06c0e01b39baaac874caaa0f46d826c", size = 482346, upload-time = "2026-01-18T20:55:39.831Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f5/e1745ddf4fa246c921b5ca253636c4c700ff768d78032f79171289159f6e/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8cde5eaa6c6cbc8622db71e4a23de56828e3d876aeb6460ffbcb5b8aff91093b", size = 425178, upload-time = "2026-01-18T20:55:27.106Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a2/e6532ed7716aed03dede8df2d0d0d4150710c2122647d94b474147ccd891/ormsgpack-1.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:dc7a33be14c347893edbb1ceda89afbf14c467d593a5ee92c11de4f1666b4d4f", size = 117183, upload-time = "2026-01-18T20:55:55.52Z" }, + { url = "https://files.pythonhosted.org/packages/4b/08/8b68f24b18e69d92238aa8f258218e6dfeacf4381d9d07ab8df303f524a9/ormsgpack-1.12.2-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bd5f4bf04c37888e864f08e740c5a573c4017f6fd6e99fa944c5c935fabf2dd9", size = 378266, upload-time = "2026-01-18T20:55:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/29fc13044ecb7c153523ae0a1972269fcd613650d1fa1a9cec1044c6b666/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d5b28b3570e9fed9a5a76528fc7230c3c76333bc214798958e58e9b79cc18a", size = 203035, upload-time = "2026-01-18T20:55:30.59Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c2/00169fb25dd8f9213f5e8a549dfb73e4d592009ebc85fbbcd3e1dcac575b/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3708693412c28f3538fb5a65da93787b6bbab3484f6bc6e935bfb77a62400ae5", size = 210539, upload-time = "2026-01-18T20:55:48.569Z" }, + { url = "https://files.pythonhosted.org/packages/1b/33/543627f323ff3c73091f51d6a20db28a1a33531af30873ea90c5ac95a9b5/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43013a3f3e2e902e1d05e72c0f1aeb5bedbb8e09240b51e26792a3c89267e181", size = 212401, upload-time = "2026-01-18T20:56:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5d/f70e2c3da414f46186659d24745483757bcc9adccb481a6eb93e2b729301/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7c8b1667a72cbba74f0ae7ecf3105a5e01304620ed14528b2cb4320679d2869b", size = 387082, upload-time = "2026-01-18T20:56:12.047Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d6/06e8dc920c7903e051f30934d874d4afccc9bb1c09dcaf0bc03a7de4b343/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6961442140193e517303d0b5d7bc2e20e69a879c2d774316125350c4a76b92", size = 482346, upload-time = "2026-01-18T20:56:05.152Z" }, + { url = "https://files.pythonhosted.org/packages/66/c4/f337ac0905eed9c393ef990c54565cd33644918e0a8031fe48c098c71dbf/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6a4c34ddef109647c769d69be65fa1de7a6022b02ad45546a69b3216573eb4a", size = 425181, upload-time = "2026-01-18T20:55:37.83Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/6d5758fabef3babdf4bbbc453738cc7de9cd3334e4c38dd5737e27b85653/ormsgpack-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:73670ed0375ecc303858e3613f407628dd1fca18fe6ac57b7b7ce66cc7bb006c", size = 117182, upload-time = "2026-01-18T20:55:31.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/17a15549233c37e7fd054c48fe9207492e06b026dbd872b826a0b5f833b6/ormsgpack-1.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:c2be829954434e33601ae5da328cccce3266b098927ca7a30246a0baec2ce7bd", size = 111464, upload-time = "2026-01-18T20:55:38.811Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/16c4b1921c308a92cef3bf6663226ae283395aa0ff6e154f925c32e91ff5/ormsgpack-1.12.2-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7a29d09b64b9694b588ff2f80e9826bdceb3a2b91523c5beae1fab27d5c940e7", size = 378618, upload-time = "2026-01-18T20:55:50.835Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/468de634079615abf66ed13bb5c34ff71da237213f29294363beeeca5306/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b39e629fd2e1c5b2f46f99778450b59454d1f901bc507963168985e79f09c5d", size = 203186, upload-time = "2026-01-18T20:56:11.163Z" }, + { url = "https://files.pythonhosted.org/packages/73/a9/d756e01961442688b7939bacd87ce13bfad7d26ce24f910f6028178b2cc8/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:958dcb270d30a7cb633a45ee62b9444433fa571a752d2ca484efdac07480876e", size = 210738, upload-time = "2026-01-18T20:56:09.181Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ba/795b1036888542c9113269a3f5690ab53dd2258c6fb17676ac4bd44fcf94/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d379d72b6c5e964851c77cfedfb386e474adee4fd39791c2c5d9efb53505cc", size = 212569, upload-time = "2026-01-18T20:56:06.135Z" }, + { url = "https://files.pythonhosted.org/packages/6c/aa/bff73c57497b9e0cba8837c7e4bcab584b1a6dbc91a5dd5526784a5030c8/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8463a3fc5f09832e67bdb0e2fda6d518dc4281b133166146a67f54c08496442e", size = 387166, upload-time = "2026-01-18T20:55:36.738Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cf/f8283cba44bcb7b14f97b6274d449db276b3a86589bdb363169b51bc12de/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:eddffb77eff0bad4e67547d67a130604e7e2dfbb7b0cde0796045be4090f35c6", size = 482498, upload-time = "2026-01-18T20:55:29.626Z" }, + { url = "https://files.pythonhosted.org/packages/05/be/71e37b852d723dfcbe952ad04178c030df60d6b78eba26bfd14c9a40575e/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcd55e5f6ba0dbce624942adf9f152062135f991a0126064889f68eb850de0dd", size = 425518, upload-time = "2026-01-18T20:55:49.556Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0c/9803aa883d18c7ef197213cd2cbf73ba76472a11fe100fb7dab2884edf48/ormsgpack-1.12.2-cp312-cp312-win_amd64.whl", hash = "sha256:d024b40828f1dde5654faebd0d824f9cc29ad46891f626272dd5bfd7af2333a4", size = 117462, upload-time = "2026-01-18T20:55:47.726Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9e/029e898298b2cc662f10d7a15652a53e3b525b1e7f07e21fef8536a09bb8/ormsgpack-1.12.2-cp312-cp312-win_arm64.whl", hash = "sha256:da538c542bac7d1c8f3f2a937863dba36f013108ce63e55745941dda4b75dbb6", size = 111559, upload-time = "2026-01-18T20:55:54.273Z" }, + { url = "https://files.pythonhosted.org/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5ea60cb5f210b1cfbad8c002948d73447508e629ec375acb82910e3efa8ff355", size = 378661, upload-time = "2026-01-18T20:55:57.765Z" }, + { url = "https://files.pythonhosted.org/packages/6e/31/5efa31346affdac489acade2926989e019e8ca98129658a183e3add7af5e/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3601f19afdbea273ed70b06495e5794606a8b690a568d6c996a90d7255e51c1", size = 203194, upload-time = "2026-01-18T20:56:08.252Z" }, + { url = "https://files.pythonhosted.org/packages/eb/56/d0087278beef833187e0167f8527235ebe6f6ffc2a143e9de12a98b1ce87/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29a9f17a3dac6054c0dce7925e0f4995c727f7c41859adf9b5572180f640d172", size = 210778, upload-time = "2026-01-18T20:55:17.694Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a2/072343e1413d9443e5a252a8eb591c2d5b1bffbe5e7bfc78c069361b92eb/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39c1bd2092880e413902910388be8715f70b9f15f20779d44e673033a6146f2d", size = 212592, upload-time = "2026-01-18T20:55:32.747Z" }, + { url = "https://files.pythonhosted.org/packages/a2/8b/a0da3b98a91d41187a63b02dda14267eefc2a74fcb43cc2701066cf1510e/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:50b7249244382209877deedeee838aef1542f3d0fc28b8fe71ca9d7e1896a0d7", size = 387164, upload-time = "2026-01-18T20:55:40.853Z" }, + { url = "https://files.pythonhosted.org/packages/19/bb/6d226bc4cf9fc20d8eb1d976d027a3f7c3491e8f08289a2e76abe96a65f3/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:5af04800d844451cf102a59c74a841324868d3f1625c296a06cc655c542a6685", size = 482516, upload-time = "2026-01-18T20:55:42.033Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f1/bb2c7223398543dedb3dbf8bb93aaa737b387de61c5feaad6f908841b782/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cec70477d4371cd524534cd16472d8b9cc187e0e3043a8790545a9a9b296c258", size = 425539, upload-time = "2026-01-18T20:55:24.727Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e8/0fb45f57a2ada1fed374f7494c8cd55e2f88ccd0ab0a669aa3468716bf5f/ormsgpack-1.12.2-cp313-cp313-win_amd64.whl", hash = "sha256:21f4276caca5c03a818041d637e4019bc84f9d6ca8baa5ea03e5cc8bf56140e9", size = 117459, upload-time = "2026-01-18T20:55:56.876Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d4/0cfeea1e960d550a131001a7f38a5132c7ae3ebde4c82af1f364ccc5d904/ormsgpack-1.12.2-cp313-cp313-win_arm64.whl", hash = "sha256:baca4b6773d20a82e36d6fd25f341064244f9f86a13dead95dd7d7f996f51709", size = 111577, upload-time = "2026-01-18T20:55:43.605Z" }, + { url = "https://files.pythonhosted.org/packages/94/16/24d18851334be09c25e87f74307c84950f18c324a4d3c0b41dabdbf19c29/ormsgpack-1.12.2-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bc68dd5915f4acf66ff2010ee47c8906dc1cf07399b16f4089f8c71733f6e36c", size = 378717, upload-time = "2026-01-18T20:55:26.164Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a2/88b9b56f83adae8032ac6a6fa7f080c65b3baf9b6b64fd3d37bd202991d4/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46d084427b4132553940070ad95107266656cb646ea9da4975f85cb1a6676553", size = 203183, upload-time = "2026-01-18T20:55:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/a9/80/43e4555963bf602e5bdc79cbc8debd8b6d5456c00d2504df9775e74b450b/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c010da16235806cf1d7bc4c96bf286bfa91c686853395a299b3ddb49499a3e13", size = 210814, upload-time = "2026-01-18T20:55:33.973Z" }, + { url = "https://files.pythonhosted.org/packages/78/e1/7cfbf28de8bca6efe7e525b329c31277d1b64ce08dcba723971c241a9d60/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18867233df592c997154ff942a6503df274b5ac1765215bceba7a231bea2745d", size = 212634, upload-time = "2026-01-18T20:55:28.634Z" }, + { url = "https://files.pythonhosted.org/packages/95/f8/30ae5716e88d792a4e879debee195653c26ddd3964c968594ddef0a3cc7e/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b009049086ddc6b8f80c76b3955df1aa22a5fbd7673c525cd63bf91f23122ede", size = 387139, upload-time = "2026-01-18T20:56:02.013Z" }, + { url = "https://files.pythonhosted.org/packages/dc/81/aee5b18a3e3a0e52f718b37ab4b8af6fae0d9d6a65103036a90c2a8ffb5d/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:1dcc17d92b6390d4f18f937cf0b99054824a7815818012ddca925d6e01c2e49e", size = 482578, upload-time = "2026-01-18T20:55:35.117Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/71c9ba472d5d45f7546317f467a5fc941929cd68fb32796ca3d13dcbaec2/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f04b5e896d510b07c0ad733d7fce2d44b260c5e6c402d272128f8941984e4285", size = 425539, upload-time = "2026-01-18T20:56:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a6/ac99cd7fe77e822fed5250ff4b86fa66dd4238937dd178d2299f10b69816/ormsgpack-1.12.2-cp314-cp314-win_amd64.whl", hash = "sha256:ae3aba7eed4ca7cb79fd3436eddd29140f17ea254b91604aa1eb19bfcedb990f", size = 117493, upload-time = "2026-01-18T20:56:07.343Z" }, + { url = "https://files.pythonhosted.org/packages/3a/67/339872846a1ae4592535385a1c1f93614138566d7af094200c9c3b45d1e5/ormsgpack-1.12.2-cp314-cp314-win_arm64.whl", hash = "sha256:118576ea6006893aea811b17429bfc561b4778fad393f5f538c84af70b01260c", size = 111579, upload-time = "2026-01-18T20:55:21.161Z" }, + { url = "https://files.pythonhosted.org/packages/49/c2/6feb972dc87285ad381749d3882d8aecbde9f6ecf908dd717d33d66df095/ormsgpack-1.12.2-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7121b3d355d3858781dc40dafe25a32ff8a8242b9d80c692fd548a4b1f7fd3c8", size = 378721, upload-time = "2026-01-18T20:55:52.12Z" }, + { url = "https://files.pythonhosted.org/packages/a3/9a/900a6b9b413e0f8a471cf07830f9cf65939af039a362204b36bd5b581d8b/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ee766d2e78251b7a63daf1cddfac36a73562d3ddef68cacfb41b2af64698033", size = 203170, upload-time = "2026-01-18T20:55:44.469Z" }, + { url = "https://files.pythonhosted.org/packages/87/4c/27a95466354606b256f24fad464d7c97ab62bce6cc529dd4673e1179b8fb/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292410a7d23de9b40444636b9b8f1e4e4b814af7f1ef476e44887e52a123f09d", size = 212816, upload-time = "2026-01-18T20:55:23.501Z" }, + { url = "https://files.pythonhosted.org/packages/73/cd/29cee6007bddf7a834e6cd6f536754c0535fcb939d384f0f37a38b1cddb8/ormsgpack-1.12.2-cp314-cp314t-win_amd64.whl", hash = "sha256:837dd316584485b72ef451d08dd3e96c4a11d12e4963aedb40e08f89685d8ec2", size = 117232, upload-time = "2026-01-18T20:55:45.448Z" }, +] + [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] @@ -1664,7 +1714,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1673,7 +1723,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1721,7 +1771,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1730,7 +1780,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, @@ -1739,7 +1789,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, @@ -1748,7 +1798,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1762,7 +1812,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1851,7 +1901,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" }, @@ -1865,7 +1915,7 @@ wheels = [ [[package]] name = "pyarrow" version = "22.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, @@ -1922,7 +1972,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, @@ -1931,7 +1981,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.12.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1946,7 +1996,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.41.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -2064,7 +2114,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2078,7 +2128,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, @@ -2087,7 +2137,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2100,7 +2150,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2117,7 +2167,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] @@ -2130,7 +2180,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2143,7 +2193,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] @@ -2155,7 +2205,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, @@ -2164,7 +2214,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, @@ -2173,7 +2223,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2182,7 +2232,7 @@ wheels = [ [[package]] name = "pywin32" version = "311" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, @@ -2204,7 +2254,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2248,7 +2298,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2262,7 +2312,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2331,7 +2381,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2346,7 +2396,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] @@ -2358,7 +2408,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2372,7 +2422,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2498,7 +2548,7 @@ wheels = [ [[package]] name = "ruff" version = "0.5.7" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/bf/2b/69e5e412f9d390adbdbcbf4f64d6914fa61b44b08839a6584655014fc524/ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5", size = 2449817, upload-time = "2024-08-08T15:43:07.467Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6b/eb/06e06aaf96af30a68e83b357b037008c54a2ddcbad4f989535007c700394/ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a", size = 9570571, upload-time = "2024-08-08T15:41:56.537Z" }, @@ -2523,7 +2573,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] @@ -2535,7 +2585,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2548,7 +2598,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2557,7 +2607,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, @@ -2566,7 +2616,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, @@ -2575,61 +2625,16 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, ] -[[package]] -name = "sqlalchemy" -version = "2.0.41" -source = { registry = "https://pypi.org/simple/" } -dependencies = [ - { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/66/45b165c595ec89aa7dcc2c1cd222ab269bc753f1fc7a1e68f8481bd957bf/sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9", size = 9689424, upload-time = "2025-05-14T17:10:32.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/12/d7c445b1940276a828efce7331cb0cb09d6e5f049651db22f4ebb0922b77/sqlalchemy-2.0.41-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b", size = 2117967, upload-time = "2025-05-14T17:48:15.841Z" }, - { url = "https://files.pythonhosted.org/packages/6f/b8/cb90f23157e28946b27eb01ef401af80a1fab7553762e87df51507eaed61/sqlalchemy-2.0.41-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5", size = 2107583, upload-time = "2025-05-14T17:48:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c2/eef84283a1c8164a207d898e063edf193d36a24fb6a5bb3ce0634b92a1e8/sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747", size = 3186025, upload-time = "2025-05-14T17:51:51.226Z" }, - { url = "https://files.pythonhosted.org/packages/bd/72/49d52bd3c5e63a1d458fd6d289a1523a8015adedbddf2c07408ff556e772/sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30", size = 3186259, upload-time = "2025-05-14T17:55:22.526Z" }, - { url = "https://files.pythonhosted.org/packages/4f/9e/e3ffc37d29a3679a50b6bbbba94b115f90e565a2b4545abb17924b94c52d/sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29", size = 3126803, upload-time = "2025-05-14T17:51:53.277Z" }, - { url = "https://files.pythonhosted.org/packages/8a/76/56b21e363f6039978ae0b72690237b38383e4657281285a09456f313dd77/sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11", size = 3148566, upload-time = "2025-05-14T17:55:24.398Z" }, - { url = "https://files.pythonhosted.org/packages/3b/92/11b8e1b69bf191bc69e300a99badbbb5f2f1102f2b08b39d9eee2e21f565/sqlalchemy-2.0.41-cp310-cp310-win32.whl", hash = "sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda", size = 2086696, upload-time = "2025-05-14T17:55:59.136Z" }, - { url = "https://files.pythonhosted.org/packages/5c/88/2d706c9cc4502654860f4576cd54f7db70487b66c3b619ba98e0be1a4642/sqlalchemy-2.0.41-cp310-cp310-win_amd64.whl", hash = "sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08", size = 2110200, upload-time = "2025-05-14T17:56:00.757Z" }, - { url = "https://files.pythonhosted.org/packages/37/4e/b00e3ffae32b74b5180e15d2ab4040531ee1bef4c19755fe7926622dc958/sqlalchemy-2.0.41-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f", size = 2121232, upload-time = "2025-05-14T17:48:20.444Z" }, - { url = "https://files.pythonhosted.org/packages/ef/30/6547ebb10875302074a37e1970a5dce7985240665778cfdee2323709f749/sqlalchemy-2.0.41-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560", size = 2110897, upload-time = "2025-05-14T17:48:21.634Z" }, - { url = "https://files.pythonhosted.org/packages/9e/21/59df2b41b0f6c62da55cd64798232d7349a9378befa7f1bb18cf1dfd510a/sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f", size = 3273313, upload-time = "2025-05-14T17:51:56.205Z" }, - { url = "https://files.pythonhosted.org/packages/62/e4/b9a7a0e5c6f79d49bcd6efb6e90d7536dc604dab64582a9dec220dab54b6/sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6", size = 3273807, upload-time = "2025-05-14T17:55:26.928Z" }, - { url = "https://files.pythonhosted.org/packages/39/d8/79f2427251b44ddee18676c04eab038d043cff0e764d2d8bb08261d6135d/sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04", size = 3209632, upload-time = "2025-05-14T17:51:59.384Z" }, - { url = "https://files.pythonhosted.org/packages/d4/16/730a82dda30765f63e0454918c982fb7193f6b398b31d63c7c3bd3652ae5/sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582", size = 3233642, upload-time = "2025-05-14T17:55:29.901Z" }, - { url = "https://files.pythonhosted.org/packages/04/61/c0d4607f7799efa8b8ea3c49b4621e861c8f5c41fd4b5b636c534fcb7d73/sqlalchemy-2.0.41-cp311-cp311-win32.whl", hash = "sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8", size = 2086475, upload-time = "2025-05-14T17:56:02.095Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8e/8344f8ae1cb6a479d0741c02cd4f666925b2bf02e2468ddaf5ce44111f30/sqlalchemy-2.0.41-cp311-cp311-win_amd64.whl", hash = "sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504", size = 2110903, upload-time = "2025-05-14T17:56:03.499Z" }, - { url = "https://files.pythonhosted.org/packages/3e/2a/f1f4e068b371154740dd10fb81afb5240d5af4aa0087b88d8b308b5429c2/sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9", size = 2119645, upload-time = "2025-05-14T17:55:24.854Z" }, - { url = "https://files.pythonhosted.org/packages/9b/e8/c664a7e73d36fbfc4730f8cf2bf930444ea87270f2825efbe17bf808b998/sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1", size = 2107399, upload-time = "2025-05-14T17:55:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/5c/78/8a9cf6c5e7135540cb682128d091d6afa1b9e48bd049b0d691bf54114f70/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70", size = 3293269, upload-time = "2025-05-14T17:50:38.227Z" }, - { url = "https://files.pythonhosted.org/packages/3c/35/f74add3978c20de6323fb11cb5162702670cc7a9420033befb43d8d5b7a4/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e", size = 3303364, upload-time = "2025-05-14T17:51:49.829Z" }, - { url = "https://files.pythonhosted.org/packages/6a/d4/c990f37f52c3f7748ebe98883e2a0f7d038108c2c5a82468d1ff3eec50b7/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078", size = 3229072, upload-time = "2025-05-14T17:50:39.774Z" }, - { url = "https://files.pythonhosted.org/packages/15/69/cab11fecc7eb64bc561011be2bd03d065b762d87add52a4ca0aca2e12904/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae", size = 3268074, upload-time = "2025-05-14T17:51:51.736Z" }, - { url = "https://files.pythonhosted.org/packages/5c/ca/0c19ec16858585d37767b167fc9602593f98998a68a798450558239fb04a/sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6", size = 2084514, upload-time = "2025-05-14T17:55:49.915Z" }, - { url = "https://files.pythonhosted.org/packages/7f/23/4c2833d78ff3010a4e17f984c734f52b531a8c9060a50429c9d4b0211be6/sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0", size = 2111557, upload-time = "2025-05-14T17:55:51.349Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ad/2e1c6d4f235a97eeef52d0200d8ddda16f6c4dd70ae5ad88c46963440480/sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443", size = 2115491, upload-time = "2025-05-14T17:55:31.177Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8d/be490e5db8400dacc89056f78a52d44b04fbf75e8439569d5b879623a53b/sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc", size = 2102827, upload-time = "2025-05-14T17:55:34.921Z" }, - { url = "https://files.pythonhosted.org/packages/a0/72/c97ad430f0b0e78efaf2791342e13ffeafcbb3c06242f01a3bb8fe44f65d/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1", size = 3225224, upload-time = "2025-05-14T17:50:41.418Z" }, - { url = "https://files.pythonhosted.org/packages/5e/51/5ba9ea3246ea068630acf35a6ba0d181e99f1af1afd17e159eac7e8bc2b8/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a", size = 3230045, upload-time = "2025-05-14T17:51:54.722Z" }, - { url = "https://files.pythonhosted.org/packages/78/2f/8c14443b2acea700c62f9b4a8bad9e49fc1b65cfb260edead71fd38e9f19/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d", size = 3159357, upload-time = "2025-05-14T17:50:43.483Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b2/43eacbf6ccc5276d76cea18cb7c3d73e294d6fb21f9ff8b4eef9b42bbfd5/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23", size = 3197511, upload-time = "2025-05-14T17:51:57.308Z" }, - { url = "https://files.pythonhosted.org/packages/fa/2e/677c17c5d6a004c3c45334ab1dbe7b7deb834430b282b8a0f75ae220c8eb/sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f", size = 2082420, upload-time = "2025-05-14T17:55:52.69Z" }, - { url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df", size = 2108329, upload-time = "2025-05-14T17:55:54.495Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fc/9ba22f01b5cdacc8f5ed0d22304718d2c758fce3fd49a5372b886a86f37c/sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576", size = 1911224, upload-time = "2025-05-14T17:39:42.154Z" }, -] - [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -2641,7 +2646,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2653,8 +2658,8 @@ wheels = [ [[package]] name = "temporalio" -version = "1.23.0" -source = { registry = "https://test.pypi.org/simple/" } +version = "1.25.0" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, { name = "protobuf" }, @@ -2662,13 +2667,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://test-files.pythonhosted.org/packages/67/48/ba7413e2fab8dcd277b9df00bafa572da24e9ca32de2f38d428dc3a2825c/temporalio-1.23.0.tar.gz", hash = "sha256:72750494b00eb73ded9db76195e3a9b53ff548780f73d878ec3f807ee3191410", size = 1933051, upload-time = "2026-02-18T17:40:03.902Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/9c/3782bab0bf11a40b550147c19a5d1a476c17405391751982408902d9f138/temporalio-1.25.0.tar.gz", hash = "sha256:a3bbec1dcc904f674402cfa4faae480fda490b1c53ea5440c1f1996c562016fb", size = 2152534, upload-time = "2026-04-08T18:53:55.388Z" } wheels = [ - { url = "https://test-files.pythonhosted.org/packages/6f/71/26c8f21dca9092201b3b9cb7aff42460b4864b5999aa4c6a4343ac66f1fd/temporalio-1.23.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6b69ac8d75f2d90e66f4edce4316f6a33badc4a30b22efc50e9eddaa9acdc216", size = 12311037, upload-time = "2026-02-18T17:39:27.941Z" }, - { url = "https://test-files.pythonhosted.org/packages/ec/47/43102816139f2d346680cb7cc1e53da5f6968355ac65b4d35d4edbfca896/temporalio-1.23.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:1bbbb2f9c3cdd09451565163f6d741e51f109694c49435d475fdfa42b597219d", size = 11821906, upload-time = "2026-02-18T17:39:35.343Z" }, - { url = "https://test-files.pythonhosted.org/packages/00/b0/899ff28464a0e17adf17476bdfac8faf4ea41870358ff2d14737e43f9e66/temporalio-1.23.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf6570e0ee696f99a38d855da4441a890c7187357c16505ed458ac9ef274ed70", size = 12063601, upload-time = "2026-02-18T17:39:43.299Z" }, - { url = "https://test-files.pythonhosted.org/packages/ed/17/b8c6d2ec3e113c6a788322513a5ff635bdd54b3791d092ed0e273467748a/temporalio-1.23.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b82d6cca54c9f376b50e941dd10d12f7fe5b692a314fb087be72cd2898646a79", size = 12394579, upload-time = "2026-02-18T17:39:52.935Z" }, - { url = "https://test-files.pythonhosted.org/packages/b4/b7/f9ef7fd5ee65aef7d59ab1e95cb1b45df2fe49c17e3aa4d650ae3322f015/temporalio-1.23.0-cp310-abi3-win_amd64.whl", hash = "sha256:43c3b99a46dd329761a256f3855710c4a5b322afc879785e468bdd0b94faace6", size = 12834494, upload-time = "2026-02-18T17:40:00.858Z" }, + { url = "https://files.pythonhosted.org/packages/19/e3/5676dd10d1164b6d6ca8752314054097b89c5da931e936af402a7b15236c/temporalio-1.25.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6dc1bc8e1773b1a833d86a7ede2dd90ef4e031ced5b748b59e7f09a5bf9b327d", size = 13943906, upload-time = "2026-04-08T18:53:30.022Z" }, + { url = "https://files.pythonhosted.org/packages/89/50/7cbf7f845973be986ec165348f72f7a409750842a04d554965a39be5cb4f/temporalio-1.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:3c8fdcf79ea5ae8ae2cf6f48072e4a86c3e0f4778f6a8a066c6ff1d336587db4", size = 13298719, upload-time = "2026-04-08T18:53:35.95Z" }, + { url = "https://files.pythonhosted.org/packages/d2/31/d474bab8535552add6ed289911bf1ffae5d7071823ece1069842190fcaed/temporalio-1.25.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:141f37aaafd7d090ba5c8776e4e9bc60df1fbc64b9f50c8f00e905a436588ddc", size = 13555435, upload-time = "2026-04-08T18:53:41.36Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c8/e7dc053d6107bf2a037a3c9fe7b86639a25dcb888bde0e1ca366901ee47f/temporalio-1.25.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7ca5bb80264976477d4dc7a839b3d22af8577ae92306526a061481db49bf92", size = 14052050, upload-time = "2026-04-08T18:53:46.44Z" }, + { url = "https://files.pythonhosted.org/packages/08/70/9340ed3a578321cbc153041d34834bb1ec3f1f3e3d9cded47cd1b7c3e403/temporalio-1.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:9411534279a2e64847231b6059c214bff4d57cfd1532bd09f333d0b1603daa7f", size = 14299684, upload-time = "2026-04-08T18:53:52.482Z" }, ] [package.optional-dependencies] @@ -2724,13 +2729,17 @@ gevent = [ ] langchain = [ { name = "fastapi" }, - { name = "langchain", marker = "python_full_version < '4'" }, - { name = "langchain-openai", marker = "python_full_version < '4'" }, - { name = "langsmith", marker = "python_full_version < '4'" }, + { name = "langchain" }, + { name = "langchain-openai" }, + { name = "langsmith" }, { name = "openai" }, { name = "tqdm" }, { name = "uvicorn", extra = ["standard"] }, ] +langgraph = [ + { name = "langgraph" }, + { name = "temporalio" }, +] nexus = [ { name = "nexus-rpc" }, ] @@ -2788,13 +2797,17 @@ encryption = [ gevent = [{ name = "gevent", marker = "python_full_version >= '3.8'", specifier = ">=25.4.2" }] langchain = [ { name = "fastapi", specifier = ">=0.115.12" }, - { name = "langchain", marker = "python_full_version >= '3.9' and python_full_version < '4'", specifier = ">=0.1.7,<0.2" }, - { name = "langchain-openai", marker = "python_full_version >= '3.9' and python_full_version < '4'", specifier = ">=0.0.6,<0.0.7" }, - { name = "langsmith", marker = "python_full_version >= '3.9' and python_full_version < '4'", specifier = ">=0.1.22,<0.2" }, + { name = "langchain", specifier = ">=0.3.0" }, + { name = "langchain-openai", specifier = ">=0.3.0" }, + { name = "langsmith", specifier = ">=0.1.22" }, { name = "openai", specifier = ">=1.4.0,<2" }, { name = "tqdm", specifier = ">=4.62.0,<5" }, { name = "uvicorn", extras = ["standard"], specifier = ">=0.24.0.post1,<0.25" }, ] +langgraph = [ + { name = "langgraph", specifier = ">=1.1.3" }, + { name = "temporalio", extras = ["langgraph"], specifier = ">=1.25" }, +] nexus = [{ name = "nexus-rpc", specifier = ">=1.1.0,<2" }] open-telemetry = [ { name = "opentelemetry-exporter-otlp-proto-grpc" }, @@ -2815,7 +2828,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2824,7 +2837,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.12.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2885,7 +2898,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2910,7 +2923,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2949,7 +2962,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2961,7 +2974,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2979,7 +2992,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2995,7 +3008,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -3004,7 +3017,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -3013,7 +3026,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] @@ -3025,29 +3038,16 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, ] -[[package]] -name = "typing-inspect" -version = "0.9.0" -source = { registry = "https://pypi.org/simple/" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, -] - [[package]] name = "typing-inspection" version = "0.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -3059,7 +3059,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, @@ -3068,16 +3068,45 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] +[[package]] +name = "uuid-utils" +version = "0.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/d1/38a573f0c631c062cf42fa1f5d021d4dd3c31fb23e4376e4b56b0c9fbbed/uuid_utils-0.14.1.tar.gz", hash = "sha256:9bfc95f64af80ccf129c604fb6b8ca66c6f256451e32bc4570f760e4309c9b69", size = 22195, upload-time = "2026-02-20T22:50:38.833Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/b7/add4363039a34506a58457d96d4aa2126061df3a143eb4d042aedd6a2e76/uuid_utils-0.14.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:93a3b5dc798a54a1feb693f2d1cb4cf08258c32ff05ae4929b5f0a2ca624a4f0", size = 604679, upload-time = "2026-02-20T22:50:27.469Z" }, + { url = "https://files.pythonhosted.org/packages/dd/84/d1d0bef50d9e66d31b2019997c741b42274d53dde2e001b7a83e9511c339/uuid_utils-0.14.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ccd65a4b8e83af23eae5e56d88034b2fe7264f465d3e830845f10d1591b81741", size = 309346, upload-time = "2026-02-20T22:50:31.857Z" }, + { url = "https://files.pythonhosted.org/packages/ef/ed/b6d6fd52a6636d7c3eddf97d68da50910bf17cd5ac221992506fb56cf12e/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b56b0cacd81583834820588378e432b0696186683b813058b707aedc1e16c4b1", size = 344714, upload-time = "2026-02-20T22:50:42.642Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a7/a19a1719fb626fe0b31882db36056d44fe904dc0cf15b06fdf56b2679cf7/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb3cf14de789097320a3c56bfdfdd51b1225d11d67298afbedee7e84e3837c96", size = 350914, upload-time = "2026-02-20T22:50:36.487Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fc/f6690e667fdc3bb1a73f57951f97497771c56fe23e3d302d7404be394d4f/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e0854a90d67f4b0cc6e54773deb8be618f4c9bad98d3326f081423b5d14fae", size = 482609, upload-time = "2026-02-20T22:50:37.511Z" }, + { url = "https://files.pythonhosted.org/packages/54/6e/dcd3fa031320921a12ec7b4672dea3bd1dd90ddffa363a91831ba834d559/uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6743ba194de3910b5feb1a62590cd2587e33a73ab6af8a01b642ceb5055862", size = 345699, upload-time = "2026-02-20T22:50:46.87Z" }, + { url = "https://files.pythonhosted.org/packages/04/28/e5220204b58b44ac0047226a9d016a113fde039280cc8732d9e6da43b39f/uuid_utils-0.14.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:043fb58fde6cf1620a6c066382f04f87a8e74feb0f95a585e4ed46f5d44af57b", size = 372205, upload-time = "2026-02-20T22:50:28.438Z" }, + { url = "https://files.pythonhosted.org/packages/c7/d9/3d2eb98af94b8dfffc82b6a33b4dfc87b0a5de2c68a28f6dde0db1f8681b/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c915d53f22945e55fe0d3d3b0b87fd965a57f5fd15666fd92d6593a73b1dd297", size = 521836, upload-time = "2026-02-20T22:50:23.057Z" }, + { url = "https://files.pythonhosted.org/packages/a8/15/0eb106cc6fe182f7577bc0ab6e2f0a40be247f35c5e297dbf7bbc460bd02/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:0972488e3f9b449e83f006ead5a0e0a33ad4a13e4462e865b7c286ab7d7566a3", size = 625260, upload-time = "2026-02-20T22:50:25.949Z" }, + { url = "https://files.pythonhosted.org/packages/3c/17/f539507091334b109e7496830af2f093d9fc8082411eafd3ece58af1f8ba/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:1c238812ae0c8ffe77d8d447a32c6dfd058ea4631246b08b5a71df586ff08531", size = 587824, upload-time = "2026-02-20T22:50:35.225Z" }, + { url = "https://files.pythonhosted.org/packages/2e/c2/d37a7b2e41f153519367d4db01f0526e0d4b06f1a4a87f1c5dfca5d70a8b/uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:bec8f8ef627af86abf8298e7ec50926627e29b34fa907fcfbedb45aaa72bca43", size = 551407, upload-time = "2026-02-20T22:50:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/65/36/2d24b2cbe78547c6532da33fb8613debd3126eccc33a6374ab788f5e46e9/uuid_utils-0.14.1-cp39-abi3-win32.whl", hash = "sha256:b54d6aa6252d96bac1fdbc80d26ba71bad9f220b2724d692ad2f2310c22ef523", size = 183476, upload-time = "2026-02-20T22:50:32.745Z" }, + { url = "https://files.pythonhosted.org/packages/83/92/2d7e90df8b1a69ec4cff33243ce02b7a62f926ef9e2f0eca5a026889cd73/uuid_utils-0.14.1-cp39-abi3-win_amd64.whl", hash = "sha256:fc27638c2ce267a0ce3e06828aff786f91367f093c80625ee21dad0208e0f5ba", size = 187147, upload-time = "2026-02-20T22:50:45.807Z" }, + { url = "https://files.pythonhosted.org/packages/d9/26/529f4beee17e5248e37e0bc17a2761d34c0fa3b1e5729c88adb2065bae6e/uuid_utils-0.14.1-cp39-abi3-win_arm64.whl", hash = "sha256:b04cb49b42afbc4ff8dbc60cf054930afc479d6f4dd7f1ec3bbe5dbfdde06b7a", size = 188132, upload-time = "2026-02-20T22:50:41.718Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/6c64bdbf71f58ccde7919e00491812556f446a5291573af92c49a5e9aaef/uuid_utils-0.14.1-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b197cd5424cf89fb019ca7f53641d05bfe34b1879614bed111c9c313b5574cd8", size = 591617, upload-time = "2026-02-20T22:50:24.532Z" }, + { url = "https://files.pythonhosted.org/packages/d0/f0/758c3b0fb0c4871c7704fef26a5bc861de4f8a68e4831669883bebe07b0f/uuid_utils-0.14.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:12c65020ba6cb6abe1d57fcbfc2d0ea0506c67049ee031714057f5caf0f9bc9c", size = 303702, upload-time = "2026-02-20T22:50:40.687Z" }, + { url = "https://files.pythonhosted.org/packages/85/89/d91862b544c695cd58855efe3201f83894ed82fffe34500774238ab8eba7/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b5d2ad28063d422ccc2c28d46471d47b61a58de885d35113a8f18cb547e25bf", size = 337678, upload-time = "2026-02-20T22:50:39.768Z" }, + { url = "https://files.pythonhosted.org/packages/ee/6b/cf342ba8a898f1de024be0243fac67c025cad530c79ea7f89c4ce718891a/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da2234387b45fde40b0fedfee64a0ba591caeea9c48c7698ab6e2d85c7991533", size = 343711, upload-time = "2026-02-20T22:50:43.965Z" }, + { url = "https://files.pythonhosted.org/packages/b3/20/049418d094d396dfa6606b30af925cc68a6670c3b9103b23e6990f84b589/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50fffc2827348c1e48972eed3d1c698959e63f9d030aa5dd82ba451113158a62", size = 476731, upload-time = "2026-02-20T22:50:30.589Z" }, + { url = "https://files.pythonhosted.org/packages/77/a1/0857f64d53a90321e6a46a3d4cc394f50e1366132dcd2ae147f9326ca98b/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1dbe718765f70f5b7f9b7f66b6a937802941b1cc56bcf642ce0274169741e01", size = 338902, upload-time = "2026-02-20T22:50:33.927Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d0/5bf7cbf1ac138c92b9ac21066d18faf4d7e7f651047b700eb192ca4b9fdb/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:258186964039a8e36db10810c1ece879d229b01331e09e9030bc5dcabe231bd2", size = 364700, upload-time = "2026-02-20T22:50:21.732Z" }, +] + [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3102,7 +3131,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3134,7 +3163,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -3234,7 +3263,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3290,10 +3319,128 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "xxhash" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, + { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, + { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, + { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, + { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, + { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, + { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, + { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" }, + { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" }, + { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" }, + { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" }, + { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" }, + { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" }, + { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" }, + { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738, upload-time = "2025-10-02T14:34:55.839Z" }, + { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821, upload-time = "2025-10-02T14:34:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127, upload-time = "2025-10-02T14:34:59.21Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975, upload-time = "2025-10-02T14:35:00.816Z" }, + { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241, upload-time = "2025-10-02T14:35:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471, upload-time = "2025-10-02T14:35:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936, upload-time = "2025-10-02T14:35:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440, upload-time = "2025-10-02T14:35:06.239Z" }, + { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990, upload-time = "2025-10-02T14:35:07.735Z" }, + { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689, upload-time = "2025-10-02T14:35:09.438Z" }, + { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068, upload-time = "2025-10-02T14:35:11.162Z" }, + { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495, upload-time = "2025-10-02T14:35:12.971Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620, upload-time = "2025-10-02T14:35:14.129Z" }, + { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542, upload-time = "2025-10-02T14:35:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880, upload-time = "2025-10-02T14:35:16.315Z" }, + { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956, upload-time = "2025-10-02T14:35:17.413Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072, upload-time = "2025-10-02T14:35:18.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409, upload-time = "2025-10-02T14:35:20.31Z" }, + { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736, upload-time = "2025-10-02T14:35:21.616Z" }, + { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833, upload-time = "2025-10-02T14:35:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348, upload-time = "2025-10-02T14:35:25.111Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070, upload-time = "2025-10-02T14:35:26.586Z" }, + { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907, upload-time = "2025-10-02T14:35:28.087Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839, upload-time = "2025-10-02T14:35:29.857Z" }, + { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304, upload-time = "2025-10-02T14:35:31.222Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930, upload-time = "2025-10-02T14:35:32.517Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787, upload-time = "2025-10-02T14:35:33.827Z" }, + { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, + { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, + { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, + { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, + { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, + { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, + { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, + { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, + { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, + { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, + { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, + { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, + { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, + { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, + { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, + { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, + { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, + { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, + { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, +] + [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3392,7 +3539,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, @@ -3401,7 +3548,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] @@ -3413,7 +3560,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] @@ -3444,3 +3591,93 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b6/66/ac05b741c2129fdf668b85631d2268421c5cd1a9ff99be1674371139d665/zope.interface-7.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a71a5b541078d0ebe373a81a3b7e71432c61d12e660f1d67896ca62d9628045b", size = 264696, upload-time = "2024-11-28T08:48:41.161Z" }, { url = "https://files.pythonhosted.org/packages/0a/2f/1bccc6f4cc882662162a1158cda1a7f616add2ffe322b28c99cb031b4ffc/zope.interface-7.2-cp313-cp313-win_amd64.whl", hash = "sha256:4893395d5dd2ba655c38ceb13014fd65667740f09fa5bb01caa1e6284e48c0cd", size = 212472, upload-time = "2024-11-28T08:49:56.587Z" }, ] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/7a/28efd1d371f1acd037ac64ed1c5e2b41514a6cc937dd6ab6a13ab9f0702f/zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd", size = 795256, upload-time = "2025-09-14T22:15:56.415Z" }, + { url = "https://files.pythonhosted.org/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7", size = 640565, upload-time = "2025-09-14T22:15:58.177Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1b/4fdb2c12eb58f31f28c4d28e8dc36611dd7205df8452e63f52fb6261d13e/zstandard-0.25.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:ab85470ab54c2cb96e176f40342d9ed41e58ca5733be6a893b730e7af9c40550", size = 5345306, upload-time = "2025-09-14T22:16:00.165Z" }, + { url = "https://files.pythonhosted.org/packages/73/28/a44bdece01bca027b079f0e00be3b6bd89a4df180071da59a3dd7381665b/zstandard-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e05ab82ea7753354bb054b92e2f288afb750e6b439ff6ca78af52939ebbc476d", size = 5055561, upload-time = "2025-09-14T22:16:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/e9/74/68341185a4f32b274e0fc3410d5ad0750497e1acc20bd0f5b5f64ce17785/zstandard-0.25.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:78228d8a6a1c177a96b94f7e2e8d012c55f9c760761980da16ae7546a15a8e9b", size = 5402214, upload-time = "2025-09-14T22:16:04.109Z" }, + { url = "https://files.pythonhosted.org/packages/8b/67/f92e64e748fd6aaffe01e2b75a083c0c4fd27abe1c8747fee4555fcee7dd/zstandard-0.25.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b6bd67528ee8b5c5f10255735abc21aa106931f0dbaf297c7be0c886353c3d0", size = 5449703, upload-time = "2025-09-14T22:16:06.312Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e5/6d36f92a197c3c17729a2125e29c169f460538a7d939a27eaaa6dcfcba8e/zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4b6d83057e713ff235a12e73916b6d356e3084fd3d14ced499d84240f3eecee0", size = 5556583, upload-time = "2025-09-14T22:16:08.457Z" }, + { url = "https://files.pythonhosted.org/packages/d7/83/41939e60d8d7ebfe2b747be022d0806953799140a702b90ffe214d557638/zstandard-0.25.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9174f4ed06f790a6869b41cba05b43eeb9a35f8993c4422ab853b705e8112bbd", size = 5045332, upload-time = "2025-09-14T22:16:10.444Z" }, + { url = "https://files.pythonhosted.org/packages/b3/87/d3ee185e3d1aa0133399893697ae91f221fda79deb61adbe998a7235c43f/zstandard-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25f8f3cd45087d089aef5ba3848cd9efe3ad41163d3400862fb42f81a3a46701", size = 5572283, upload-time = "2025-09-14T22:16:12.128Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1d/58635ae6104df96671076ac7d4ae7816838ce7debd94aecf83e30b7121b0/zstandard-0.25.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3756b3e9da9b83da1796f8809dd57cb024f838b9eeafde28f3cb472012797ac1", size = 4959754, upload-time = "2025-09-14T22:16:14.225Z" }, + { url = "https://files.pythonhosted.org/packages/75/d6/57e9cb0a9983e9a229dd8fd2e6e96593ef2aa82a3907188436f22b111ccd/zstandard-0.25.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81dad8d145d8fd981b2962b686b2241d3a1ea07733e76a2f15435dfb7fb60150", size = 5266477, upload-time = "2025-09-14T22:16:16.343Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a9/ee891e5edf33a6ebce0a028726f0bbd8567effe20fe3d5808c42323e8542/zstandard-0.25.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a5a419712cf88862a45a23def0ae063686db3d324cec7edbe40509d1a79a0aab", size = 5440914, upload-time = "2025-09-14T22:16:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/58/08/a8522c28c08031a9521f27abc6f78dbdee7312a7463dd2cfc658b813323b/zstandard-0.25.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e7360eae90809efd19b886e59a09dad07da4ca9ba096752e61a2e03c8aca188e", size = 5819847, upload-time = "2025-09-14T22:16:20.559Z" }, + { url = "https://files.pythonhosted.org/packages/6f/11/4c91411805c3f7b6f31c60e78ce347ca48f6f16d552fc659af6ec3b73202/zstandard-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:75ffc32a569fb049499e63ce68c743155477610532da1eb38e7f24bf7cd29e74", size = 5363131, upload-time = "2025-09-14T22:16:22.206Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d6/8c4bd38a3b24c4c7676a7a3d8de85d6ee7a983602a734b9f9cdefb04a5d6/zstandard-0.25.0-cp310-cp310-win32.whl", hash = "sha256:106281ae350e494f4ac8a80470e66d1fe27e497052c8d9c3b95dc4cf1ade81aa", size = 436469, upload-time = "2025-09-14T22:16:25.002Z" }, + { url = "https://files.pythonhosted.org/packages/93/90/96d50ad417a8ace5f841b3228e93d1bb13e6ad356737f42e2dde30d8bd68/zstandard-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea9d54cc3d8064260114a0bbf3479fc4a98b21dffc89b3459edd506b69262f6e", size = 506100, upload-time = "2025-09-14T22:16:23.569Z" }, + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +] From e2832bb662c169191ddc324d4fce57e4bb6020af Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 21:28:07 -0500 Subject: [PATCH 7/9] Address review: consistent v2 API, unique thread_id, SDK prereq note --- langgraph_plugin/README.md | 2 ++ langgraph_plugin/graph_api/human_in_the_loop/workflow.py | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/langgraph_plugin/README.md b/langgraph_plugin/README.md index e13a7b9a..cb34b7fb 100644 --- a/langgraph_plugin/README.md +++ b/langgraph_plugin/README.md @@ -19,6 +19,8 @@ Samples are organized by API style: ## Prerequisites +> **Note:** These samples require the LangGraph plugin from [sdk-python#1448](https://github.com/temporalio/sdk-python/pull/1448), which has not been released yet. They will not be runnable until the SDK is published with the `temporalio[langgraph]` extra. + 1. Install dependencies: ```bash diff --git a/langgraph_plugin/graph_api/human_in_the_loop/workflow.py b/langgraph_plugin/graph_api/human_in_the_loop/workflow.py index 7ffca5e8..fc5f3b5f 100644 --- a/langgraph_plugin/graph_api/human_in_the_loop/workflow.py +++ b/langgraph_plugin/graph_api/human_in_the_loop/workflow.py @@ -60,7 +60,9 @@ def get_draft(self) -> str | None: @workflow.run async def run(self, user_message: str) -> str: g = graph("chatbot").compile(checkpointer=InMemorySaver()) - config = RunnableConfig({"configurable": {"thread_id": "1"}}) + config = RunnableConfig( + {"configurable": {"thread_id": workflow.info().workflow_id}} + ) # First invocation: runs generate_draft, then pauses at interrupt() result = await g.ainvoke(user_message, config, version="v2") @@ -72,4 +74,7 @@ async def run(self, user_message: str) -> str: await workflow.wait_condition(lambda: self._human_input is not None) # Resume the graph with the human's feedback - return await g.ainvoke(Command(resume=self._human_input), config) + resumed = await g.ainvoke( + Command(resume=self._human_input), config, version="v2" + ) + return resumed.value From f3fb15c058acf06807dd04f8cfaf00ed994f6295 Mon Sep 17 00:00:00 2001 From: DABH Date: Tue, 14 Apr 2026 21:28:29 -0500 Subject: [PATCH 8/9] Remove SDK prereq note - PR won't merge until plugin is released --- langgraph_plugin/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/langgraph_plugin/README.md b/langgraph_plugin/README.md index cb34b7fb..e13a7b9a 100644 --- a/langgraph_plugin/README.md +++ b/langgraph_plugin/README.md @@ -19,8 +19,6 @@ Samples are organized by API style: ## Prerequisites -> **Note:** These samples require the LangGraph plugin from [sdk-python#1448](https://github.com/temporalio/sdk-python/pull/1448), which has not been released yet. They will not be runnable until the SDK is published with the `temporalio[langgraph]` extra. - 1. Install dependencies: ```bash From 67d1310b795da53636774c40f1b9a9c3d7d777e7 Mon Sep 17 00:00:00 2001 From: DABH Date: Wed, 15 Apr 2026 11:09:22 -0500 Subject: [PATCH 9/9] Add LangSmith tracing sample (Graph API + Functional API) Combines LangGraphPlugin (durable execution) with LangSmithPlugin (observability) for full tracing of LLM calls through Temporal workflows. --- langgraph_plugin/README.md | 1 + .../langsmith_tracing/README.md | 41 ++++++++++++++++ .../langsmith_tracing/__init__.py | 1 + .../langsmith_tracing/run_worker.py | 45 +++++++++++++++++ .../langsmith_tracing/run_workflow.py | 34 +++++++++++++ .../langsmith_tracing/workflow.py | 48 +++++++++++++++++++ .../graph_api/langsmith_tracing/README.md | 43 +++++++++++++++++ .../graph_api/langsmith_tracing/__init__.py | 1 + .../graph_api/langsmith_tracing/run_worker.py | 37 ++++++++++++++ .../langsmith_tracing/run_workflow.py | 32 +++++++++++++ .../graph_api/langsmith_tracing/workflow.py | 43 +++++++++++++++++ 11 files changed, 326 insertions(+) create mode 100644 langgraph_plugin/functional_api/langsmith_tracing/README.md create mode 100644 langgraph_plugin/functional_api/langsmith_tracing/__init__.py create mode 100644 langgraph_plugin/functional_api/langsmith_tracing/run_worker.py create mode 100644 langgraph_plugin/functional_api/langsmith_tracing/run_workflow.py create mode 100644 langgraph_plugin/functional_api/langsmith_tracing/workflow.py create mode 100644 langgraph_plugin/graph_api/langsmith_tracing/README.md create mode 100644 langgraph_plugin/graph_api/langsmith_tracing/__init__.py create mode 100644 langgraph_plugin/graph_api/langsmith_tracing/run_worker.py create mode 100644 langgraph_plugin/graph_api/langsmith_tracing/run_workflow.py create mode 100644 langgraph_plugin/graph_api/langsmith_tracing/workflow.py diff --git a/langgraph_plugin/README.md b/langgraph_plugin/README.md index e13a7b9a..47847893 100644 --- a/langgraph_plugin/README.md +++ b/langgraph_plugin/README.md @@ -16,6 +16,7 @@ Samples are organized by API style: | **Continue-as-new** | [graph_api/continue_as_new](graph_api/continue_as_new) | [functional_api/continue_as_new](functional_api/continue_as_new) | Multi-stage data pipeline that uses `continue-as-new` with task result caching so previously-completed stages are not re-executed. | | **ReAct Agent** | [graph_api/react_agent](graph_api/react_agent) | [functional_api/react_agent](functional_api/react_agent) | Tool-calling agent loop. Graph API uses conditional edges; Functional API uses a `while` loop. | | **Control Flow** | -- | [functional_api/control_flow](functional_api/control_flow) | Demonstrates parallel task execution, `for` loops, and `if/else` branching -- patterns that are natural in the Functional API. | +| **LangSmith Tracing** | [graph_api/langsmith_tracing](graph_api/langsmith_tracing) | [functional_api/langsmith_tracing](functional_api/langsmith_tracing) | Combines `LangGraphPlugin` with Temporal's `LangSmithPlugin` for durable execution + full observability of LLM calls. Requires API keys. | ## Prerequisites diff --git a/langgraph_plugin/functional_api/langsmith_tracing/README.md b/langgraph_plugin/functional_api/langsmith_tracing/README.md new file mode 100644 index 00000000..6596cb0d --- /dev/null +++ b/langgraph_plugin/functional_api/langsmith_tracing/README.md @@ -0,0 +1,41 @@ +# LangSmith Tracing (Functional API) + +Same pattern as the Graph API version, using `@task` and `@entrypoint` decorators. + +## What This Sample Demonstrates + +- Combining `LangSmithPlugin` (observability) with `LangGraphPlugin` (durability) +- `@traceable` decorator on a `@task` for LangSmith tracing of LLM calls +- Both plugins working together in the Functional API style + +## How It Works + +1. The Temporal client is created with `LangSmithPlugin(add_temporal_runs=True)`. +2. The worker registers the `chat` task with `LangGraphPlugin`. +3. When the workflow runs, the `chat` task executes as a Temporal activity. +4. The `@traceable` decorator sends trace data to LangSmith. + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +export ANTHROPIC_API_KEY='your-key' +export LANGCHAIN_API_KEY='your-key' + +# Terminal 1 +uv run langgraph_plugin/functional_api/langsmith_tracing/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/functional_api/langsmith_tracing/run_workflow.py +``` + +Traces will appear in your [LangSmith](https://smith.langchain.com/) dashboard. + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `@traceable` chat task, `@entrypoint`, and `ChatFunctionalWorkflow` | +| `run_worker.py` | Creates client with `LangSmithPlugin`, worker with `LangGraphPlugin` | +| `run_workflow.py` | Creates client with `LangSmithPlugin`, executes workflow | diff --git a/langgraph_plugin/functional_api/langsmith_tracing/__init__.py b/langgraph_plugin/functional_api/langsmith_tracing/__init__.py new file mode 100644 index 00000000..4cb57b73 --- /dev/null +++ b/langgraph_plugin/functional_api/langsmith_tracing/__init__.py @@ -0,0 +1 @@ +"""LangSmith tracing with LangGraph Functional API and Temporal.""" diff --git a/langgraph_plugin/functional_api/langsmith_tracing/run_worker.py b/langgraph_plugin/functional_api/langsmith_tracing/run_worker.py new file mode 100644 index 00000000..2154ef24 --- /dev/null +++ b/langgraph_plugin/functional_api/langsmith_tracing/run_worker.py @@ -0,0 +1,45 @@ +"""Worker for the LangSmith tracing sample (Functional API). + +Requires ANTHROPIC_API_KEY and LANGCHAIN_API_KEY environment variables. +""" + +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.contrib.langsmith import LangSmithPlugin +from temporalio.worker import Worker + +from langgraph_plugin.functional_api.langsmith_tracing.workflow import ( + ChatFunctionalWorkflow, + activity_options, + all_tasks, + chat_entrypoint, +) + + +async def main() -> None: + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[LangSmithPlugin(add_temporal_runs=True)], + ) + + worker = Worker( + client, + task_queue="langgraph-langsmith-functional", + workflows=[ChatFunctionalWorkflow], + plugins=[ + LangGraphPlugin( + entrypoints={"chat": chat_entrypoint}, + tasks=all_tasks, + activity_options=activity_options, + ) + ], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/langsmith_tracing/run_workflow.py b/langgraph_plugin/functional_api/langsmith_tracing/run_workflow.py new file mode 100644 index 00000000..4431d062 --- /dev/null +++ b/langgraph_plugin/functional_api/langsmith_tracing/run_workflow.py @@ -0,0 +1,34 @@ +"""Start the LangSmith tracing chat workflow (Functional API). + +Requires ANTHROPIC_API_KEY and LANGCHAIN_API_KEY environment variables. +""" + +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.langsmith import LangSmithPlugin + +from langgraph_plugin.functional_api.langsmith_tracing.workflow import ( + ChatFunctionalWorkflow, +) + + +async def main() -> None: + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[LangSmithPlugin(add_temporal_runs=True)], + ) + + result = await client.execute_workflow( + ChatFunctionalWorkflow.run, + "What is the meaning of life?", + id="langsmith-chat-functional-workflow", + task_queue="langgraph-langsmith-functional", + ) + + print(f"Response: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/functional_api/langsmith_tracing/workflow.py b/langgraph_plugin/functional_api/langsmith_tracing/workflow.py new file mode 100644 index 00000000..b0aa7ab1 --- /dev/null +++ b/langgraph_plugin/functional_api/langsmith_tracing/workflow.py @@ -0,0 +1,48 @@ +"""LangSmith tracing with LangGraph Functional API and Temporal. + +Demonstrates combining LangGraphPlugin (durable task execution) with +LangSmithPlugin (observability) for full tracing of LLM calls through +Temporal workflows. + +Requires ANTHROPIC_API_KEY and LANGCHAIN_API_KEY environment variables. +""" + +from datetime import timedelta + +from langgraph.func import entrypoint as lg_entrypoint +from langgraph.func import task +from langsmith import traceable +from temporalio import workflow +from temporalio.contrib.langgraph import entrypoint + +from langchain.chat_models import init_chat_model + + +@task +@traceable(name="chat_task", run_type="chain") +def chat(message: str) -> str: + """Call an LLM to respond to the message. Traced by LangSmith.""" + response = init_chat_model("claude-sonnet-4-6").invoke(message) + return response.content + + +@lg_entrypoint() +async def chat_entrypoint(message: str) -> dict: + """Chat entrypoint: call the LLM and return the response.""" + response = await chat(message) + return {"response": response} + + +all_tasks = [chat] + +activity_options = { + t.func.__name__: {"start_to_close_timeout": timedelta(seconds=30)} + for t in all_tasks +} + + +@workflow.defn +class ChatFunctionalWorkflow: + @workflow.run + async def run(self, message: str) -> dict: + return await entrypoint("chat").ainvoke(message) diff --git a/langgraph_plugin/graph_api/langsmith_tracing/README.md b/langgraph_plugin/graph_api/langsmith_tracing/README.md new file mode 100644 index 00000000..13f33fb8 --- /dev/null +++ b/langgraph_plugin/graph_api/langsmith_tracing/README.md @@ -0,0 +1,43 @@ +# LangSmith Tracing (Graph API) + +Demonstrates combining the LangGraph plugin (durable execution) with Temporal's LangSmith plugin (observability) for full tracing of LLM calls through Temporal workflows. + +## What This Sample Demonstrates + +- Using `LangSmithPlugin` on the Temporal client for automatic trace propagation +- Using `LangGraphPlugin` on the worker for durable LangGraph execution +- `@traceable` decorators for fine-grained LangSmith tracing within activities +- Both plugins working together: durability + observability + +## How It Works + +1. The Temporal client is created with `LangSmithPlugin(add_temporal_runs=True)`. +2. The worker is created with `LangGraphPlugin` wrapping the chat graph. +3. When the workflow runs, the `chat` node executes as a Temporal activity. +4. The `@traceable` decorator on the activity sends trace data to LangSmith. +5. The `LangSmithPlugin` adds Temporal-specific metadata to the traces. + +## Running the Sample + +Prerequisites: `uv sync --group langgraph` and a running Temporal dev server. + +```bash +export ANTHROPIC_API_KEY='your-key' +export LANGCHAIN_API_KEY='your-key' + +# Terminal 1 +uv run langgraph_plugin/graph_api/langsmith_tracing/run_worker.py + +# Terminal 2 +uv run langgraph_plugin/graph_api/langsmith_tracing/run_workflow.py +``` + +Traces will appear in your [LangSmith](https://smith.langchain.com/) dashboard. + +## Files + +| File | Description | +|------|-------------| +| `workflow.py` | `@traceable` chat node, `build_graph()`, and `ChatWorkflow` | +| `run_worker.py` | Creates client with `LangSmithPlugin`, worker with `LangGraphPlugin` | +| `run_workflow.py` | Creates client with `LangSmithPlugin`, executes workflow | diff --git a/langgraph_plugin/graph_api/langsmith_tracing/__init__.py b/langgraph_plugin/graph_api/langsmith_tracing/__init__.py new file mode 100644 index 00000000..dab692ec --- /dev/null +++ b/langgraph_plugin/graph_api/langsmith_tracing/__init__.py @@ -0,0 +1 @@ +"""LangSmith tracing with LangGraph Graph API and Temporal.""" diff --git a/langgraph_plugin/graph_api/langsmith_tracing/run_worker.py b/langgraph_plugin/graph_api/langsmith_tracing/run_worker.py new file mode 100644 index 00000000..d15cbe88 --- /dev/null +++ b/langgraph_plugin/graph_api/langsmith_tracing/run_worker.py @@ -0,0 +1,37 @@ +"""Worker for the LangSmith tracing sample (Graph API). + +Requires ANTHROPIC_API_KEY and LANGCHAIN_API_KEY environment variables. +""" + +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.langgraph import LangGraphPlugin +from temporalio.contrib.langsmith import LangSmithPlugin +from temporalio.worker import Worker + +from langgraph_plugin.graph_api.langsmith_tracing.workflow import ( + ChatWorkflow, + build_graph, +) + + +async def main() -> None: + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[LangSmithPlugin(add_temporal_runs=True)], + ) + + worker = Worker( + client, + task_queue="langgraph-langsmith", + workflows=[ChatWorkflow], + plugins=[LangGraphPlugin(graphs={"chat": build_graph()})], + ) + print("Worker started. Ctrl+C to exit.") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/langsmith_tracing/run_workflow.py b/langgraph_plugin/graph_api/langsmith_tracing/run_workflow.py new file mode 100644 index 00000000..3cae0417 --- /dev/null +++ b/langgraph_plugin/graph_api/langsmith_tracing/run_workflow.py @@ -0,0 +1,32 @@ +"""Start the LangSmith tracing chat workflow (Graph API). + +Requires ANTHROPIC_API_KEY and LANGCHAIN_API_KEY environment variables. +""" + +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.langsmith import LangSmithPlugin + +from langgraph_plugin.graph_api.langsmith_tracing.workflow import ChatWorkflow + + +async def main() -> None: + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[LangSmithPlugin(add_temporal_runs=True)], + ) + + result = await client.execute_workflow( + ChatWorkflow.run, + "What is the meaning of life?", + id="langsmith-chat-workflow", + task_queue="langgraph-langsmith", + ) + + print(f"Response: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/langgraph_plugin/graph_api/langsmith_tracing/workflow.py b/langgraph_plugin/graph_api/langsmith_tracing/workflow.py new file mode 100644 index 00000000..75beb93d --- /dev/null +++ b/langgraph_plugin/graph_api/langsmith_tracing/workflow.py @@ -0,0 +1,43 @@ +"""LangSmith tracing with LangGraph Graph API and Temporal. + +Demonstrates combining LangGraphPlugin (durable graph execution) with +LangSmithPlugin (observability) for full tracing of LLM calls through +Temporal workflows. + +Requires ANTHROPIC_API_KEY and LANGCHAIN_API_KEY environment variables. +""" + +from datetime import timedelta + +from langgraph.graph import START, StateGraph +from langsmith import traceable +from temporalio import workflow +from temporalio.contrib.langgraph import graph + +from langchain.chat_models import init_chat_model + + +@traceable(name="chat_activity", run_type="chain") +async def chat(message: str) -> str: + """Call an LLM to respond to the message. Traced by LangSmith.""" + response = await init_chat_model("claude-sonnet-4-6").ainvoke(message) + return response.content + + +def build_graph() -> StateGraph: + """Construct a single-node chat graph.""" + g = StateGraph(str) + g.add_node( + "chat", + chat, + metadata={"start_to_close_timeout": timedelta(seconds=30)}, + ) + g.add_edge(START, "chat") + return g + + +@workflow.defn +class ChatWorkflow: + @workflow.run + async def run(self, message: str) -> str: + return await graph("chat").compile().ainvoke(message)