diff --git a/CHANGELOG.md b/CHANGELOG.md index 72f1f90e3..bc180124d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,13 @@ to include examples, links to docs, or any other relevant information. ### Added +- `temporalio.contrib.deepagents` runs Deep Agents' `langchain-quickjs` code interpreter + in-workflow: the QuickJS REPL executes on the workflow event loop (upstream's dedicated + thread cannot wake the deterministic loop, which parked the workflow forever), a sub-agent + dispatched from JavaScript via `task()` gets its own `deepagents.invoke_model` Activities, + and the interpreter's modules pass through the sandbox. `langchain-quickjs` remains + optional; nothing is imported unless the workflow imports it. + - Added the `temporalio.contrib.gcp.cloud_run.id` module with the `CloudRunIdPlugin` client plugin to set the worker identity on Cloud Run. ### Changed diff --git a/pyproject.toml b/pyproject.toml index 2cbccee9f..44f0152ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,6 +98,7 @@ dev = [ "langgraph>=1.1.0", "langsmith>=0.7.34,<0.13", "deepagents>=0.7.12,<0.8; python_version >= '3.11'", + "langchain-quickjs>=0.3.5,<0.4; python_version >= '3.11'", "langchain>=1.3.11,<2; python_version >= '3.11'", "langchain-core>=1.4.8,<2; python_version >= '3.11'", "langchain-anthropic>=1.4.7; python_version >= '3.11'", diff --git a/temporalio/contrib/deepagents/README.md b/temporalio/contrib/deepagents/README.md index decae8b27..5697c792d 100644 --- a/temporalio/contrib/deepagents/README.md +++ b/temporalio/contrib/deepagents/README.md @@ -315,6 +315,29 @@ worker is unaffected, and the original function is restored when the worker stops. If you would rather be explicit, use `create_temporal_deep_agent` or pass `TemporalModel("provider:name")` yourself. +## Code interpreter (`langchain-quickjs`) + +Deep Agents' [code interpreter](https://docs.langchain.com/oss/python/deepagents/interpreters) +(`pip install "deepagents[quickjs]"`) runs inside the workflow: add +`CodeInterpreterMiddleware()` to `create_deep_agent(middleware=[...])` as usual. The +plugin runs the QuickJS VM on the workflow's own event loop (upstream hosts it on a +thread the deterministic loop cannot service) and passes `langchain_quickjs`, +`quickjs_rs`, `wasmtime`, and `bsdiff4` through the sandbox. `langchain-quickjs` stays +optional: nothing is imported unless your workflow imports it. + +What is durable: the JavaScript itself is workflow code and replays; a sub-agent +dispatched from JavaScript with `task(...)` runs in-workflow, so its model calls are +`deepagents.invoke_model` Activities like any other sub-agent's; a tool called from +JavaScript through PTC (`tools.(...)`) follows that tool's own Workflow-vs-Activity +choice above, so wrap I/O tools with `tool_as_activity`. + +Rules for the JavaScript, because it is workflow code: do not read the clock or +randomness — inside the VM `Date.now()` is wall-clock and `Math.random()` is seeded per +runtime, so both break replay; set the middleware's `timeout=` generously, since it is +wall-clock; and prefer `mode="turn"` — a `mode="thread"` heap snapshot lives in graph +state and is not carried across `run_deep_agent`'s continue-as-new. Upstream's own +caveat applies too: PTC and `task()` calls do not pass through `interrupt_on` approval. + ## Composing with other plugins This plugin carries no tracing context of its own. For observability, compose it diff --git a/temporalio/contrib/deepagents/_plugin.py b/temporalio/contrib/deepagents/_plugin.py index 3b95fcdaf..fcefd8c0b 100644 --- a/temporalio/contrib/deepagents/_plugin.py +++ b/temporalio/contrib/deepagents/_plugin.py @@ -205,9 +205,16 @@ async def _run_context(self) -> AsyncIterator[None]: # Installed for the life of the process, never uninstalled — see # _install_langsmith_temporal_override for why. _install_langsmith_temporal_override() + # No-op unless quickjs-rs (the langchain-quickjs code interpreter's VM) + # is installed; see _quickjs for why its worker thread cannot be used + # from a workflow. + from temporalio.contrib.deepagents import _quickjs + + _quickjs.install_quickjs_inline_patch() try: yield finally: + _quickjs.uninstall_quickjs_inline_patch() if patched: # Import is cached: patched=True implies the import above succeeded. from temporalio.contrib.deepagents import _model, _tools diff --git a/temporalio/contrib/deepagents/_quickjs.py b/temporalio/contrib/deepagents/_quickjs.py new file mode 100644 index 000000000..837eec1e0 --- /dev/null +++ b/temporalio/contrib/deepagents/_quickjs.py @@ -0,0 +1,87 @@ +"""In-workflow execution of the ``langchain-quickjs`` code interpreter. + +``langchain_quickjs.CodeInterpreterMiddleware`` gives a Deep Agent an ``eval`` +tool that runs model-written JavaScript in a QuickJS VM. Upstream hosts that VM +on a dedicated OS thread per LangGraph thread +(``quickjs_rs.threading.ThreadWorker``) and hands results back to the caller's +loop through ``asyncio.wrap_future`` — that is, ``call_soon_threadsafe``. The +deterministic workflow event loop neither implements that nor runs outside an +activation, so an unmodified ``eval`` parks the workflow forever: no failure, +no deadlock report, the execution just never wakes up. + +Nothing about the REPL needs the thread. ``quickjs_rs`` drives the VM +cooperatively on whatever loop awaits it, and the middleware's ``task()`` / +``tools.*`` bridges already run their callbacks directly when the calling loop +is the loop that invoked ``eval``. So inside a workflow the worker's hops are +made inline: JavaScript runs as workflow code, a sub-agent dispatched from +JavaScript runs in-workflow (its model calls are ``deepagents.invoke_model`` +activities like any other sub-agent's), and a PTC tool call follows the tool's +own Workflow-vs-Activity wrapping. Outside a workflow upstream behavior is +untouched, and when ``quickjs_rs`` is not installed there is nothing to patch. +""" + +from __future__ import annotations + +import importlib +from typing import Any + +from temporalio import workflow + +_originals: dict[str, Any] = {} + + +def install_quickjs_inline_patch() -> None: + """Run ``quickjs_rs`` worker hops inline while in a workflow. Idempotent.""" + try: + threading_mod = importlib.import_module("quickjs_rs.threading") + except ImportError: + return + if _originals: + return + worker_cls = threading_mod.ThreadWorker + orig_run_sync = worker_cls.run_sync + orig_run_async = worker_cls.run_async + orig_ensure_started = worker_cls._ensure_started + + def run_sync(self: Any, coro: Any) -> Any: + if not workflow.in_workflow(): + return orig_run_sync(self, coro) + # The REPL's synchronous hops (context creation, snapshot, close) never + # suspend; drive the coroutine to completion right here. + try: + coro.send(None) + except StopIteration as done: + return done.value + coro.close() + raise RuntimeError( + "quickjs-rs REPL work suspended on the synchronous in-workflow path" + ) + + async def run_async(self: Any, coro: Any) -> Any: + if not workflow.in_workflow(): + return await orig_run_async(self, coro) + return await coro + + def ensure_started(self: Any) -> None: + if workflow.in_workflow(): + return + orig_ensure_started(self) + + _originals.update( + run_sync=orig_run_sync, + run_async=orig_run_async, + _ensure_started=orig_ensure_started, + ) + worker_cls.run_sync = run_sync + worker_cls.run_async = run_async + worker_cls._ensure_started = ensure_started + + +def uninstall_quickjs_inline_patch() -> None: + """Restore ``quickjs_rs``'s thread-based worker hops.""" + if not _originals: + return + worker_cls = importlib.import_module("quickjs_rs.threading").ThreadWorker + for name, original in _originals.items(): + setattr(worker_cls, name, original) + _originals.clear() diff --git a/temporalio/contrib/deepagents/_serde.py b/temporalio/contrib/deepagents/_serde.py index 13ed0d1c6..6bbcdc0cd 100644 --- a/temporalio/contrib/deepagents/_serde.py +++ b/temporalio/contrib/deepagents/_serde.py @@ -383,6 +383,12 @@ def cache_put(key: str, value: Any) -> None: "langchain_anthropic", "langgraph", "deepagents", + # The langchain-quickjs code interpreter and its VM; a name-only allowlist, + # so nothing here is imported unless the workflow imports it. + "langchain_quickjs", + "quickjs_rs", + "wasmtime", + "bsdiff4", "langsmith", "numpy", "pydantic", diff --git a/tests/contrib/deepagents/test_quickjs_interpreter.py b/tests/contrib/deepagents/test_quickjs_interpreter.py new file mode 100644 index 000000000..0ca555467 --- /dev/null +++ b/tests/contrib/deepagents/test_quickjs_interpreter.py @@ -0,0 +1,171 @@ +"""The ``langchain-quickjs`` code interpreter runs in-workflow with durable bridges. + +The middleware's ``eval`` tool runs model-written JavaScript in a QuickJS VM. +Upstream hosts the VM on its own thread and wakes the caller through +``call_soon_threadsafe``, which the workflow event loop cannot service: without +the plugin's inline patch the workflow parks forever after the first model +call. With it, JavaScript is workflow code, a sub-agent dispatched from +JavaScript via ``task()`` runs in-workflow (so its model call is an +``invoke_model`` activity), and a PTC tool wrapped with ``tool_as_activity`` +crosses as an ``invoke_tool`` activity. Both scenarios replay from history. +""" + +from __future__ import annotations + +import sys +import uuid +from datetime import timedelta + +import pytest + +from temporalio.testing import WorkflowEnvironment + +pytestmark = pytest.mark.skipif( + sys.version_info < (3, 11), reason="deepagents requires Python >= 3.11" +) +pytest.importorskip("deepagents") +pytest.importorskip("langchain_core") +pytest.importorskip("langchain_quickjs") + +from temporalio import workflow # noqa: E402 +from temporalio.worker import Replayer, Worker # noqa: E402 +from tests.contrib.deepagents.helpers import count_scheduled_activities # noqa: E402 + +# Bind deepagents symbols off the module importorskip returns: a static +# `from deepagents import ...` cannot resolve on Python 3.10 (deepagents +# needs >= 3.11), and with the package absent the type checkers mis-resolve +# the name against this same-named test directory. +create_deep_agent = pytest.importorskip("deepagents").create_deep_agent +CodeInterpreterMiddleware = pytest.importorskip( + "langchain_quickjs" +).CodeInterpreterMiddleware + +with workflow.unsafe.imports_passed_through(): + from langchain_core.messages import AIMessage + + from temporalio.contrib.deepagents import DeepAgentsPlugin, tool_as_activity + from temporalio.contrib.deepagents.testing import MockTool, mock_model_provider + +INVOKE_MODEL = "deepagents.invoke_model" +INVOKE_TOOL = "deepagents.invoke_tool" + +# One eval: a PTC tool call, then a sub-agent dispatched from JavaScript. +_JS = ( + 'const found = await tools.lookup({q: "x"}); ' + 'const summary = await task({description: "Summarize", subagentType: "researcher"}); ' + "`${found}|${summary}`" +) + + +@workflow.defn +class InterpreterWorkflow: + @workflow.run + async def run(self, question: str) -> str: + lookup = tool_as_activity( + MockTool(name="lookup", description="Look up q.", result="looked-up"), + start_to_close_timeout=timedelta(seconds=10), + ) + agent = create_deep_agent( + model="anthropic:claude-sonnet-4-5", + system_prompt="You coordinate.", + tools=[lookup], + subagents=[ + { + "name": "researcher", + "description": "Researches.", + "system_prompt": "You research.", + } + ], + middleware=[CodeInterpreterMiddleware(ptc=["lookup"])], + ) + result = await agent.ainvoke( + {"messages": [{"role": "user", "content": question}]} + ) + # The eval tool's result carries what crossed back through JavaScript. + return str(result["messages"][-2].content) + + +def _plugin() -> DeepAgentsPlugin: + # Main agent asks for one eval; the sub-agent answers; the main agent finishes. + return DeepAgentsPlugin( + model_provider=mock_model_provider( + [ + AIMessage( + content="", + tool_calls=[{"name": "eval", "args": {"code": _JS}, "id": "c1"}], + ), + "Researcher findings.", + "Final answer.", + ] + ), + ) + + +async def _run_and_replay(env: WorkflowEnvironment, **worker_kwargs: object) -> None: + plugin = _plugin() + task_queue = f"da-quickjs-{uuid.uuid4()}" + async with Worker( + env.client, + task_queue=task_queue, + workflows=[InterpreterWorkflow], + plugins=[plugin], + **worker_kwargs, # type: ignore[arg-type] + ): + handle = await env.client.start_workflow( + InterpreterWorkflow.run, + "Go", + id=f"da-quickjs-{uuid.uuid4()}", + task_queue=task_queue, + execution_timeout=timedelta(seconds=60), + ) + out = await handle.result() + history = await handle.fetch_history() + + assert out == "looked-up|Researcher findings." + counts = await count_scheduled_activities(handle) + # main -> eval, the sub-agent dispatched from JavaScript, main -> final. + assert counts[INVOKE_MODEL] == 3, counts + # The PTC call reached the tool_as_activity wrapper, not the tool body. + assert counts[INVOKE_TOOL] == 1, counts + + # The JavaScript re-executes on replay against the recorded activity results. + await Replayer(workflows=[InterpreterWorkflow], plugins=[plugin]).replay_workflow( + history + ) + + +@pytest.mark.asyncio +async def test_interpreter_runs_in_workflow_with_durable_bridges( + env: WorkflowEnvironment, +) -> None: + await _run_and_replay(env) + + +@pytest.mark.asyncio +async def test_interpreter_survives_cache_eviction(env: WorkflowEnvironment) -> None: + # Every activation replays from scratch, so the eval (which spans a tool + # activity and a sub-agent's model activity) is re-driven several times. + await _run_and_replay(env, max_cached_workflows=0) + + +def test_inline_patch_is_inert_outside_workflows() -> None: + # Activities and clients in the same process keep upstream's thread-hosted + # VM; only in-workflow calls run inline. + from quickjs_rs.threading import ThreadWorker + + from temporalio.contrib.deepagents import _quickjs + + _quickjs.install_quickjs_inline_patch() + try: + + async def probe() -> str: + return "ran" + + worker = ThreadWorker(name="probe") + try: + assert worker.run_sync(probe()) == "ran" + assert worker._thread is not None, "expected upstream's worker thread" + finally: + worker.close() + finally: + _quickjs.uninstall_quickjs_inline_patch() diff --git a/uv.lock b/uv.lock index 7562ad66a..a6e41f354 100644 --- a/uv.lock +++ b/uv.lock @@ -475,6 +475,76 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f5/2e/68781b78e764e5ccc4af1e3d27e060069c73af90234853fa80000e7ee79d/bracex-3.0-py3-none-any.whl", hash = "sha256:3833e61c2f092d5aa0468fa2e6c6e990a306185abf763b6d122f0158e59c58a5", size = 11738, upload-time = "2026-06-30T00:43:34.196Z" }, ] +[[package]] +name = "bsdiff4" +version = "1.2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/b9/4559ede9a4c8c4451688303544da84654643fdc7f28790aca85be80b4b7c/bsdiff4-1.2.6.tar.gz", hash = "sha256:2ab57d01a78b39e29e5accc9cfead4130982ded9dccbc4261bd0e9c51d6b751d", size = 13259, upload-time = "2025-02-19T17:42:33.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/e3/61c89b6fa5594ec5453b62aae8814c5c49d74eac5897ce939fa44cbb6d2b/bsdiff4-1.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5af4fe780e859491beaf641e34c0e965f5f65fcd96b2d7860ca297b3fc91a53", size = 16213, upload-time = "2025-02-19T17:39:31.121Z" }, + { url = "https://files.pythonhosted.org/packages/2a/4f/43b5c2ce34ab614e8fa8aaa2f00336e1ab33b1219aa619117cfe22235762/bsdiff4-1.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:139d4a4a3eef2c6bb85ce5e18de27a0ebae11eacac3b3ff4423986f13a21c375", size = 16034, upload-time = "2025-02-19T17:39:33.17Z" }, + { url = "https://files.pythonhosted.org/packages/ad/f6/45a31bbe00da13a2d6371cdbee03f3f68a9f19e98c66cb8d38acf115409d/bsdiff4-1.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab903d1a7f3158d77a139fc42540c52b778510158337daf81bbd06b18ad2cd9b", size = 32012, upload-time = "2025-02-19T17:39:35.374Z" }, + { url = "https://files.pythonhosted.org/packages/88/9a/563f3060b17abac1056938383578017bb7dec6a7316bc52a281c39b3cb88/bsdiff4-1.2.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bce6c2ab32c7fa53f971c05ca5f8428408efc7f87527a84c7e62f32a4d6d2d4d", size = 34072, upload-time = "2025-02-19T17:39:37.241Z" }, + { url = "https://files.pythonhosted.org/packages/e0/8d/5657d9c1034bb9c5fdc2a962d863993a3c98a57bc8577b319c8c6f53a9bb/bsdiff4-1.2.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:899aec9c1c2fe23d143563af9aa9ccda5c79166886f58263a96f3fe89eb1ad3b", size = 32000, upload-time = "2025-02-19T17:39:38.478Z" }, + { url = "https://files.pythonhosted.org/packages/f5/56/7e0c3fdf6f06b84cc0282900f468a32f3367b533f343d22b5e9fc934f16b/bsdiff4-1.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07ec6b37098aa1abef8b1ce7132925ba79755581dddfb7fd86c6226a7302877", size = 31485, upload-time = "2025-02-19T17:39:41.404Z" }, + { url = "https://files.pythonhosted.org/packages/e0/5e/c97119ad48eaac1fc18a385fe77319d54148af0e269e2fc3e70e93bba80e/bsdiff4-1.2.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6be63ba562c94a3b4b1e3ff1e2b264da34be9dc1e9cd997875bfe11851045f75", size = 34280, upload-time = "2025-02-19T17:39:43.084Z" }, + { url = "https://files.pythonhosted.org/packages/b4/d1/be25015a4f53f719cc79cec50549ec901d285aa0efdd32912a2a8b172722/bsdiff4-1.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7d3c163daa68218a2ee8e6fa462c2748e7a85831c768600b206e0b16efcf7a47", size = 32047, upload-time = "2025-02-19T17:39:44.277Z" }, + { url = "https://files.pythonhosted.org/packages/6f/b4/d39b5ab00bee25f603d4ba8a1da3f5d0843dfb50b1faffd8bb6e2b741da6/bsdiff4-1.2.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b8ee881d162dd8a5f0c75f6b79547fddafc63ae713b852cef04f9358c9d8cc1e", size = 35589, upload-time = "2025-02-19T17:39:45.381Z" }, + { url = "https://files.pythonhosted.org/packages/d1/8f/f282fafeb986708c10608f19ed54fbae98d476d473f79dfb2967f346aa36/bsdiff4-1.2.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ed07a0ffa04758965680ed5307ea1a2c393740b44b03f4de6938b316847e6f8b", size = 34109, upload-time = "2025-02-19T17:39:46.58Z" }, + { url = "https://files.pythonhosted.org/packages/9d/fd/c37ab67951f5cda29e8e8c9dc26ff2d9a894aaa2942a378e8aca930083c8/bsdiff4-1.2.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bf055ebf32fffe93e9f803b8c9e5c13ddec4722bef970004815aedee85ebb7bd", size = 33629, upload-time = "2025-02-19T17:39:47.65Z" }, + { url = "https://files.pythonhosted.org/packages/dc/4b/a123309c61b89055d9bf19c9cff9baaf2da97a4d1c7fd7a6985da333d008/bsdiff4-1.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:661e3c2ad174bfef21c53bc9eb28e221c9eb1a5fc68637f45e1d49c2778dd46a", size = 31186, upload-time = "2025-02-19T17:39:49.605Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b5/3ac6340d1331af194063acb38071401815dc7a7e210822207504b469697e/bsdiff4-1.2.6-cp310-cp310-win32.whl", hash = "sha256:bacc5460c473b4ef6c09ccea16df2afd31b2860b9838edb870fed19bf4212d71", size = 18260, upload-time = "2025-02-19T17:39:50.679Z" }, + { url = "https://files.pythonhosted.org/packages/c2/89/e239c2a61b7751da63746c5f46f848f075ac5b4f8ed526d042389c49f280/bsdiff4-1.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:544234a2729c167c80f28804ef1deb4b82df8d35de0820ac30a540028c9c47d1", size = 19529, upload-time = "2025-02-19T17:39:52.444Z" }, + { url = "https://files.pythonhosted.org/packages/10/08/6472d5c2527688b16ad2c2dd09e324281f5e78eea5e4dba5f65a7949f39c/bsdiff4-1.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b151c28098b3c522b1735cdfe5e84e8f164f0ef4a592adb227d7a10727034673", size = 16212, upload-time = "2025-02-19T17:39:53.399Z" }, + { url = "https://files.pythonhosted.org/packages/33/41/4d1fa5980c01faa0d5c578e41ce73b4df98cd74e33f92323880df0da035e/bsdiff4-1.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:29def064f6bcd13d0d7a82e5caa4848158b7f49c3a8fe44fbef3031456fb7dd2", size = 16031, upload-time = "2025-02-19T17:39:54.481Z" }, + { url = "https://files.pythonhosted.org/packages/9e/41/188f858a71eb529145b6706f8ac618fd9f719807f46e0cebe2ea482bfe78/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f4cf8e00116e14e9e6c3fb5747478022a27215a9a65ed223fed82d2cfbc4d3", size = 33763, upload-time = "2025-02-19T17:39:55.438Z" }, + { url = "https://files.pythonhosted.org/packages/27/ea/84cc364a0c0f6eb3e503bf1625aa62eb411aa7474d1c91ec201812295fcb/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:897a260d30acc4df9803f500682eb7951fdc104a3e155787e1e581258f38df50", size = 35705, upload-time = "2025-02-19T17:39:56.601Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/c235fd3e95aa3a4ac53de83605723a149a33eb11aff64e49488132b857f8/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d994ee6113c3f030bb9f373e917f00db13c026c295fe9f314f23171935d88371", size = 33807, upload-time = "2025-02-19T17:39:57.601Z" }, + { url = "https://files.pythonhosted.org/packages/d2/8b/010d14d3ab321c1c35fc4145b020c1e76ed8a29a214ce6bcc093ddedee13/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba5028a2aaa8e4cacb224031af9140e05d9c407ba15b59471380badcc4845777", size = 33250, upload-time = "2025-02-19T17:39:58.552Z" }, + { url = "https://files.pythonhosted.org/packages/2c/91/ae41950f7b823e8061520f3b28d47534b47f314b4148690c4a002d764bd7/bsdiff4-1.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1edd3069dc14cecaa804faaae776a5d14f85217c41b3180b794e5fbf684d35dd", size = 35919, upload-time = "2025-02-19T17:40:00.052Z" }, + { url = "https://files.pythonhosted.org/packages/6c/b4/f29c451e7718d4366a72f9a87a7f3cc76cb56cb5e9305eae087eab83f7a0/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0fb562e451d5b3a7523c67ce04fe541d3a004914e5760a47116883972f5ff8bc", size = 33740, upload-time = "2025-02-19T17:40:01.893Z" }, + { url = "https://files.pythonhosted.org/packages/3a/73/004b3c4511df3df0d5e591ecd7aaf92c851b22be200283428d3577f4400b/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b7309380d8edbd3d46c4ed3930f7062b793bac8f004b32139db7af7c4612e241", size = 37325, upload-time = "2025-02-19T17:40:02.911Z" }, + { url = "https://files.pythonhosted.org/packages/d9/ea/5fa1d331c4a2e73e4e90a851768749a9960cefcb443da3abaae69e891f06/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f2f7504f08181227717fee04f25169d5901322c29d3fd054e4cb61bd60b3ffb4", size = 35791, upload-time = "2025-02-19T17:40:03.866Z" }, + { url = "https://files.pythonhosted.org/packages/10/04/7616e8abec54562c86742c7bacaaba53c0c4733565ea00e8c5ffe2c5c9ce/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6ad599216e7ee3db5737951d06c43b8e65d5b0db5c42300e85f18d399ec0bc5e", size = 35413, upload-time = "2025-02-19T17:40:05.692Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d6/3fff18a97e127cc783e02de3c934bca63fabc0d4a379e091973b006cbae6/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cd133a9475c9dfba6243dd07f118ee58a0b7f136c00d316e2d92d3f82169bd9e", size = 32939, upload-time = "2025-02-19T17:40:06.639Z" }, + { url = "https://files.pythonhosted.org/packages/36/32/2943637e17eca717cdd091625d4198cf7a49dd7d235944a86f1a8a6134fe/bsdiff4-1.2.6-cp311-cp311-win32.whl", hash = "sha256:403e8cc003451a8c4672c345a50aee3cf89d20983701e38fbbb67e07cb808c57", size = 18257, upload-time = "2025-02-19T17:40:07.59Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f8/83f087ab62bebde26956f084ab272e19d11db5df6700f4f48d29647235fd/bsdiff4-1.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:164a059e1e07932f91d90471a4ef4dac749f2dee780f08501522805398b32ed8", size = 19530, upload-time = "2025-02-19T17:40:08.504Z" }, + { url = "https://files.pythonhosted.org/packages/9a/58/044dd110fb0a0160f5cacecbfb9904043c8179f8c14093e22b6d8c6b9391/bsdiff4-1.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:69c5052e94ad991c397b5a46f8eab42f2e256c42aa5677896b7a3ea9e3d06adc", size = 16267, upload-time = "2025-02-19T17:40:10.376Z" }, + { url = "https://files.pythonhosted.org/packages/37/a1/70b74154344486bac9bf438ec309ae502f07df8cd7ca713d58f658769ff4/bsdiff4-1.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:223ae0fc9f386dcf919a09a2029c391a0f0afaf4a5892b9a6e1b622bf42e1ae5", size = 16090, upload-time = "2025-02-19T17:40:11.334Z" }, + { url = "https://files.pythonhosted.org/packages/1a/90/36531261d8a150fcb8193fe2ad46d939b8a91549976424852f6a2a335689/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48ea2298a281068d82b78454ee58ac7306ed38c9af55afddb04cf796df932d63", size = 33675, upload-time = "2025-02-19T17:40:13.218Z" }, + { url = "https://files.pythonhosted.org/packages/4a/97/8b73b3684c63e88508ad308229f33a8a5be6c4762e4160f96e2a6fc46906/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2534e286ef5ae58767b9b17be64742424ca1e52ec748b0d8f8e24eecd12bc28a", size = 35648, upload-time = "2025-02-19T17:40:14.296Z" }, + { url = "https://files.pythonhosted.org/packages/52/39/0b1dd6494c743fa2c62bd7c35f5dec9f5802d01c1da1ef75a2e20a481ed4/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff079b0f4cf874af4b6816983557b6b9d45996f88736046653e2d2311fa1876", size = 33772, upload-time = "2025-02-19T17:40:15.341Z" }, + { url = "https://files.pythonhosted.org/packages/88/23/98fc7482f957602c611203a9e485b9dbf4caf9d918e92453e3729cf5f0b4/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56c2728c96d1d4eb8e089e4797c018a56be3f905f440fb507773f44c567fcd38", size = 33238, upload-time = "2025-02-19T17:40:16.343Z" }, + { url = "https://files.pythonhosted.org/packages/75/04/c3db957b7a324a3f25f721a82c288e9abe60059a0a2d2f9b3c19fb49cdb2/bsdiff4-1.2.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9deb9b3cdb4d327e43b8c7bd11ed3707587f1183b35fb8a4c06c4f34bce62c6a", size = 35889, upload-time = "2025-02-19T17:40:18.237Z" }, + { url = "https://files.pythonhosted.org/packages/c3/a8/73d2abfd98a33cd74a0fc491e527d734c222ae18b499a10689f3adbc8d5c/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87c67b06ac96af6171b774dc8c03d2bde70c67c6488078eff44e0af4864acf6", size = 33606, upload-time = "2025-02-19T17:40:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/6b/c3/713b3bb3711b62e51f6f67d6d9f63098e4d3a51d8b91e52c962f5c01a2b7/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04bb2948301ad48123d308bf2342c83cae81d7edb52d11bdde00266d89ca071e", size = 37211, upload-time = "2025-02-19T17:40:22.365Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c5/40559695ea0bd3332c37ef8182fc0f96ceed838ae6b03ca9ddcd8cf0f7df/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:43649a44fc21f017be902e19ccf7fb8bac6ef2d7f93d871bbc6bc49acec9ffee", size = 35750, upload-time = "2025-02-19T17:40:23.554Z" }, + { url = "https://files.pythonhosted.org/packages/bb/9b/eb4683896119ec9d26d1eb3f12efc0d8a902451f4025db12c21c5a82992a/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:baa76ec557dc48847c3ed1ff5720b5095c439c868f7568da30dcabbabceb2b92", size = 35364, upload-time = "2025-02-19T17:40:24.485Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ad/0968b67aecf00873e0e5c07e97ba2300594505d4dbce62702b9f56a62d66/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:701168e2931da777e6e72ae17f22eb519e9ce25ec5108d149c9da7b3b80e1184", size = 32831, upload-time = "2025-02-19T17:40:25.571Z" }, + { url = "https://files.pythonhosted.org/packages/6c/18/adfcf72780f19cea1fe9948cbfb49890599424e94c752bf7d614093c0fc5/bsdiff4-1.2.6-cp312-cp312-win32.whl", hash = "sha256:f9f2e5e716d35af3252f69a15afc2b166970c98596a1114af4c6d2834fe8e871", size = 18308, upload-time = "2025-02-19T17:40:26.571Z" }, + { url = "https://files.pythonhosted.org/packages/9d/5d/31672172bb4566c1f1187fa28a1437125d4b5106bc55f9f7b9a75371094c/bsdiff4-1.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:0b29568d1e33e32ea075c12a696b32e4d6cea344d0270a2292075254efd86014", size = 19553, upload-time = "2025-02-19T17:40:27.592Z" }, + { url = "https://files.pythonhosted.org/packages/4f/56/887d90b0e52ce7b5533a6f1390ab9a68215a70ba34848441730e215ffc1c/bsdiff4-1.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a98d7975a670fc360d894ef2ec00294e6b7b19790c58457e40c8a5d57a1865b0", size = 16260, upload-time = "2025-02-19T17:40:28.614Z" }, + { url = "https://files.pythonhosted.org/packages/d8/4c/825a16932605d305501ed144ae5567a3dc90c9164a393c61cc0ed68df3f0/bsdiff4-1.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ee4417341712a4bf736694ce9ad3902b8c6fbd3425aadca44df9b66a51bbefa4", size = 16080, upload-time = "2025-02-19T17:40:29.612Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e2/0cf538a786f47b08e26f3970a6f98c2b7b9d555c01e085425282944a2c7f/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ddfa2137de44c9743a611d71d263d0cc8c45e5b18ee84ca5ff6b6240be1740", size = 33664, upload-time = "2025-02-19T17:40:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/1f/c0/44ac255f1d16865e39ef941470e30bb5c362dd216b62837bb13880d1dd36/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6474d8f34f89d25fa1803c639cc8ed49121752a56a15b4cd21e9267154cdaf70", size = 35648, upload-time = "2025-02-19T17:40:32.793Z" }, + { url = "https://files.pythonhosted.org/packages/cb/6b/d5871af38cbb8527652b65463c3dd736b6250828d8d6daf48be712a2ebfe/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8e9c876929c03ef5d448e2626e8b2961040c3a9f0dd3d483643dbccd0e7ff7a", size = 33792, upload-time = "2025-02-19T17:40:35.498Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1e/7027849a6dc02b580e352b1528899053bd919029b185fbaa14c6f268180b/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46313f0eb8f63efb54a3c4219cd7b5b8a7795012b535f9d0838fe3f2b3349849", size = 33238, upload-time = "2025-02-19T17:40:37.165Z" }, + { url = "https://files.pythonhosted.org/packages/97/df/c4a3e2bb1c1f9f09c2c5f8a9025c67f5ec7fcc8949338e54cb2d4fba9009/bsdiff4-1.2.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6b5757b1a83829f00ef34953c6865ea82e9c71126e465bc32d029c55da9e45b", size = 35866, upload-time = "2025-02-19T17:40:38.789Z" }, + { url = "https://files.pythonhosted.org/packages/83/03/76a5aaaa0ccc282b239b3f148f6dd6033d37f79c1d1a89846b712224d132/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:734552992ecc86749a8ef55d03f999f9a47576cc609d7d4d9a7aec274b43ee4d", size = 33688, upload-time = "2025-02-19T17:40:39.762Z" }, + { url = "https://files.pythonhosted.org/packages/b3/b3/b240d4840a16d923c60e8e9eacf0777cf9378e30610037f6c85324daea85/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:853c3221daac6f8d347f12eb0b73ca9dbb7db483e7b5f40b1e2fbb05730645a7", size = 37273, upload-time = "2025-02-19T17:40:41.626Z" }, + { url = "https://files.pythonhosted.org/packages/7d/84/2223a09c4950a3e419ce94eb0af6d90c1ee562b9962ef2d72515f4ad6271/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:94526dc11e56f330c2f4b1e2e9389b958a7891f6c86b5aac83bd9c7a90eb088a", size = 35844, upload-time = "2025-02-19T17:40:42.646Z" }, + { url = "https://files.pythonhosted.org/packages/18/7b/c02f703b449feb20b245eb803e7d446508b80d5b4065d1eb9cc75d02ae3b/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f5474e1d9253564ed0823e2685a403d9dfdbba3c7b70a80f5066d61427848253", size = 35418, upload-time = "2025-02-19T17:40:44.562Z" }, + { url = "https://files.pythonhosted.org/packages/eb/52/623ee28011b6935f0dfe67397ec27c2a900b9f0bda1b1ec2a5b174c53fb7/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5529731ac88151345a8bb76dad4fdb218af10a8a505161d1aa3d669e49cb7b77", size = 32892, upload-time = "2025-02-19T17:40:45.552Z" }, + { url = "https://files.pythonhosted.org/packages/44/6c/e740e347bb46ea08ceacf39df56c2ffd2bd20b95d458409ea303fbf2b946/bsdiff4-1.2.6-cp313-cp313-win32.whl", hash = "sha256:c8089827c41b37f7c9192492742289929097c5ab2a6b3a120919fee27fbc01b8", size = 18304, upload-time = "2025-02-19T17:40:47.37Z" }, + { url = "https://files.pythonhosted.org/packages/88/d1/9be6f6124afab9837db1ffc5801ca1aa86f2077d4224ff729e88fabada71/bsdiff4-1.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:37ff935ba714e0726584dad2bc4c063218b588b110115e8554ebc438ee7bccf3", size = 19543, upload-time = "2025-02-19T17:40:48.369Z" }, + { url = "https://files.pythonhosted.org/packages/4a/f3/8579894ec44ceae5e120b37fc18cc7fc24021f0fb2fe7c90f92fa9c3c7ab/bsdiff4-1.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:61f504f8ad04cc4f4aea06a56f81ba392fcfd58434b67210186772bc949f6b8d", size = 16223, upload-time = "2025-02-19T17:42:01.132Z" }, + { url = "https://files.pythonhosted.org/packages/bd/4f/4dce64c017702e0f16fde4cb79dbb5bf446d57135d3f76ebd4fb9fde55a9/bsdiff4-1.2.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e778f9e9e3df5f3ffdf82b338ceefa2a6fee3fd14366d50cde74dc849e083cbb", size = 15868, upload-time = "2025-02-19T17:42:02.902Z" }, + { url = "https://files.pythonhosted.org/packages/67/e5/6b7f12d45ac7cf9d842cafa2905262c78fe6ac43feca2439f9679267253a/bsdiff4-1.2.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e08bc23ca5425f72d2c87a66b6ac4e8d7765abe04ed9c8233b8cdb3ef1ee6808", size = 17483, upload-time = "2025-02-19T17:42:04.016Z" }, + { url = "https://files.pythonhosted.org/packages/88/9c/03a1bdb9c7804efa3dddb56987bcd5619f6f6c840e42c6d861ab4298e366/bsdiff4-1.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e986f6278d9f1dc124d9c67533d6dd1c93883b5d57ca54c4e224ec888613ab7", size = 16889, upload-time = "2025-02-19T17:42:05.634Z" }, + { url = "https://files.pythonhosted.org/packages/78/16/109ba98222911bc6163c15f4605e19043c94982b3364f64dc1ac563e6a79/bsdiff4-1.2.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94290de262cb823bb557860c20769e63fd20f3d29b1a31b8c69e4309f2fdede0", size = 17419, upload-time = "2025-02-19T17:42:07.448Z" }, + { url = "https://files.pythonhosted.org/packages/a1/da/407abc7404975c5c06926f036db77ea97f0031ede68249a8ad090fc3c8ab/bsdiff4-1.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9f246beea8dce9725b2ae17487059e488b213ea22e9df04170fca2dec9ac2f30", size = 19564, upload-time = "2025-02-19T17:42:08.482Z" }, +] + [[package]] name = "cachecontrol" version = "0.14.4" @@ -2111,6 +2181,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/2e/d82db9eec13ad0f72e7aaad5c4bc730ab111934fdc83c85523206eb9b0a0/langchain_protocol-0.0.18-py3-none-any.whl", hash = "sha256:70b53a86fbf9cedc863555effe44da192ab02d556ddbf2cf95b8873adcf41b5a", size = 7221, upload-time = "2026-06-18T17:08:25.996Z" }, ] +[[package]] +name = "langchain-quickjs" +version = "0.3.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bsdiff4" }, + { name = "deepagents" }, + { name = "langchain" }, + { name = "langchain-core", version = "1.6.1", source = { registry = "https://pypi.org/simple" } }, + { name = "langgraph", version = "1.2.11", source = { registry = "https://pypi.org/simple" } }, + { name = "quickjs-rs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cf/2a/45e376a9958c61537973458ad62b39c61a3f9e22cdf3598ea0b7b775a155/langchain_quickjs-0.3.5.tar.gz", hash = "sha256:4b4da850c71bb755af21a5cef46d599b0c0ad2dc78170a8399996ac32fc96435", size = 225157, upload-time = "2026-07-29T18:26:32.78Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/a1/bf460ae2009f76ec2fabd263ad202f6649c6ae6cb7429f0688c4239ff759/langchain_quickjs-0.3.5-py3-none-any.whl", hash = "sha256:288b276ea7dcc3cfac2b84b7fed1079ac076e1c682bc3e4e2c2ce31d20ea2d2c", size = 45509, upload-time = "2026-07-29T18:26:31.268Z" }, +] + [[package]] name = "langgraph" version = "1.2.9" @@ -4115,6 +4202,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] +[[package]] +name = "quickjs-rs" +version = "0.2.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wasmtime" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7f/dc/177301106aede96a709d5577127aaa090364d4abb8b4c4cfb87b12ae2c30/quickjs_rs-0.2.5.tar.gz", hash = "sha256:3ceb30fba27013108fac92f0a716d6a16980131ce5b13f9912848df1f1f2cf09", size = 830147, upload-time = "2026-07-24T20:29:26.377Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/1d/e4406d13ce9b9443dbfa59e2a2d5b3e11278ebe322b54de38ae18faf5436/quickjs_rs-0.2.5-py3-none-any.whl", hash = "sha256:e82240af1f1dd1b2e12bcf169a22a8e0e451e356f0688f2fc3bba886d9b2bb20", size = 801138, upload-time = "2026-07-24T20:29:24.194Z" }, +] + [[package]] name = "readme-renderer" version = "45.0" @@ -4879,6 +4978,7 @@ dev = [ { name = "langchain", marker = "python_full_version >= '3.11'" }, { name = "langchain-anthropic", marker = "python_full_version >= '3.11'" }, { name = "langchain-core", version = "1.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "langchain-quickjs", marker = "python_full_version >= '3.11'" }, { name = "langgraph", version = "1.2.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "langgraph", version = "1.2.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "langsmith" }, @@ -4964,6 +5064,7 @@ dev = [ { name = "langchain", marker = "python_full_version >= '3.11'", specifier = ">=1.3.11,<2" }, { name = "langchain-anthropic", marker = "python_full_version >= '3.11'", specifier = ">=1.4.7" }, { name = "langchain-core", marker = "python_full_version >= '3.11'", specifier = ">=1.4.8,<2" }, + { name = "langchain-quickjs", marker = "python_full_version >= '3.11'", specifier = ">=0.3.5,<0.4" }, { name = "langgraph", specifier = ">=1.1.0" }, { name = "langsmith", specifier = ">=0.7.34,<0.13" }, { name = "litellm", specifier = ">=1.83.0" }, @@ -5456,6 +5557,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/45/ec/dbb7e5a6b91f86bfb9eb7d2988a2730907b6a729875b949c7f022e8b88fa/uvicorn-0.51.0-py3-none-any.whl", hash = "sha256:5d38af6cd620f2ae3849fb44fd4879e0890aa1febe8d47eb355fb45d93fe6a5b", size = 73219, upload-time = "2026-07-08T10:59:04.44Z" }, ] +[[package]] +name = "wasmtime" +version = "48.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/42/1f/03a286dc84d83cc3274d5599543558442ba9332b676e6408ee9e1c171199/wasmtime-48.0.0.tar.gz", hash = "sha256:dba27d59209fac703e7d5753af78c2af2c1cd1ed735f520ec76dc31c60a05815", size = 128804, upload-time = "2026-08-20T19:31:57.29Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/e6/39da2f4047a281bce7d4651e21785942d630033931eb397cf734e7ccc048/wasmtime-48.0.0-py3-none-android_26_arm64_v8a.whl", hash = "sha256:a55abf132fe238b843a963c68cd1a30d8f686c1bc75d8fbf042d8b7a1d51ee36", size = 8800816, upload-time = "2026-08-20T19:31:28.761Z" }, + { url = "https://files.pythonhosted.org/packages/be/d0/f4f107166a65ddf8a6d8cf74f0cea33c06a08c74fe686f8e83b194e57e8b/wasmtime-48.0.0-py3-none-android_26_x86_64.whl", hash = "sha256:d8e94276ff6c0c5ce73ee16ccbacb00b3512a4b3a664749380705d81ee06a23c", size = 9731711, upload-time = "2026-08-20T19:31:31.905Z" }, + { url = "https://files.pythonhosted.org/packages/95/15/20fad0cb2b9cff130c225bf827e16365e02883f504297eccf172c6bb7228/wasmtime-48.0.0-py3-none-any.whl", hash = "sha256:49c9ee43e9cf59ad7453ac65dce0cc4b885837904dd3cfd45faafe930defe14a", size = 8157926, upload-time = "2026-08-20T19:31:34.74Z" }, + { url = "https://files.pythonhosted.org/packages/89/93/911434c6c4406e6979b6cb67ba889c85633ff8d92eb0cb569fec6e2a43f7/wasmtime-48.0.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:50e1ea81a3bec537d00e076722dfdc48978a56ea24619d8153aa1f75b11796b9", size = 9395773, upload-time = "2026-08-20T19:31:37.312Z" }, + { url = "https://files.pythonhosted.org/packages/dc/a6/91c9c19ed7f8e164f4db6405d872c9397be9f53e4f325d0adcd5e67598f4/wasmtime-48.0.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ea69889a3c51702e9da5f5f441027ca934f7758f8926a4ed167b0d6877f092e8", size = 8343024, upload-time = "2026-08-20T19:31:39.922Z" }, + { url = "https://files.pythonhosted.org/packages/a2/92/e144fcf578fc394678c24b042efe45f3b0614acdb87ea95d8b839b208842/wasmtime-48.0.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:58544d539053dff7bd4cf30c40d7a540862d683013c0dfa6ba46a063f5b682f7", size = 9796354, upload-time = "2026-08-20T19:31:42.325Z" }, + { url = "https://files.pythonhosted.org/packages/1c/c3/a957b226979daaeb09ec024562e9aac05e475a954537e6f150eb60bca84d/wasmtime-48.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:26fce3613fefbe29a28e9d659dca3326e800593858e5758cad086eb802b3b766", size = 8734885, upload-time = "2026-08-20T19:31:44.966Z" }, + { url = "https://files.pythonhosted.org/packages/cf/bf/00e44d1971307620d6660760ed04796405a5fb1819c8b43ec03ad85efac6/wasmtime-48.0.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:77f6b75db20be065e205e7af814d4e4f06784c3a00eb346e8c76148ecb4afe5a", size = 8786289, upload-time = "2026-08-20T19:31:47.99Z" }, + { url = "https://files.pythonhosted.org/packages/8c/55/ce68af7734a5a9424dd66a301b11c810215ec7f70230b35bed10ed312e97/wasmtime-48.0.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:62b241c8d5dfb59ff8af1ccaa5351f0ab7aba8cc872f7d80e0e3c95d54c13562", size = 9889697, upload-time = "2026-08-20T19:31:50.854Z" }, + { url = "https://files.pythonhosted.org/packages/9d/12/5266bebece874ebfa3196c973b917091dd4c55e9e9da55401e312c403044/wasmtime-48.0.0-py3-none-win_amd64.whl", hash = "sha256:21fa500e70f3819a8c0539c3f0be6b3b81ec3c630bb90c47dba4d8a2c1d4c698", size = 8157931, upload-time = "2026-08-20T19:31:53.312Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a4/bb6c90d99ad893bd42f33aa7fb386deecb55987f012c0c2f5fcaba83106d/wasmtime-48.0.0-py3-none-win_arm64.whl", hash = "sha256:09cd5e14df80a3a8d447428a548583181c568ea2e617419d23600deff21d4b82", size = 7044651, upload-time = "2026-08-20T19:31:55.63Z" }, +] + [[package]] name = "watchdog" version = "6.0.0"