From e9b2b20cedc8b25a3a306fdee7e217c89af81e84 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:37:42 -0800 Subject: [PATCH 01/19] feat: Integrate MCP Apps into A2UI - Adds McpAppsCustomComponent using the official @modelcontextprotocol/ext-apps SDK. - Implements double-iframe sandbox isolation (sandbox.html, sandbox.ts). - Upgrades the backend MCP server (floor_plan_server.py) to a persistent SSE architecture using Starlette. - Configures agent.py to connect via mcp.client.sse. - Refines Vite configuration for seamless dual-origin local development. --- .../adk/contact_multiple_surfaces/agent.py | 129 +- .../floor_plan_server.py | 299 ++ .../contact_multiple_surfaces/pyproject.toml | 4 + samples/agent/adk/uv.lock | 2599 +++++++++-------- samples/client/lit/contact/.env.example | 18 + samples/client/lit/contact/package.json | 1 + samples/client/lit/contact/sandbox.html | 37 + .../custom-components/mcp-apps-component.ts | 208 ++ .../custom-components/register-components.ts | 15 + samples/client/lit/contact/ui/sandbox.ts | 107 + samples/client/lit/contact/vite.config.ts | 4 + samples/client/lit/package-lock.json | 1328 ++++++++- 12 files changed, 3433 insertions(+), 1316 deletions(-) create mode 100644 samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py create mode 100644 samples/client/lit/contact/.env.example create mode 100644 samples/client/lit/contact/sandbox.html create mode 100644 samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts create mode 100644 samples/client/lit/contact/ui/sandbox.ts diff --git a/samples/agent/adk/contact_multiple_surfaces/agent.py b/samples/agent/adk/contact_multiple_surfaces/agent.py index fdc98e9cf..4c755ce84 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent.py @@ -231,16 +231,131 @@ async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: if query.startswith("ACTION:") and "view_location" in query: logger.info("--- ContactAgent.stream: Detected view_location ACTION ---") - # Use the predefined example floor plan - json_content = load_floor_plan_example().strip() - start_idx = json_content.find("[") - end_idx = json_content.rfind("]") - if start_idx != -1 and end_idx != -1: - json_content = json_content[start_idx : end_idx + 1] + from mcp import ClientSession + from mcp.client.sse import sse_client + + try: + # Connect to the persistent Starlette SSE server + async with sse_client("http://127.0.0.1:8000/sse") as (read, write): + async with ClientSession(read, write) as mcp_session: + await mcp_session.initialize() + + logger.info("--- ContactAgent: Fetching ui://floor-plan-server/map from persistent SSE server ---") + result = await mcp_session.read_resource("ui://floor-plan-server/map") + + if not result.contents or len(result.contents) == 0: + raise ValueError("No content returned from floor plan server") + + html_content = result.contents[0].text + except Exception as e: + logger.error(f"Failed to fetch floor plan from SSE server: {e}") + yield { + "is_task_complete": True, + "content": f"Failed to load floor plan: {str(e)}" + } + return + + json_content = [ + { + "beginRendering": { + "surfaceId": "location-surface", + "root": "floor-plan-card" + } + }, + { + "surfaceUpdate": { + "surfaceId": "location-surface", + "components": [ + { + "id": "floor-plan-card", + "component": { + "Card": { + "child": "floor-plan-col" + } + } + }, + { + "id": "floor-plan-col", + "component": { + "Column": { + "children": { + "explicitList": [ + "floor-plan-title", + "floor-plan-comp", + "dismiss-fp" + ] + } + } + } + }, + { + "id": "floor-plan-title", + "component": { + "Text": { + "usageHint": "h2", + "text": { + "literalString": "Office Floor Plan" + } + } + } + }, + { + "id": "floor-plan-comp", + "component": { + "McpAppsCustomComponent": { + "htmlContent": html_content, + "height": 400, + "allowedTools": [ + "chart_node_click" + ] + } + } + }, + { + "id": "dismiss-fp-text", + "component": { + "Text": { + "text": { + "literalString": "Close Map" + } + } + } + }, + { + "id": "dismiss-fp", + "component": { + "Button": { + "child": "dismiss-fp-text", + "action": { + "name": "close_modal", + "context": [] + } + } + } + } + ] + } + } + ] logger.info(f"--- ContactAgent.stream: Sending Floor Plan ---") final_response_content = ( - f"Here is the floor plan.\n---a2ui_JSON---\n{json_content}" + f"Here is the floor plan.\n---a2ui_JSON---\n{json.dumps(json_content)}" + ) + yield {"is_task_complete": True, "content": final_response_content} + return + + if query.startswith("ACTION:") and "close_modal" in query: + logger.info("--- ContactAgent.stream: Handling close_modal ACTION ---") + json_content = [ + { + "deleteSurface": { + "surfaceId": "location-surface" + } + } + ] + final_response_content = ( + f"Modal closed.\n---a2ui_JSON---\n{json.dumps(json_content)}" ) yield {"is_task_complete": True, "content": final_response_content} return diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py new file mode 100644 index 000000000..f1d219861 --- /dev/null +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py @@ -0,0 +1,299 @@ +import asyncio +from mcp.server import Server +from mcp.types import Resource, TextContent + +app = Server("floor-plan-server") + +RESOURCE_URI = "ui://floor-plan-server/map" +MIME_TYPE = "text/html;profile=mcp-app" + +@app.list_resources() +async def list_resources() -> list[Resource]: + return [ + Resource( + uri=RESOURCE_URI, + name="Interactive Floor Plan", + mimeType=MIME_TYPE, + description="A visual floor plan showing desk assignments." + ) + ] + +@app.read_resource() +async def read_resource(uri: str) -> str | bytes: + if str(uri) != RESOURCE_URI: + raise ValueError(f"Unknown resource: {uri}") + + html = """ + + + + + + Floor Plan + + + + +
+
+ Office Floor Plan +
+
+
+ + + +""" + return html + +import uvicorn +from starlette.applications import Starlette +from starlette.requests import Request +from starlette.responses import Response +from starlette.routing import Mount, Route +from mcp.server.sse import SseServerTransport + +sse = SseServerTransport("/messages/") + +async def handle_sse(request: Request): + """Handle the initial SSE connection from the A2UI agent.""" + async with sse.connect_sse( + request.scope, request.receive, request._send + ) as streams: + await app.run( + streams[0], + streams[1], + app.create_initialization_options() + ) + return Response() + +starlette_app = Starlette( + routes=[ + Route("/sse", endpoint=handle_sse, methods=["GET"]), + Mount("/messages/", app=sse.handle_post_message), + ] +) + +if __name__ == "__main__": + uvicorn.run(starlette_app, host="127.0.0.1", port=8000) diff --git a/samples/agent/adk/contact_multiple_surfaces/pyproject.toml b/samples/agent/adk/contact_multiple_surfaces/pyproject.toml index 44d33cff4..d0aa361b3 100644 --- a/samples/agent/adk/contact_multiple_surfaces/pyproject.toml +++ b/samples/agent/adk/contact_multiple_surfaces/pyproject.toml @@ -13,6 +13,10 @@ dependencies = [ "litellm", "jsonschema>=4.0.0", "a2ui-agent", + "mcp>=1.26.0", + "uvicorn>=0.40.0", + "starlette>=0.50.0", + "fastapi>=0.123.10", ] [tool.hatch.build.targets.wheel] diff --git a/samples/agent/adk/uv.lock b/samples/agent/adk/uv.lock index 0fb42d7e9..039306d68 100644 --- a/samples/agent/adk/uv.lock +++ b/samples/agent/adk/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.13" resolution-markers = [ "python_full_version >= '3.14'", @@ -29,9 +29,9 @@ dependencies = [ { name = "protobuf" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/a3/76f2d94a32a1b0dc760432d893a09ec5ed31de5ad51b1ef0f9d199ceb260/a2a_sdk-0.3.22.tar.gz", hash = "sha256:77a5694bfc4f26679c11b70c7f1062522206d430b34bc1215cfbb1eba67b7e7d", size = 231535, upload-time = "2025-12-16T18:39:21.19Z" } +sdist = { url = "https://files.pythonhosted.org/packages/92/a3/76f2d94a32a1b0dc760432d893a09ec5ed31de5ad51b1ef0f9d199ceb260/a2a_sdk-0.3.22.tar.gz", hash = "sha256:77a5694bfc4f26679c11b70c7f1062522206d430b34bc1215cfbb1eba67b7e7d", size = 231535, upload_time = "2025-12-16T18:39:21.19Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/e8/f4e39fd1cf0b3c4537b974637143f3ebfe1158dad7232d9eef15666a81ba/a2a_sdk-0.3.22-py3-none-any.whl", hash = "sha256:b98701135bb90b0ff85d35f31533b6b7a299bf810658c1c65f3814a6c15ea385", size = 144347, upload-time = "2025-12-16T18:39:19.218Z" }, + { url = "https://files.pythonhosted.org/packages/64/e8/f4e39fd1cf0b3c4537b974637143f3ebfe1158dad7232d9eef15666a81ba/a2a_sdk-0.3.22-py3-none-any.whl", hash = "sha256:b98701135bb90b0ff85d35f31533b6b7a299bf810658c1c65f3814a6c15ea385", size = 144347, upload_time = "2025-12-16T18:39:19.218Z" }, ] [[package]] @@ -95,11 +95,15 @@ dependencies = [ { name = "a2a-sdk" }, { name = "a2ui-agent" }, { name = "click" }, + { name = "fastapi" }, { name = "google-adk" }, { name = "google-genai" }, { name = "jsonschema" }, { name = "litellm" }, + { name = "mcp" }, { name = "python-dotenv" }, + { name = "starlette" }, + { name = "uvicorn" }, ] [package.metadata] @@ -107,11 +111,15 @@ requires-dist = [ { name = "a2a-sdk", specifier = ">=0.3.0" }, { name = "a2ui-agent", editable = "../../../a2a_agents/python/a2ui_agent" }, { name = "click", specifier = ">=8.1.8" }, + { name = "fastapi", specifier = ">=0.123.10" }, { name = "google-adk", specifier = ">=1.8.0" }, { name = "google-genai", specifier = ">=1.27.0" }, { name = "jsonschema", specifier = ">=4.0.0" }, { name = "litellm" }, + { name = "mcp", specifier = ">=1.26.0" }, { name = "python-dotenv", specifier = ">=1.1.0" }, + { name = "starlette", specifier = ">=0.50.0" }, + { name = "uvicorn", specifier = ">=0.40.0" }, ] [[package]] @@ -145,9 +153,9 @@ requires-dist = [ name = "aiohappyeyeballs" version = "2.6.1" 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" } +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" }, + { 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" }, ] [[package]] @@ -163,59 +171,59 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload-time = "2026-01-03T17:30:45.832Z" }, - { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload-time = "2026-01-03T17:30:47.466Z" }, - { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload-time = "2026-01-03T17:30:49.373Z" }, - { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload-time = "2026-01-03T17:30:50.974Z" }, - { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload-time = "2026-01-03T17:30:52.729Z" }, - { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload-time = "2026-01-03T17:30:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload-time = "2026-01-03T17:30:56.512Z" }, - { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload-time = "2026-01-03T17:30:58.256Z" }, - { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload-time = "2026-01-03T17:31:00.445Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload-time = "2026-01-03T17:31:03.024Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload-time = "2026-01-03T17:31:04.842Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload-time = "2026-01-03T17:31:06.868Z" }, - { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload-time = "2026-01-03T17:31:08.958Z" }, - { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload-time = "2026-01-03T17:31:10.676Z" }, - { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload-time = "2026-01-03T17:31:12.575Z" }, - { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload-time = "2026-01-03T17:31:14.382Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload-time = "2026-01-03T17:31:15.958Z" }, - { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238, upload-time = "2026-01-03T17:31:17.909Z" }, - { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292, upload-time = "2026-01-03T17:31:19.919Z" }, - { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021, upload-time = "2026-01-03T17:31:21.636Z" }, - { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263, upload-time = "2026-01-03T17:31:23.296Z" }, - { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107, upload-time = "2026-01-03T17:31:25.334Z" }, - { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196, upload-time = "2026-01-03T17:31:27.394Z" }, - { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591, upload-time = "2026-01-03T17:31:29.238Z" }, - { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277, upload-time = "2026-01-03T17:31:31.053Z" }, - { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575, upload-time = "2026-01-03T17:31:32.87Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455, upload-time = "2026-01-03T17:31:34.76Z" }, - { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417, upload-time = "2026-01-03T17:31:36.699Z" }, - { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968, upload-time = "2026-01-03T17:31:38.622Z" }, - { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690, upload-time = "2026-01-03T17:31:40.57Z" }, - { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390, upload-time = "2026-01-03T17:31:42.857Z" }, - { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188, upload-time = "2026-01-03T17:31:44.984Z" }, - { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126, upload-time = "2026-01-03T17:31:47.463Z" }, - { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128, upload-time = "2026-01-03T17:31:49.2Z" }, - { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512, upload-time = "2026-01-03T17:31:51.134Z" }, - { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444, upload-time = "2026-01-03T17:31:52.85Z" }, - { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798, upload-time = "2026-01-03T17:31:54.91Z" }, - { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835, upload-time = "2026-01-03T17:31:56.733Z" }, - { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486, upload-time = "2026-01-03T17:31:58.65Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951, upload-time = "2026-01-03T17:32:00.989Z" }, - { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001, upload-time = "2026-01-03T17:32:03.122Z" }, - { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246, upload-time = "2026-01-03T17:32:05.255Z" }, - { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131, upload-time = "2026-01-03T17:32:07.607Z" }, - { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196, upload-time = "2026-01-03T17:32:09.59Z" }, - { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841, upload-time = "2026-01-03T17:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193, upload-time = "2026-01-03T17:32:13.705Z" }, - { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979, upload-time = "2026-01-03T17:32:15.965Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193, upload-time = "2026-01-03T17:32:18.219Z" }, - { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload_time = "2026-01-03T17:33:05.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload_time = "2026-01-03T17:30:45.832Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload_time = "2026-01-03T17:30:47.466Z" }, + { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload_time = "2026-01-03T17:30:49.373Z" }, + { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload_time = "2026-01-03T17:30:50.974Z" }, + { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload_time = "2026-01-03T17:30:52.729Z" }, + { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload_time = "2026-01-03T17:30:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload_time = "2026-01-03T17:30:56.512Z" }, + { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload_time = "2026-01-03T17:30:58.256Z" }, + { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload_time = "2026-01-03T17:31:00.445Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload_time = "2026-01-03T17:31:03.024Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload_time = "2026-01-03T17:31:04.842Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload_time = "2026-01-03T17:31:06.868Z" }, + { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload_time = "2026-01-03T17:31:08.958Z" }, + { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload_time = "2026-01-03T17:31:10.676Z" }, + { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload_time = "2026-01-03T17:31:12.575Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload_time = "2026-01-03T17:31:14.382Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload_time = "2026-01-03T17:31:15.958Z" }, + { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238, upload_time = "2026-01-03T17:31:17.909Z" }, + { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292, upload_time = "2026-01-03T17:31:19.919Z" }, + { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021, upload_time = "2026-01-03T17:31:21.636Z" }, + { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263, upload_time = "2026-01-03T17:31:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107, upload_time = "2026-01-03T17:31:25.334Z" }, + { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196, upload_time = "2026-01-03T17:31:27.394Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591, upload_time = "2026-01-03T17:31:29.238Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277, upload_time = "2026-01-03T17:31:31.053Z" }, + { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575, upload_time = "2026-01-03T17:31:32.87Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455, upload_time = "2026-01-03T17:31:34.76Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417, upload_time = "2026-01-03T17:31:36.699Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968, upload_time = "2026-01-03T17:31:38.622Z" }, + { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690, upload_time = "2026-01-03T17:31:40.57Z" }, + { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390, upload_time = "2026-01-03T17:31:42.857Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188, upload_time = "2026-01-03T17:31:44.984Z" }, + { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126, upload_time = "2026-01-03T17:31:47.463Z" }, + { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128, upload_time = "2026-01-03T17:31:49.2Z" }, + { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512, upload_time = "2026-01-03T17:31:51.134Z" }, + { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444, upload_time = "2026-01-03T17:31:52.85Z" }, + { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798, upload_time = "2026-01-03T17:31:54.91Z" }, + { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835, upload_time = "2026-01-03T17:31:56.733Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486, upload_time = "2026-01-03T17:31:58.65Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951, upload_time = "2026-01-03T17:32:00.989Z" }, + { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001, upload_time = "2026-01-03T17:32:03.122Z" }, + { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246, upload_time = "2026-01-03T17:32:05.255Z" }, + { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131, upload_time = "2026-01-03T17:32:07.607Z" }, + { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196, upload_time = "2026-01-03T17:32:09.59Z" }, + { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841, upload_time = "2026-01-03T17:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193, upload_time = "2026-01-03T17:32:13.705Z" }, + { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979, upload_time = "2026-01-03T17:32:15.965Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193, upload_time = "2026-01-03T17:32:18.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload_time = "2026-01-03T17:32:20.25Z" }, + { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload_time = "2026-01-03T17:32:22.215Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload_time = "2026-01-03T17:32:24.546Z" }, ] [[package]] @@ -225,18 +233,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload_time = "2025-07-03T22:54:43.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload_time = "2025-07-03T22:54:42.156Z" }, ] [[package]] name = "aiosqlite" version = "0.22.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload-time = "2025-12-23T19:25:43.997Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload_time = "2025-12-23T19:25:43.997Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload_time = "2025-12-23T19:25:42.139Z" }, ] [[package]] @@ -248,27 +256,27 @@ dependencies = [ { name = "sqlalchemy" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725, upload-time = "2026-02-10T16:00:47.195Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725, upload_time = "2026-02-10T16:00:47.195Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/29/6533c317b74f707ea28f8d633734dbda2119bbadfc61b2f3640ba835d0f7/alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", size = 263893, upload-time = "2026-02-10T16:00:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/d2/29/6533c317b74f707ea28f8d633734dbda2119bbadfc61b2f3640ba835d0f7/alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", size = 263893, upload_time = "2026-02-10T16:00:49.997Z" }, ] [[package]] name = "annotated-doc" version = "0.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload_time = "2025-11-10T22:07:42.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload_time = "2025-11-10T22:07:40.673Z" }, ] [[package]] name = "annotated-types" version = "0.7.0" 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" } +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" }, + { 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" }, ] [[package]] @@ -278,18 +286,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload_time = "2026-01-06T11:45:21.246Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload_time = "2026-01-06T11:45:19.497Z" }, ] [[package]] name = "attrs" version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload_time = "2025-10-06T13:54:44.725Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload_time = "2025-10-06T13:54:43.17Z" }, ] [[package]] @@ -299,9 +307,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/dc/ed1681bf1339dd6ea1ce56136bad4baabc6f7ad466e375810702b0237047/authlib-1.6.7.tar.gz", hash = "sha256:dbf10100011d1e1b34048c9d120e83f13b35d69a826ae762b93d2fb5aafc337b", size = 164950, upload-time = "2026-02-06T14:04:14.171Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/dc/ed1681bf1339dd6ea1ce56136bad4baabc6f7ad466e375810702b0237047/authlib-1.6.7.tar.gz", hash = "sha256:dbf10100011d1e1b34048c9d120e83f13b35d69a826ae762b93d2fb5aafc337b", size = 164950, upload_time = "2026-02-06T14:04:14.171Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/00/3ed12264094ec91f534fae429945efbaa9f8c666f3aa7061cc3b2a26a0cd/authlib-1.6.7-py2.py3-none-any.whl", hash = "sha256:c637340d9a02789d2efa1d003a7437d10d3e565237bcb5fcbc6c134c7b95bab0", size = 244115, upload-time = "2026-02-06T14:04:12.141Z" }, + { url = "https://files.pythonhosted.org/packages/f8/00/3ed12264094ec91f534fae429945efbaa9f8c666f3aa7061cc3b2a26a0cd/authlib-1.6.7-py2.py3-none-any.whl", hash = "sha256:c637340d9a02789d2efa1d003a7437d10d3e565237bcb5fcbc6c134c7b95bab0", size = 244115, upload_time = "2026-02-06T14:04:12.141Z" }, ] [[package]] @@ -316,28 +324,28 @@ dependencies = [ { name = "platformdirs" }, { name = "pytokens" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/d9/07b458a3f1c525ac392b5edc6b191ff140b596f9d77092429417a54e249d/black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7", size = 659264, upload-time = "2025-12-08T01:40:52.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/d9/07b458a3f1c525ac392b5edc6b191ff140b596f9d77092429417a54e249d/black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7", size = 659264, upload_time = "2025-12-08T01:40:52.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/52/c551e36bc95495d2aa1a37d50566267aa47608c81a53f91daa809e03293f/black-25.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a05ddeb656534c3e27a05a29196c962877c83fa5503db89e68857d1161ad08a5", size = 1923809, upload-time = "2025-12-08T01:46:55.126Z" }, - { url = "https://files.pythonhosted.org/packages/a0/f7/aac9b014140ee56d247e707af8db0aae2e9efc28d4a8aba92d0abd7ae9d1/black-25.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ec77439ef3e34896995503865a85732c94396edcc739f302c5673a2315e1e7f", size = 1742384, upload-time = "2025-12-08T01:49:37.022Z" }, - { url = "https://files.pythonhosted.org/packages/74/98/38aaa018b2ab06a863974c12b14a6266badc192b20603a81b738c47e902e/black-25.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e509c858adf63aa61d908061b52e580c40eae0dfa72415fa47ac01b12e29baf", size = 1798761, upload-time = "2025-12-08T01:46:05.386Z" }, - { url = "https://files.pythonhosted.org/packages/16/3a/a8ac542125f61574a3f015b521ca83b47321ed19bb63fe6d7560f348bfe1/black-25.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:252678f07f5bac4ff0d0e9b261fbb029fa530cfa206d0a636a34ab445ef8ca9d", size = 1429180, upload-time = "2025-12-08T01:45:34.903Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2d/bdc466a3db9145e946762d52cd55b1385509d9f9004fec1c97bdc8debbfb/black-25.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc5b1c09fe3c931ddd20ee548511c64ebf964ada7e6f0763d443947fd1c603ce", size = 1239350, upload-time = "2025-12-08T01:46:09.458Z" }, - { url = "https://files.pythonhosted.org/packages/35/46/1d8f2542210c502e2ae1060b2e09e47af6a5e5963cb78e22ec1a11170b28/black-25.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0a0953b134f9335c2434864a643c842c44fba562155c738a2a37a4d61f00cad5", size = 1917015, upload-time = "2025-12-08T01:53:27.987Z" }, - { url = "https://files.pythonhosted.org/packages/41/37/68accadf977672beb8e2c64e080f568c74159c1aaa6414b4cd2aef2d7906/black-25.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2355bbb6c3b76062870942d8cc450d4f8ac71f9c93c40122762c8784df49543f", size = 1741830, upload-time = "2025-12-08T01:54:36.861Z" }, - { url = "https://files.pythonhosted.org/packages/ac/76/03608a9d8f0faad47a3af3a3c8c53af3367f6c0dd2d23a84710456c7ac56/black-25.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9678bd991cc793e81d19aeeae57966ee02909877cb65838ccffef24c3ebac08f", size = 1791450, upload-time = "2025-12-08T01:44:52.581Z" }, - { url = "https://files.pythonhosted.org/packages/06/99/b2a4bd7dfaea7964974f947e1c76d6886d65fe5d24f687df2d85406b2609/black-25.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:97596189949a8aad13ad12fcbb4ae89330039b96ad6742e6f6b45e75ad5cfd83", size = 1452042, upload-time = "2025-12-08T01:46:13.188Z" }, - { url = "https://files.pythonhosted.org/packages/b2/7c/d9825de75ae5dd7795d007681b752275ea85a1c5d83269b4b9c754c2aaab/black-25.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:778285d9ea197f34704e3791ea9404cd6d07595745907dd2ce3da7a13627b29b", size = 1267446, upload-time = "2025-12-08T01:46:14.497Z" }, - { url = "https://files.pythonhosted.org/packages/68/11/21331aed19145a952ad28fca2756a1433ee9308079bd03bd898e903a2e53/black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828", size = 206191, upload-time = "2025-12-08T01:40:50.963Z" }, + { url = "https://files.pythonhosted.org/packages/c8/52/c551e36bc95495d2aa1a37d50566267aa47608c81a53f91daa809e03293f/black-25.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a05ddeb656534c3e27a05a29196c962877c83fa5503db89e68857d1161ad08a5", size = 1923809, upload_time = "2025-12-08T01:46:55.126Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f7/aac9b014140ee56d247e707af8db0aae2e9efc28d4a8aba92d0abd7ae9d1/black-25.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ec77439ef3e34896995503865a85732c94396edcc739f302c5673a2315e1e7f", size = 1742384, upload_time = "2025-12-08T01:49:37.022Z" }, + { url = "https://files.pythonhosted.org/packages/74/98/38aaa018b2ab06a863974c12b14a6266badc192b20603a81b738c47e902e/black-25.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e509c858adf63aa61d908061b52e580c40eae0dfa72415fa47ac01b12e29baf", size = 1798761, upload_time = "2025-12-08T01:46:05.386Z" }, + { url = "https://files.pythonhosted.org/packages/16/3a/a8ac542125f61574a3f015b521ca83b47321ed19bb63fe6d7560f348bfe1/black-25.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:252678f07f5bac4ff0d0e9b261fbb029fa530cfa206d0a636a34ab445ef8ca9d", size = 1429180, upload_time = "2025-12-08T01:45:34.903Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2d/bdc466a3db9145e946762d52cd55b1385509d9f9004fec1c97bdc8debbfb/black-25.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc5b1c09fe3c931ddd20ee548511c64ebf964ada7e6f0763d443947fd1c603ce", size = 1239350, upload_time = "2025-12-08T01:46:09.458Z" }, + { url = "https://files.pythonhosted.org/packages/35/46/1d8f2542210c502e2ae1060b2e09e47af6a5e5963cb78e22ec1a11170b28/black-25.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0a0953b134f9335c2434864a643c842c44fba562155c738a2a37a4d61f00cad5", size = 1917015, upload_time = "2025-12-08T01:53:27.987Z" }, + { url = "https://files.pythonhosted.org/packages/41/37/68accadf977672beb8e2c64e080f568c74159c1aaa6414b4cd2aef2d7906/black-25.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2355bbb6c3b76062870942d8cc450d4f8ac71f9c93c40122762c8784df49543f", size = 1741830, upload_time = "2025-12-08T01:54:36.861Z" }, + { url = "https://files.pythonhosted.org/packages/ac/76/03608a9d8f0faad47a3af3a3c8c53af3367f6c0dd2d23a84710456c7ac56/black-25.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9678bd991cc793e81d19aeeae57966ee02909877cb65838ccffef24c3ebac08f", size = 1791450, upload_time = "2025-12-08T01:44:52.581Z" }, + { url = "https://files.pythonhosted.org/packages/06/99/b2a4bd7dfaea7964974f947e1c76d6886d65fe5d24f687df2d85406b2609/black-25.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:97596189949a8aad13ad12fcbb4ae89330039b96ad6742e6f6b45e75ad5cfd83", size = 1452042, upload_time = "2025-12-08T01:46:13.188Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7c/d9825de75ae5dd7795d007681b752275ea85a1c5d83269b4b9c754c2aaab/black-25.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:778285d9ea197f34704e3791ea9404cd6d07595745907dd2ce3da7a13627b29b", size = 1267446, upload_time = "2025-12-08T01:46:14.497Z" }, + { url = "https://files.pythonhosted.org/packages/68/11/21331aed19145a952ad28fca2756a1433ee9308079bd03bd898e903a2e53/black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828", size = 206191, upload_time = "2025-12-08T01:40:50.963Z" }, ] [[package]] name = "certifi" version = "2026.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload_time = "2026-01-04T02:42:41.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload_time = "2026-01-04T02:42:40.15Z" }, ] [[package]] @@ -347,83 +355,83 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload_time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload_time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload_time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload_time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload_time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload_time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload_time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload_time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload_time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload_time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload_time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload_time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload_time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload_time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload_time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload_time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload_time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload_time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload_time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload_time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload_time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload_time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload_time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload_time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload_time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload_time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload_time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload_time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload_time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload_time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload_time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload_time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload_time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload_time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload_time = "2025-09-08T23:23:43.004Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, - { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, - { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, - { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, - { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, - { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, - { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, - { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, - { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, - { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, - { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, - { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, - { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, - { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, - { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, - { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, - { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, - { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, - { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, - { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, - { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, - { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, - { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, - { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, - { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, - { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, - { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, - { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload_time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload_time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload_time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload_time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload_time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload_time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload_time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload_time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload_time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload_time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload_time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload_time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload_time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload_time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload_time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload_time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload_time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload_time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload_time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload_time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload_time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload_time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload_time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload_time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload_time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload_time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload_time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload_time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload_time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload_time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload_time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload_time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload_time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload_time = "2025-10-14T04:42:31.76Z" }, ] [[package]] @@ -433,27 +441,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload_time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload_time = "2025-11-15T20:45:41.139Z" }, ] [[package]] name = "cloudpickle" version = "3.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload_time = "2025-11-03T09:25:26.604Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload_time = "2025-11-03T09:25:25.534Z" }, ] [[package]] name = "colorama" version = "0.4.6" 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" } +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" }, + { 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" }, ] [[package]] @@ -463,68 +471,68 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" }, - { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, - { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, - { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, - { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, - { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, - { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, - { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, - { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" }, - { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" }, - { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" }, - { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" }, - { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" }, - { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" }, - { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" }, - { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" }, - { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" }, - { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" }, - { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" }, - { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, - { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, - { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, - { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, - { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, - { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, - { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, - { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, - { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, - { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, - { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" }, - { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload_time = "2026-02-10T19:18:38.255Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload_time = "2026-02-10T19:17:08.274Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload_time = "2026-02-10T19:17:10.53Z" }, + { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload_time = "2026-02-10T19:17:12.388Z" }, + { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload_time = "2026-02-10T19:17:13.853Z" }, + { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload_time = "2026-02-10T19:17:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload_time = "2026-02-10T19:17:17.221Z" }, + { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload_time = "2026-02-10T19:17:18.792Z" }, + { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload_time = "2026-02-10T19:17:20.256Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload_time = "2026-02-10T19:17:21.825Z" }, + { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload_time = "2026-02-10T19:17:25.133Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload_time = "2026-02-10T19:17:26.66Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload_time = "2026-02-10T19:17:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload_time = "2026-02-10T19:17:30.518Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload_time = "2026-02-10T19:17:32.083Z" }, + { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload_time = "2026-02-10T19:17:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload_time = "2026-02-10T19:17:35.569Z" }, + { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload_time = "2026-02-10T19:17:36.938Z" }, + { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload_time = "2026-02-10T19:17:38.748Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload_time = "2026-02-10T19:17:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload_time = "2026-02-10T19:17:41.789Z" }, + { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload_time = "2026-02-10T19:17:43.379Z" }, + { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload_time = "2026-02-10T19:17:45.481Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload_time = "2026-02-10T19:17:46.997Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload_time = "2026-02-10T19:17:48.661Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload_time = "2026-02-10T19:17:50.058Z" }, + { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload_time = "2026-02-10T19:17:51.54Z" }, + { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload_time = "2026-02-10T19:17:52.997Z" }, + { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload_time = "2026-02-10T19:17:54.549Z" }, + { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload_time = "2026-02-10T19:17:56.267Z" }, + { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload_time = "2026-02-10T19:17:58.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload_time = "2026-02-10T19:18:00.619Z" }, + { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload_time = "2026-02-10T19:18:02.379Z" }, + { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload_time = "2026-02-10T19:18:03.964Z" }, + { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload_time = "2026-02-10T19:18:05.588Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload_time = "2026-02-10T19:18:07.167Z" }, + { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload_time = "2026-02-10T19:18:09.813Z" }, + { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload_time = "2026-02-10T19:18:11.263Z" }, + { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload_time = "2026-02-10T19:18:12.914Z" }, + { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload_time = "2026-02-10T19:18:14.375Z" }, + { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload_time = "2026-02-10T19:18:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload_time = "2026-02-10T19:18:17.361Z" }, + { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload_time = "2026-02-10T19:18:18.899Z" }, ] [[package]] name = "distro" version = "1.9.0" 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" } +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" }, + { 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" }, ] [[package]] name = "docstring-parser" version = "0.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload_time = "2025-07-21T07:35:01.868Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, + { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload_time = "2025-07-21T07:35:00.684Z" }, ] [[package]] @@ -537,130 +545,130 @@ dependencies = [ { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/ff/e01087de891010089f1620c916c0c13130f3898177955c13e2b02d22ec4a/fastapi-0.123.10.tar.gz", hash = "sha256:624d384d7cda7c096449c889fc776a0571948ba14c3c929fa8e9a78cd0b0a6a8", size = 356360, upload-time = "2025-12-05T21:27:46.237Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/ff/e01087de891010089f1620c916c0c13130f3898177955c13e2b02d22ec4a/fastapi-0.123.10.tar.gz", hash = "sha256:624d384d7cda7c096449c889fc776a0571948ba14c3c929fa8e9a78cd0b0a6a8", size = 356360, upload_time = "2025-12-05T21:27:46.237Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/f0/7cb92c4a720def85240fd63fbbcf147ce19e7a731c8e1032376bb5a486ac/fastapi-0.123.10-py3-none-any.whl", hash = "sha256:0503b7b7bc71bc98f7c90c9117d21fdf6147c0d74703011b87936becc86985c1", size = 111774, upload-time = "2025-12-05T21:27:44.78Z" }, + { url = "https://files.pythonhosted.org/packages/d7/f0/7cb92c4a720def85240fd63fbbcf147ce19e7a731c8e1032376bb5a486ac/fastapi-0.123.10-py3-none-any.whl", hash = "sha256:0503b7b7bc71bc98f7c90c9117d21fdf6147c0d74703011b87936becc86985c1", size = 111774, upload_time = "2025-12-05T21:27:44.78Z" }, ] [[package]] name = "fastuuid" version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/83/ae12dd39b9a39b55d7f90abb8971f1a5f3c321fd72d5aa83f90dc67fe9ed/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021", size = 510720, upload-time = "2025-10-19T22:42:34.633Z" }, - { url = "https://files.pythonhosted.org/packages/53/b0/a4b03ff5d00f563cc7546b933c28cb3f2a07344b2aec5834e874f7d44143/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc", size = 262024, upload-time = "2025-10-19T22:30:25.482Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5", size = 251679, upload-time = "2025-10-19T22:36:14.096Z" }, - { url = "https://files.pythonhosted.org/packages/60/f5/a7e9cda8369e4f7919d36552db9b2ae21db7915083bc6336f1b0082c8b2e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f", size = 277862, upload-time = "2025-10-19T22:36:23.302Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d3/8ce11827c783affffd5bd4d6378b28eb6cc6d2ddf41474006b8d62e7448e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87", size = 278278, upload-time = "2025-10-19T22:29:43.809Z" }, - { url = "https://files.pythonhosted.org/packages/a2/51/680fb6352d0bbade04036da46264a8001f74b7484e2fd1f4da9e3db1c666/fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b", size = 301788, upload-time = "2025-10-19T22:36:06.825Z" }, - { url = "https://files.pythonhosted.org/packages/fa/7c/2014b5785bd8ebdab04ec857635ebd84d5ee4950186a577db9eff0fb8ff6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022", size = 459819, upload-time = "2025-10-19T22:35:31.623Z" }, - { url = "https://files.pythonhosted.org/packages/01/d2/524d4ceeba9160e7a9bc2ea3e8f4ccf1ad78f3bde34090ca0c51f09a5e91/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995", size = 478546, upload-time = "2025-10-19T22:26:03.023Z" }, - { url = "https://files.pythonhosted.org/packages/bc/17/354d04951ce114bf4afc78e27a18cfbd6ee319ab1829c2d5fb5e94063ac6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab", size = 450921, upload-time = "2025-10-19T22:31:02.151Z" }, - { url = "https://files.pythonhosted.org/packages/fb/be/d7be8670151d16d88f15bb121c5b66cdb5ea6a0c2a362d0dcf30276ade53/fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad", size = 154559, upload-time = "2025-10-19T22:36:36.011Z" }, - { url = "https://files.pythonhosted.org/packages/22/1d/5573ef3624ceb7abf4a46073d3554e37191c868abc3aecd5289a72f9810a/fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed", size = 156539, upload-time = "2025-10-19T22:33:35.898Z" }, - { url = "https://files.pythonhosted.org/packages/16/c9/8c7660d1fe3862e3f8acabd9be7fc9ad71eb270f1c65cce9a2b7a31329ab/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b852a870a61cfc26c884af205d502881a2e59cc07076b60ab4a951cc0c94d1ad", size = 510600, upload-time = "2025-10-19T22:43:44.17Z" }, - { url = "https://files.pythonhosted.org/packages/4c/f4/a989c82f9a90d0ad995aa957b3e572ebef163c5299823b4027986f133dfb/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c7502d6f54cd08024c3ea9b3514e2d6f190feb2f46e6dbcd3747882264bb5f7b", size = 262069, upload-time = "2025-10-19T22:43:38.38Z" }, - { url = "https://files.pythonhosted.org/packages/da/6c/a1a24f73574ac995482b1326cf7ab41301af0fabaa3e37eeb6b3df00e6e2/fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ca61b592120cf314cfd66e662a5b54a578c5a15b26305e1b8b618a6f22df714", size = 251543, upload-time = "2025-10-19T22:32:22.537Z" }, - { url = "https://files.pythonhosted.org/packages/1a/20/2a9b59185ba7a6c7b37808431477c2d739fcbdabbf63e00243e37bd6bf49/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa75b6657ec129d0abded3bec745e6f7ab642e6dba3a5272a68247e85f5f316f", size = 277798, upload-time = "2025-10-19T22:33:53.821Z" }, - { url = "https://files.pythonhosted.org/packages/ef/33/4105ca574f6ded0af6a797d39add041bcfb468a1255fbbe82fcb6f592da2/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0dfea3972200f72d4c7df02c8ac70bad1bb4c58d7e0ec1e6f341679073a7f", size = 278283, upload-time = "2025-10-19T22:29:02.812Z" }, - { url = "https://files.pythonhosted.org/packages/fe/8c/fca59f8e21c4deb013f574eae05723737ddb1d2937ce87cb2a5d20992dc3/fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bf539a7a95f35b419f9ad105d5a8a35036df35fdafae48fb2fd2e5f318f0d75", size = 301627, upload-time = "2025-10-19T22:35:54.985Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e2/f78c271b909c034d429218f2798ca4e89eeda7983f4257d7865976ddbb6c/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:9a133bf9cc78fdbd1179cb58a59ad0100aa32d8675508150f3658814aeefeaa4", size = 459778, upload-time = "2025-10-19T22:28:00.999Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f0/5ff209d865897667a2ff3e7a572267a9ced8f7313919f6d6043aed8b1caa/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:f54d5b36c56a2d5e1a31e73b950b28a0d83eb0c37b91d10408875a5a29494bad", size = 478605, upload-time = "2025-10-19T22:36:21.764Z" }, - { url = "https://files.pythonhosted.org/packages/e0/c8/2ce1c78f983a2c4987ea865d9516dbdfb141a120fd3abb977ae6f02ba7ca/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:ec27778c6ca3393ef662e2762dba8af13f4ec1aaa32d08d77f71f2a70ae9feb8", size = 450837, upload-time = "2025-10-19T22:34:37.178Z" }, - { url = "https://files.pythonhosted.org/packages/df/60/dad662ec9a33b4a5fe44f60699258da64172c39bd041da2994422cdc40fe/fastuuid-0.14.0-cp314-cp314-win32.whl", hash = "sha256:e23fc6a83f112de4be0cc1990e5b127c27663ae43f866353166f87df58e73d06", size = 154532, upload-time = "2025-10-19T22:35:18.217Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f6/da4db31001e854025ffd26bc9ba0740a9cbba2c3259695f7c5834908b336/fastuuid-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:df61342889d0f5e7a32f7284e55ef95103f2110fee433c2ae7c2c0956d76ac8a", size = 156457, upload-time = "2025-10-19T22:33:44.579Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload_time = "2025-10-19T22:19:22.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/83/ae12dd39b9a39b55d7f90abb8971f1a5f3c321fd72d5aa83f90dc67fe9ed/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021", size = 510720, upload_time = "2025-10-19T22:42:34.633Z" }, + { url = "https://files.pythonhosted.org/packages/53/b0/a4b03ff5d00f563cc7546b933c28cb3f2a07344b2aec5834e874f7d44143/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc", size = 262024, upload_time = "2025-10-19T22:30:25.482Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5", size = 251679, upload_time = "2025-10-19T22:36:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/a7e9cda8369e4f7919d36552db9b2ae21db7915083bc6336f1b0082c8b2e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f", size = 277862, upload_time = "2025-10-19T22:36:23.302Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d3/8ce11827c783affffd5bd4d6378b28eb6cc6d2ddf41474006b8d62e7448e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87", size = 278278, upload_time = "2025-10-19T22:29:43.809Z" }, + { url = "https://files.pythonhosted.org/packages/a2/51/680fb6352d0bbade04036da46264a8001f74b7484e2fd1f4da9e3db1c666/fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b", size = 301788, upload_time = "2025-10-19T22:36:06.825Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7c/2014b5785bd8ebdab04ec857635ebd84d5ee4950186a577db9eff0fb8ff6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022", size = 459819, upload_time = "2025-10-19T22:35:31.623Z" }, + { url = "https://files.pythonhosted.org/packages/01/d2/524d4ceeba9160e7a9bc2ea3e8f4ccf1ad78f3bde34090ca0c51f09a5e91/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995", size = 478546, upload_time = "2025-10-19T22:26:03.023Z" }, + { url = "https://files.pythonhosted.org/packages/bc/17/354d04951ce114bf4afc78e27a18cfbd6ee319ab1829c2d5fb5e94063ac6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab", size = 450921, upload_time = "2025-10-19T22:31:02.151Z" }, + { url = "https://files.pythonhosted.org/packages/fb/be/d7be8670151d16d88f15bb121c5b66cdb5ea6a0c2a362d0dcf30276ade53/fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad", size = 154559, upload_time = "2025-10-19T22:36:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/22/1d/5573ef3624ceb7abf4a46073d3554e37191c868abc3aecd5289a72f9810a/fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed", size = 156539, upload_time = "2025-10-19T22:33:35.898Z" }, + { url = "https://files.pythonhosted.org/packages/16/c9/8c7660d1fe3862e3f8acabd9be7fc9ad71eb270f1c65cce9a2b7a31329ab/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b852a870a61cfc26c884af205d502881a2e59cc07076b60ab4a951cc0c94d1ad", size = 510600, upload_time = "2025-10-19T22:43:44.17Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f4/a989c82f9a90d0ad995aa957b3e572ebef163c5299823b4027986f133dfb/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c7502d6f54cd08024c3ea9b3514e2d6f190feb2f46e6dbcd3747882264bb5f7b", size = 262069, upload_time = "2025-10-19T22:43:38.38Z" }, + { url = "https://files.pythonhosted.org/packages/da/6c/a1a24f73574ac995482b1326cf7ab41301af0fabaa3e37eeb6b3df00e6e2/fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ca61b592120cf314cfd66e662a5b54a578c5a15b26305e1b8b618a6f22df714", size = 251543, upload_time = "2025-10-19T22:32:22.537Z" }, + { url = "https://files.pythonhosted.org/packages/1a/20/2a9b59185ba7a6c7b37808431477c2d739fcbdabbf63e00243e37bd6bf49/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa75b6657ec129d0abded3bec745e6f7ab642e6dba3a5272a68247e85f5f316f", size = 277798, upload_time = "2025-10-19T22:33:53.821Z" }, + { url = "https://files.pythonhosted.org/packages/ef/33/4105ca574f6ded0af6a797d39add041bcfb468a1255fbbe82fcb6f592da2/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0dfea3972200f72d4c7df02c8ac70bad1bb4c58d7e0ec1e6f341679073a7f", size = 278283, upload_time = "2025-10-19T22:29:02.812Z" }, + { url = "https://files.pythonhosted.org/packages/fe/8c/fca59f8e21c4deb013f574eae05723737ddb1d2937ce87cb2a5d20992dc3/fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bf539a7a95f35b419f9ad105d5a8a35036df35fdafae48fb2fd2e5f318f0d75", size = 301627, upload_time = "2025-10-19T22:35:54.985Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e2/f78c271b909c034d429218f2798ca4e89eeda7983f4257d7865976ddbb6c/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:9a133bf9cc78fdbd1179cb58a59ad0100aa32d8675508150f3658814aeefeaa4", size = 459778, upload_time = "2025-10-19T22:28:00.999Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f0/5ff209d865897667a2ff3e7a572267a9ced8f7313919f6d6043aed8b1caa/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:f54d5b36c56a2d5e1a31e73b950b28a0d83eb0c37b91d10408875a5a29494bad", size = 478605, upload_time = "2025-10-19T22:36:21.764Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c8/2ce1c78f983a2c4987ea865d9516dbdfb141a120fd3abb977ae6f02ba7ca/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:ec27778c6ca3393ef662e2762dba8af13f4ec1aaa32d08d77f71f2a70ae9feb8", size = 450837, upload_time = "2025-10-19T22:34:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/df/60/dad662ec9a33b4a5fe44f60699258da64172c39bd041da2994422cdc40fe/fastuuid-0.14.0-cp314-cp314-win32.whl", hash = "sha256:e23fc6a83f112de4be0cc1990e5b127c27663ae43f866353166f87df58e73d06", size = 154532, upload_time = "2025-10-19T22:35:18.217Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/da4db31001e854025ffd26bc9ba0740a9cbba2c3259695f7c5834908b336/fastuuid-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:df61342889d0f5e7a32f7284e55ef95103f2110fee433c2ae7c2c0956d76ac8a", size = 156457, upload_time = "2025-10-19T22:33:44.579Z" }, ] [[package]] name = "filelock" version = "3.20.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload_time = "2026-01-09T17:55:05.421Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, + { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload_time = "2026-01-09T17:55:04.334Z" }, ] [[package]] name = "frozenlist" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, - { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, - { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, - { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, - { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, - { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, - { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, - { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, - { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, - { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, - { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, - { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, - { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, - { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, - { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, - { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, - { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, - { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, - { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, - { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, - { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, - { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, - { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, - { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, - { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, - { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, - { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, - { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, - { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, - { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, - { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, - { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, - { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, - { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, - { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, - { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, - { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, - { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, - { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, - { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, - { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, - { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, - { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, - { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, - { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, - { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, - { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, - { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, - { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, - { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, - { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, - { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, - { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload_time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload_time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload_time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload_time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload_time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload_time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload_time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload_time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload_time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload_time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload_time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload_time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload_time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload_time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload_time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload_time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload_time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload_time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload_time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload_time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload_time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload_time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload_time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload_time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload_time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload_time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload_time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload_time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload_time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload_time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload_time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload_time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload_time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload_time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload_time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload_time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload_time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload_time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload_time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload_time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload_time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload_time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload_time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload_time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload_time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload_time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload_time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload_time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload_time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload_time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload_time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload_time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload_time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload_time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload_time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload_time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload_time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload_time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload_time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload_time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload_time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload_time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload_time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload_time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload_time = "2025-10-06T05:37:54.513Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload_time = "2025-10-06T05:38:16.721Z" }, ] [[package]] name = "fsspec" version = "2026.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload_time = "2026-02-05T21:50:53.743Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload_time = "2026-02-05T21:50:51.819Z" }, ] [[package]] @@ -722,9 +730,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/10/05572d33273292bac49c2d1785925f7bc3ff2fe50e3044cf1062c1dde32e/google_api_core-2.29.0.tar.gz", hash = "sha256:84181be0f8e6b04006df75ddfe728f24489f0af57c96a529ff7cf45bc28797f7", size = 177828, upload-time = "2026-01-08T22:21:39.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/10/05572d33273292bac49c2d1785925f7bc3ff2fe50e3044cf1062c1dde32e/google_api_core-2.29.0.tar.gz", hash = "sha256:84181be0f8e6b04006df75ddfe728f24489f0af57c96a529ff7cf45bc28797f7", size = 177828, upload_time = "2026-01-08T22:21:39.269Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/b6/85c4d21067220b9a78cfb81f516f9725ea6befc1544ec9bd2c1acd97c324/google_api_core-2.29.0-py3-none-any.whl", hash = "sha256:d30bc60980daa36e314b5d5a3e5958b0200cb44ca8fa1be2b614e932b75a3ea9", size = 173906, upload-time = "2026-01-08T22:21:36.093Z" }, + { url = "https://files.pythonhosted.org/packages/77/b6/85c4d21067220b9a78cfb81f516f9725ea6befc1544ec9bd2c1acd97c324/google_api_core-2.29.0-py3-none-any.whl", hash = "sha256:d30bc60980daa36e314b5d5a3e5958b0200cb44ca8fa1be2b614e932b75a3ea9", size = 173906, upload_time = "2026-01-08T22:21:36.093Z" }, ] [package.optional-dependencies] @@ -744,9 +752,9 @@ dependencies = [ { name = "httplib2" }, { name = "uritemplate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e4/8d/4ab3e3516b93bb50ed7814738ea61d49cba3f72f4e331dc9518ae2731e92/google_api_python_client-2.190.0.tar.gz", hash = "sha256:5357f34552e3724d80d2604c8fa146766e0a9d6bb0afada886fafed9feafeef6", size = 14111143, upload-time = "2026-02-12T00:38:03.37Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/8d/4ab3e3516b93bb50ed7814738ea61d49cba3f72f4e331dc9518ae2731e92/google_api_python_client-2.190.0.tar.gz", hash = "sha256:5357f34552e3724d80d2604c8fa146766e0a9d6bb0afada886fafed9feafeef6", size = 14111143, upload_time = "2026-02-12T00:38:03.37Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/ad/223d5f4b0b987669ffeb3eadd7e9f85ece633aa7fd3246f1e2f6238e1e05/google_api_python_client-2.190.0-py3-none-any.whl", hash = "sha256:d9b5266758f96c39b8c21d9bbfeb4e58c14dbfba3c931f7c5a8d7fdcd292dd57", size = 14682070, upload-time = "2026-02-12T00:38:00.974Z" }, + { url = "https://files.pythonhosted.org/packages/07/ad/223d5f4b0b987669ffeb3eadd7e9f85ece633aa7fd3246f1e2f6238e1e05/google_api_python_client-2.190.0-py3-none-any.whl", hash = "sha256:d9b5266758f96c39b8c21d9bbfeb4e58c14dbfba3c931f7c5a8d7fdcd292dd57", size = 14682070, upload_time = "2026-02-12T00:38:00.974Z" }, ] [[package]] @@ -758,9 +766,9 @@ dependencies = [ { name = "pyasn1-modules" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/41/242044323fbd746615884b1c16639749e73665b718209946ebad7ba8a813/google_auth-2.48.0.tar.gz", hash = "sha256:4f7e706b0cd3208a3d940a19a822c37a476ddba5450156c3e6624a71f7c841ce", size = 326522, upload-time = "2026-01-26T19:22:47.157Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/41/242044323fbd746615884b1c16639749e73665b718209946ebad7ba8a813/google_auth-2.48.0.tar.gz", hash = "sha256:4f7e706b0cd3208a3d940a19a822c37a476ddba5450156c3e6624a71f7c841ce", size = 326522, upload_time = "2026-01-26T19:22:47.157Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/1d/d6466de3a5249d35e832a52834115ca9d1d0de6abc22065f049707516d47/google_auth-2.48.0-py3-none-any.whl", hash = "sha256:2e2a537873d449434252a9632c28bfc268b0adb1e53f9fb62afc5333a975903f", size = 236499, upload-time = "2026-01-26T19:22:45.099Z" }, + { url = "https://files.pythonhosted.org/packages/83/1d/d6466de3a5249d35e832a52834115ca9d1d0de6abc22065f049707516d47/google_auth-2.48.0-py3-none-any.whl", hash = "sha256:2e2a537873d449434252a9632c28bfc268b0adb1e53f9fb62afc5333a975903f", size = 236499, upload_time = "2026-01-26T19:22:45.099Z" }, ] [package.optional-dependencies] @@ -776,9 +784,9 @@ dependencies = [ { name = "google-auth" }, { name = "httplib2" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d5/ad/c1f2b1175096a8d04cf202ad5ea6065f108d26be6fc7215876bde4a7981d/google_auth_httplib2-0.3.0.tar.gz", hash = "sha256:177898a0175252480d5ed916aeea183c2df87c1f9c26705d74ae6b951c268b0b", size = 11134, upload-time = "2025-12-15T22:13:51.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/ad/c1f2b1175096a8d04cf202ad5ea6065f108d26be6fc7215876bde4a7981d/google_auth_httplib2-0.3.0.tar.gz", hash = "sha256:177898a0175252480d5ed916aeea183c2df87c1f9c26705d74ae6b951c268b0b", size = 11134, upload_time = "2025-12-15T22:13:51.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/d5/3c97526c8796d3caf5f4b3bed2b05e8a7102326f00a334e7a438237f3b22/google_auth_httplib2-0.3.0-py3-none-any.whl", hash = "sha256:426167e5df066e3f5a0fc7ea18768c08e7296046594ce4c8c409c2457dd1f776", size = 9529, upload-time = "2025-12-15T22:13:51.048Z" }, + { url = "https://files.pythonhosted.org/packages/99/d5/3c97526c8796d3caf5f4b3bed2b05e8a7102326f00a334e7a438237f3b22/google_auth_httplib2-0.3.0-py3-none-any.whl", hash = "sha256:426167e5df066e3f5a0fc7ea18768c08e7296046594ce4c8c409c2457dd1f776", size = 9529, upload_time = "2025-12-15T22:13:51.048Z" }, ] [[package]] @@ -799,9 +807,9 @@ dependencies = [ { name = "pydantic" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/76/0da98f663f5c58239900fa8f99488d01439b1ca7846c9667217a3aee20b1/google_cloud_aiplatform-1.137.0.tar.gz", hash = "sha256:76e66e2c3879936e51039d8bbd82581451510b4c7a840a588daaecee893d7d1e", size = 9947045, upload-time = "2026-02-11T16:23:18.435Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/76/0da98f663f5c58239900fa8f99488d01439b1ca7846c9667217a3aee20b1/google_cloud_aiplatform-1.137.0.tar.gz", hash = "sha256:76e66e2c3879936e51039d8bbd82581451510b4c7a840a588daaecee893d7d1e", size = 9947045, upload_time = "2026-02-11T16:23:18.435Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/b5/795c410120cb350058b9328f051b57a49a897514ba1bc65677ade0f6c1be/google_cloud_aiplatform-1.137.0-py2.py3-none-any.whl", hash = "sha256:e99dd235c237cbbeb0e73b0fc4b1ca9588b4144ac243a6242b2005b339b40ce8", size = 8204286, upload-time = "2026-02-11T16:23:15.462Z" }, + { url = "https://files.pythonhosted.org/packages/72/b5/795c410120cb350058b9328f051b57a49a897514ba1bc65677ade0f6c1be/google_cloud_aiplatform-1.137.0-py2.py3-none-any.whl", hash = "sha256:e99dd235c237cbbeb0e73b0fc4b1ca9588b4144ac243a6242b2005b339b40ce8", size = 8204286, upload_time = "2026-02-11T16:23:15.462Z" }, ] [package.optional-dependencies] @@ -830,9 +838,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/65/38/89317773c64b5a7e9b56b9aecb2e39ac02d8d6d09fb5b276710c6892e690/google_cloud_appengine_logging-1.8.0.tar.gz", hash = "sha256:84b705a69e4109fc2f68dfe36ce3df6a34d5c3d989eee6d0ac1b024dda0ba6f5", size = 18071, upload-time = "2026-01-15T13:14:40.024Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/38/89317773c64b5a7e9b56b9aecb2e39ac02d8d6d09fb5b276710c6892e690/google_cloud_appengine_logging-1.8.0.tar.gz", hash = "sha256:84b705a69e4109fc2f68dfe36ce3df6a34d5c3d989eee6d0ac1b024dda0ba6f5", size = 18071, upload_time = "2026-01-15T13:14:40.024Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/66/4a9be8afb1d0bf49472478cec20fefe4f4cb3a6e67be2231f097041e7339/google_cloud_appengine_logging-1.8.0-py3-none-any.whl", hash = "sha256:a4ce9ce94a9fd8c89ed07fa0b06fcf9ea3642f9532a1be1a8c7b5f82c0a70ec6", size = 18380, upload-time = "2026-01-09T14:52:58.154Z" }, + { url = "https://files.pythonhosted.org/packages/a2/66/4a9be8afb1d0bf49472478cec20fefe4f4cb3a6e67be2231f097041e7339/google_cloud_appengine_logging-1.8.0-py3-none-any.whl", hash = "sha256:a4ce9ce94a9fd8c89ed07fa0b06fcf9ea3642f9532a1be1a8c7b5f82c0a70ec6", size = 18380, upload_time = "2026-01-09T14:52:58.154Z" }, ] [[package]] @@ -843,9 +851,9 @@ dependencies = [ { name = "googleapis-common-protos" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/d2/ad96950410f8a05e921a6da2e1a6ba4aeca674bbb5dda8200c3c7296d7ad/google_cloud_audit_log-0.4.0.tar.gz", hash = "sha256:8467d4dcca9f3e6160520c24d71592e49e874838f174762272ec10e7950b6feb", size = 44682, upload-time = "2025-10-17T02:33:44.641Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/d2/ad96950410f8a05e921a6da2e1a6ba4aeca674bbb5dda8200c3c7296d7ad/google_cloud_audit_log-0.4.0.tar.gz", hash = "sha256:8467d4dcca9f3e6160520c24d71592e49e874838f174762272ec10e7950b6feb", size = 44682, upload_time = "2025-10-17T02:33:44.641Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/25/532886995f11102ad6de290496de5db227bd3a73827702445928ad32edcb/google_cloud_audit_log-0.4.0-py3-none-any.whl", hash = "sha256:6b88e2349df45f8f4cc0993b687109b1388da1571c502dc1417efa4b66ec55e0", size = 44890, upload-time = "2025-10-17T02:30:55.11Z" }, + { url = "https://files.pythonhosted.org/packages/9b/25/532886995f11102ad6de290496de5db227bd3a73827702445928ad32edcb/google_cloud_audit_log-0.4.0-py3-none-any.whl", hash = "sha256:6b88e2349df45f8f4cc0993b687109b1388da1571c502dc1417efa4b66ec55e0", size = 44890, upload_time = "2025-10-17T02:30:55.11Z" }, ] [[package]] @@ -861,9 +869,9 @@ dependencies = [ { name = "python-dateutil" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/0a/62438ca138a095945468968696d9cca75a4cfd059e810402e70b0236d8ba/google_cloud_bigquery-3.40.0.tar.gz", hash = "sha256:b3ccb11caf0029f15b29569518f667553fe08f6f1459b959020c83fbbd8f2e68", size = 509287, upload-time = "2026-01-08T01:07:26.065Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/0a/62438ca138a095945468968696d9cca75a4cfd059e810402e70b0236d8ba/google_cloud_bigquery-3.40.0.tar.gz", hash = "sha256:b3ccb11caf0029f15b29569518f667553fe08f6f1459b959020c83fbbd8f2e68", size = 509287, upload_time = "2026-01-08T01:07:26.065Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/6a/90a04270dd60cc70259b73744f6e610ae9a158b21ab50fb695cca0056a3d/google_cloud_bigquery-3.40.0-py3-none-any.whl", hash = "sha256:0469bcf9e3dad3cab65b67cce98180c8c0aacf3253d47f0f8e976f299b49b5ab", size = 261335, upload-time = "2026-01-08T01:07:23.761Z" }, + { url = "https://files.pythonhosted.org/packages/90/6a/90a04270dd60cc70259b73744f6e610ae9a158b21ab50fb695cca0056a3d/google_cloud_bigquery-3.40.0-py3-none-any.whl", hash = "sha256:0469bcf9e3dad3cab65b67cce98180c8c0aacf3253d47f0f8e976f299b49b5ab", size = 261335, upload_time = "2026-01-08T01:07:23.761Z" }, ] [[package]] @@ -877,9 +885,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cf/72/b5dbf3487ea320a87c6d1ba8bb7680fafdb3147343a06d928b4209abcdba/google_cloud_bigquery_storage-2.36.0.tar.gz", hash = "sha256:d3c1ce9d2d3a4d7116259889dcbe3c7c70506f71f6ce6bbe54aa0a68bbba8f8f", size = 306959, upload-time = "2025-12-18T18:01:45.916Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/72/b5dbf3487ea320a87c6d1ba8bb7680fafdb3147343a06d928b4209abcdba/google_cloud_bigquery_storage-2.36.0.tar.gz", hash = "sha256:d3c1ce9d2d3a4d7116259889dcbe3c7c70506f71f6ce6bbe54aa0a68bbba8f8f", size = 306959, upload_time = "2025-12-18T18:01:45.916Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/50/70e4bc2d52b52145b6e70008fbf806cef850e809dd3e30b4493d91c069ea/google_cloud_bigquery_storage-2.36.0-py3-none-any.whl", hash = "sha256:1769e568070db672302771d2aec18341de10712aa9c4a8c549f417503e0149f0", size = 303731, upload-time = "2025-12-18T18:01:44.598Z" }, + { url = "https://files.pythonhosted.org/packages/01/50/70e4bc2d52b52145b6e70008fbf806cef850e809dd3e30b4493d91c069ea/google_cloud_bigquery_storage-2.36.0-py3-none-any.whl", hash = "sha256:1769e568070db672302771d2aec18341de10712aa9c4a8c549f417503e0149f0", size = 303731, upload_time = "2025-12-18T18:01:44.598Z" }, ] [[package]] @@ -895,9 +903,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/c9/aceae21411b1a77fb4d3cde6e6f461321ee33c65fb8dc53480d4e47e1a55/google_cloud_bigtable-2.35.0.tar.gz", hash = "sha256:f5699012c5fea4bd4bdf7e80e5e3a812a847eb8f41bf8dc2f43095d6d876b83b", size = 775613, upload-time = "2025-12-17T15:18:14.303Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/c9/aceae21411b1a77fb4d3cde6e6f461321ee33c65fb8dc53480d4e47e1a55/google_cloud_bigtable-2.35.0.tar.gz", hash = "sha256:f5699012c5fea4bd4bdf7e80e5e3a812a847eb8f41bf8dc2f43095d6d876b83b", size = 775613, upload_time = "2025-12-17T15:18:14.303Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/69/03eed134d71f6117ffd9efac2d1033bb2fa2522e9e82545a0828061d32f4/google_cloud_bigtable-2.35.0-py3-none-any.whl", hash = "sha256:f355bfce1f239453ec2bb3839b0f4f9937cf34ef06ef29e1ca63d58fd38d0c50", size = 540341, upload-time = "2025-12-17T15:18:12.176Z" }, + { url = "https://files.pythonhosted.org/packages/62/69/03eed134d71f6117ffd9efac2d1033bb2fa2522e9e82545a0828061d32f4/google_cloud_bigtable-2.35.0-py3-none-any.whl", hash = "sha256:f355bfce1f239453ec2bb3839b0f4f9937cf34ef06ef29e1ca63d58fd38d0c50", size = 540341, upload_time = "2025-12-17T15:18:12.176Z" }, ] [[package]] @@ -908,9 +916,9 @@ dependencies = [ { name = "google-api-core" }, { name = "google-auth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload_time = "2025-10-29T23:17:39.513Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload_time = "2025-10-29T23:17:38.548Z" }, ] [[package]] @@ -923,9 +931,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8f/cd/b33bbc4b096d937abee5ebfad3908b2bdc65acd1582191aa33beaa2b70a5/google_cloud_discoveryengine-0.13.12.tar.gz", hash = "sha256:d6b9f8fadd8ad0d2f4438231c5eb7772a317e9f59cafbcbadc19b5d54c609419", size = 3582382, upload-time = "2025-09-22T16:51:14.052Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/cd/b33bbc4b096d937abee5ebfad3908b2bdc65acd1582191aa33beaa2b70a5/google_cloud_discoveryengine-0.13.12.tar.gz", hash = "sha256:d6b9f8fadd8ad0d2f4438231c5eb7772a317e9f59cafbcbadc19b5d54c609419", size = 3582382, upload_time = "2025-09-22T16:51:14.052Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/70/607f6011648f603d35e60a16c34aee68a0b39510e4268d4859f3268684f9/google_cloud_discoveryengine-0.13.12-py3-none-any.whl", hash = "sha256:295f8c6df3fb26b90fb82c2cd6fbcf4b477661addcb19a94eea16463a5c4e041", size = 3337248, upload-time = "2025-09-22T16:50:57.375Z" }, + { url = "https://files.pythonhosted.org/packages/93/70/607f6011648f603d35e60a16c34aee68a0b39510e4268d4859f3268684f9/google_cloud_discoveryengine-0.13.12-py3-none-any.whl", hash = "sha256:295f8c6df3fb26b90fb82c2cd6fbcf4b477661addcb19a94eea16463a5c4e041", size = 3337248, upload_time = "2025-09-22T16:50:57.375Z" }, ] [[package]] @@ -940,9 +948,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/0b/037b1e1eb601646d6f49bc06d62094c1d0996b373dcbf70c426c6c51572e/google_cloud_iam-2.21.0.tar.gz", hash = "sha256:fc560527e22b97c6cbfba0797d867cf956c727ba687b586b9aa44d78e92281a3", size = 499038, upload-time = "2026-01-15T13:15:08.243Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/0b/037b1e1eb601646d6f49bc06d62094c1d0996b373dcbf70c426c6c51572e/google_cloud_iam-2.21.0.tar.gz", hash = "sha256:fc560527e22b97c6cbfba0797d867cf956c727ba687b586b9aa44d78e92281a3", size = 499038, upload_time = "2026-01-15T13:15:08.243Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/44/02ac4e147ea034a3d641c11b54c9d8d0b80fc1ea6a8b7d6c1588d208d42a/google_cloud_iam-2.21.0-py3-none-any.whl", hash = "sha256:1b4a21302b186a31f3a516ccff303779638308b7c801fb61a2406b6a0c6293c4", size = 458958, upload-time = "2026-01-15T13:13:40.671Z" }, + { url = "https://files.pythonhosted.org/packages/c8/44/02ac4e147ea034a3d641c11b54c9d8d0b80fc1ea6a8b7d6c1588d208d42a/google_cloud_iam-2.21.0-py3-none-any.whl", hash = "sha256:1b4a21302b186a31f3a516ccff303779638308b7c801fb61a2406b6a0c6293c4", size = 458958, upload_time = "2026-01-15T13:13:40.671Z" }, ] [[package]] @@ -960,9 +968,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7f/47/31ef0261802fe8b37c221392e1d6ff01d30b03dce5e20e77fc7d57ddf8a3/google_cloud_logging-3.13.0.tar.gz", hash = "sha256:3aae0573b1a1a4f59ecdf4571f4e7881b5823bd129fe469561c1c49a7fa8a4c1", size = 290169, upload-time = "2025-12-16T14:11:07.345Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/47/31ef0261802fe8b37c221392e1d6ff01d30b03dce5e20e77fc7d57ddf8a3/google_cloud_logging-3.13.0.tar.gz", hash = "sha256:3aae0573b1a1a4f59ecdf4571f4e7881b5823bd129fe469561c1c49a7fa8a4c1", size = 290169, upload_time = "2025-12-16T14:11:07.345Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/5a/778dca2e375171af4085554cb3bc643627717a7e4e1539842ced3afd6ec4/google_cloud_logging-3.13.0-py3-none-any.whl", hash = "sha256:f215e1c76ee29239c6cacf02443dffa985663c74bf47c9818854694805c6019f", size = 230518, upload-time = "2025-12-16T14:11:05.894Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5a/778dca2e375171af4085554cb3bc643627717a7e4e1539842ced3afd6ec4/google_cloud_logging-3.13.0-py3-none-any.whl", hash = "sha256:f215e1c76ee29239c6cacf02443dffa985663c74bf47c9818854694805c6019f", size = 230518, upload_time = "2025-12-16T14:11:05.894Z" }, ] [[package]] @@ -976,9 +984,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/06/9fc0a34bed4221a68eef3e0373ae054de367dc42c0b689d5d917587ef61b/google_cloud_monitoring-2.29.1.tar.gz", hash = "sha256:86cac55cdd2608561819d19544fb3c129bbb7dcecc445d8de426e34cd6fa8e49", size = 404383, upload-time = "2026-02-05T18:59:13.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/97/06/9fc0a34bed4221a68eef3e0373ae054de367dc42c0b689d5d917587ef61b/google_cloud_monitoring-2.29.1.tar.gz", hash = "sha256:86cac55cdd2608561819d19544fb3c129bbb7dcecc445d8de426e34cd6fa8e49", size = 404383, upload_time = "2026-02-05T18:59:13.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/97/7c27aa95eccf8b62b066295a7c4ad04284364b696d3e7d9d47152b255a24/google_cloud_monitoring-2.29.1-py3-none-any.whl", hash = "sha256:944a57031f20da38617d184d5658c1f938e019e8061f27fd944584831a1b9d5a", size = 387922, upload-time = "2026-02-05T18:58:54.964Z" }, + { url = "https://files.pythonhosted.org/packages/ac/97/7c27aa95eccf8b62b066295a7c4ad04284364b696d3e7d9d47152b255a24/google_cloud_monitoring-2.29.1-py3-none-any.whl", hash = "sha256:944a57031f20da38617d184d5658c1f938e019e8061f27fd944584831a1b9d5a", size = 387922, upload_time = "2026-02-05T18:58:54.964Z" }, ] [[package]] @@ -993,9 +1001,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/7f/db00b2820475793a52958dc55fe9ec2eb8e863546e05fcece9b921f86ebe/google_cloud_resource_manager-1.16.0.tar.gz", hash = "sha256:cc938f87cc36c2672f062b1e541650629e0d954c405a4dac35ceedee70c267c3", size = 459840, upload-time = "2026-01-15T13:04:07.726Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/7f/db00b2820475793a52958dc55fe9ec2eb8e863546e05fcece9b921f86ebe/google_cloud_resource_manager-1.16.0.tar.gz", hash = "sha256:cc938f87cc36c2672f062b1e541650629e0d954c405a4dac35ceedee70c267c3", size = 459840, upload_time = "2026-01-15T13:04:07.726Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/ff/4b28bcc791d9d7e4ac8fea00fbd90ccb236afda56746a3b4564d2ae45df3/google_cloud_resource_manager-1.16.0-py3-none-any.whl", hash = "sha256:fb9a2ad2b5053c508e1c407ac31abfd1a22e91c32876c1892830724195819a28", size = 400218, upload-time = "2026-01-15T13:02:47.378Z" }, + { url = "https://files.pythonhosted.org/packages/94/ff/4b28bcc791d9d7e4ac8fea00fbd90ccb236afda56746a3b4564d2ae45df3/google_cloud_resource_manager-1.16.0-py3-none-any.whl", hash = "sha256:fb9a2ad2b5053c508e1c407ac31abfd1a22e91c32876c1892830724195819a28", size = 400218, upload_time = "2026-01-15T13:02:47.378Z" }, ] [[package]] @@ -1010,9 +1018,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/9c/a6c7144bc96df77376ae3fcc916fb639c40814c2e4bba2051d31dc136cd0/google_cloud_secret_manager-2.26.0.tar.gz", hash = "sha256:0d1d6f76327685a0ed78a4cf50f289e1bfbbe56026ed0affa98663b86d6d50d6", size = 277603, upload-time = "2025-12-18T00:29:31.065Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/9c/a6c7144bc96df77376ae3fcc916fb639c40814c2e4bba2051d31dc136cd0/google_cloud_secret_manager-2.26.0.tar.gz", hash = "sha256:0d1d6f76327685a0ed78a4cf50f289e1bfbbe56026ed0affa98663b86d6d50d6", size = 277603, upload_time = "2025-12-18T00:29:31.065Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/30/a58739dd12cec0f7f761ed1efb518aed2250a407d4ed14c5a0eeee7eaaf9/google_cloud_secret_manager-2.26.0-py3-none-any.whl", hash = "sha256:940a5447a6ec9951446fd1a0f22c81a4303fde164cd747aae152c5f5c8e6723e", size = 223623, upload-time = "2025-12-18T00:29:29.311Z" }, + { url = "https://files.pythonhosted.org/packages/c8/30/a58739dd12cec0f7f761ed1efb518aed2250a407d4ed14c5a0eeee7eaaf9/google_cloud_secret_manager-2.26.0-py3-none-any.whl", hash = "sha256:940a5447a6ec9951446fd1a0f22c81a4303fde164cd747aae152c5f5c8e6723e", size = 223623, upload_time = "2025-12-18T00:29:29.311Z" }, ] [[package]] @@ -1034,9 +1042,9 @@ dependencies = [ { name = "protobuf" }, { name = "sqlparse" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/80/86e152f887cdddab5b8268c93d18c671a3653545be2ea2babab6b6ad635f/google_cloud_spanner-3.62.0.tar.gz", hash = "sha256:a25bdbfda84bc7a819f04e45473187d8670711fd5ec827cf442e3664661d1d23", size = 722967, upload-time = "2026-01-16T06:33:29.462Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/80/86e152f887cdddab5b8268c93d18c671a3653545be2ea2babab6b6ad635f/google_cloud_spanner-3.62.0.tar.gz", hash = "sha256:a25bdbfda84bc7a819f04e45473187d8670711fd5ec827cf442e3664661d1d23", size = 722967, upload_time = "2026-01-16T06:33:29.462Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/a3/27c0af7f4350757f449e601733d960fc6e2717fa25d3d826ad29b694de68/google_cloud_spanner-3.62.0-py3-none-any.whl", hash = "sha256:b59d7b731463ce998439c1998730760e36f3d699510608d896f2ca8bc57613a9", size = 516156, upload-time = "2026-01-16T06:33:28.173Z" }, + { url = "https://files.pythonhosted.org/packages/9c/a3/27c0af7f4350757f449e601733d960fc6e2717fa25d3d826ad29b694de68/google_cloud_spanner-3.62.0-py3-none-any.whl", hash = "sha256:b59d7b731463ce998439c1998730760e36f3d699510608d896f2ca8bc57613a9", size = 516156, upload_time = "2026-01-16T06:33:28.173Z" }, ] [[package]] @@ -1050,9 +1058,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/b7/b078693abc67af4cbbf60727ebd29d37f786ada8a6146ada2d5918da6a3a/google_cloud_speech-2.36.1.tar.gz", hash = "sha256:30fef3b30c1e1b5f376be3cf82a724c8629994de045935f85e4b7bceae8c2129", size = 401910, upload-time = "2026-02-05T18:59:22.411Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/b7/b078693abc67af4cbbf60727ebd29d37f786ada8a6146ada2d5918da6a3a/google_cloud_speech-2.36.1.tar.gz", hash = "sha256:30fef3b30c1e1b5f376be3cf82a724c8629994de045935f85e4b7bceae8c2129", size = 401910, upload_time = "2026-02-05T18:59:22.411Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/13/b1437f2716ce56ca13298855929e5fb790c13c3ddee24248a3682ba392a5/google_cloud_speech-2.36.1-py3-none-any.whl", hash = "sha256:a54985b3e7c001a9feae78cec77e67e85d29b3851d00af1f805ffff3f477d8fe", size = 342457, upload-time = "2026-02-05T18:58:59.518Z" }, + { url = "https://files.pythonhosted.org/packages/f0/13/b1437f2716ce56ca13298855929e5fb790c13c3ddee24248a3682ba392a5/google_cloud_speech-2.36.1-py3-none-any.whl", hash = "sha256:a54985b3e7c001a9feae78cec77e67e85d29b3851d00af1f805ffff3f477d8fe", size = 342457, upload_time = "2026-02-05T18:58:59.518Z" }, ] [[package]] @@ -1067,9 +1075,9 @@ dependencies = [ { name = "google-resumable-media" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f7/b1/4f0798e88285b50dfc60ed3a7de071def538b358db2da468c2e0deecbb40/google_cloud_storage-3.9.0.tar.gz", hash = "sha256:f2d8ca7db2f652be757e92573b2196e10fbc09649b5c016f8b422ad593c641cc", size = 17298544, upload-time = "2026-02-02T13:36:34.119Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/b1/4f0798e88285b50dfc60ed3a7de071def538b358db2da468c2e0deecbb40/google_cloud_storage-3.9.0.tar.gz", hash = "sha256:f2d8ca7db2f652be757e92573b2196e10fbc09649b5c016f8b422ad593c641cc", size = 17298544, upload_time = "2026-02-02T13:36:34.119Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/0b/816a6ae3c9fd096937d2e5f9670558908811d57d59ddf69dd4b83b326fd1/google_cloud_storage-3.9.0-py3-none-any.whl", hash = "sha256:2dce75a9e8b3387078cbbdad44757d410ecdb916101f8ba308abf202b6968066", size = 321324, upload-time = "2026-02-02T13:36:32.271Z" }, + { url = "https://files.pythonhosted.org/packages/46/0b/816a6ae3c9fd096937d2e5f9670558908811d57d59ddf69dd4b83b326fd1/google_cloud_storage-3.9.0-py3-none-any.whl", hash = "sha256:2dce75a9e8b3387078cbbdad44757d410ecdb916101f8ba308abf202b6968066", size = 321324, upload_time = "2026-02-02T13:36:32.271Z" }, ] [[package]] @@ -1083,27 +1091,27 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/34/b1883f4682f1681941100df0e411cb0185013f7c349489ab1330348d7c5c/google_cloud_trace-1.18.0.tar.gz", hash = "sha256:46d42b90273da3bc4850bb0d6b9a205eb826a54561ff1b30ca33cc92174c3f37", size = 103347, upload-time = "2026-01-15T13:04:56.441Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/34/b1883f4682f1681941100df0e411cb0185013f7c349489ab1330348d7c5c/google_cloud_trace-1.18.0.tar.gz", hash = "sha256:46d42b90273da3bc4850bb0d6b9a205eb826a54561ff1b30ca33cc92174c3f37", size = 103347, upload_time = "2026-01-15T13:04:56.441Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/15/366fd8b028a50a9018c933270d220a4e53dca8022ce9086618b72978ab90/google_cloud_trace-1.18.0-py3-none-any.whl", hash = "sha256:52c002d8d3da802e031fee62cd49a1baf899932d4f548a150f685af6815b5554", size = 107488, upload-time = "2026-01-15T12:17:21.519Z" }, + { url = "https://files.pythonhosted.org/packages/87/15/366fd8b028a50a9018c933270d220a4e53dca8022ce9086618b72978ab90/google_cloud_trace-1.18.0-py3-none-any.whl", hash = "sha256:52c002d8d3da802e031fee62cd49a1baf899932d4f548a150f685af6815b5554", size = 107488, upload_time = "2026-01-15T12:17:21.519Z" }, ] [[package]] name = "google-crc32c" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } +sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload_time = "2025-12-16T00:35:25.142Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload-time = "2025-12-16T00:23:20.709Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload-time = "2025-12-16T00:43:14.628Z" }, - { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload-time = "2025-12-16T00:40:24.742Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload-time = "2025-12-16T00:40:25.505Z" }, - { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload-time = "2025-12-16T00:35:22.107Z" }, - { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301, upload-time = "2025-12-16T00:24:48.527Z" }, - { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868, upload-time = "2025-12-16T00:48:12.163Z" }, - { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381, upload-time = "2025-12-16T00:40:26.268Z" }, - { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734, upload-time = "2025-12-16T00:40:27.028Z" }, - { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878, upload-time = "2025-12-16T00:35:23.142Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload_time = "2025-12-16T00:23:20.709Z" }, + { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload_time = "2025-12-16T00:43:14.628Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload_time = "2025-12-16T00:40:24.742Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload_time = "2025-12-16T00:40:25.505Z" }, + { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload_time = "2025-12-16T00:35:22.107Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301, upload_time = "2025-12-16T00:24:48.527Z" }, + { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868, upload_time = "2025-12-16T00:48:12.163Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381, upload_time = "2025-12-16T00:40:26.268Z" }, + { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734, upload_time = "2025-12-16T00:40:27.028Z" }, + { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878, upload_time = "2025-12-16T00:35:23.142Z" }, ] [[package]] @@ -1122,9 +1130,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/d7/07ec5dadd0741f09e89f3ff5f0ce051ce2aa3a76797699d661dc88def077/google_genai-1.63.0.tar.gz", hash = "sha256:dc76cab810932df33cbec6c7ef3ce1538db5bef27aaf78df62ac38666c476294", size = 491970, upload-time = "2026-02-11T23:46:28.472Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/d7/07ec5dadd0741f09e89f3ff5f0ce051ce2aa3a76797699d661dc88def077/google_genai-1.63.0.tar.gz", hash = "sha256:dc76cab810932df33cbec6c7ef3ce1538db5bef27aaf78df62ac38666c476294", size = 491970, upload_time = "2026-02-11T23:46:28.472Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/c8/ba32159e553fab787708c612cf0c3a899dafe7aca81115d841766e3bfe69/google_genai-1.63.0-py3-none-any.whl", hash = "sha256:6206c13fc20f332703ca7375bea7c191c82f95d6781c29936c6982d86599b359", size = 724747, upload-time = "2026-02-11T23:46:26.697Z" }, + { url = "https://files.pythonhosted.org/packages/82/c8/ba32159e553fab787708c612cf0c3a899dafe7aca81115d841766e3bfe69/google_genai-1.63.0-py3-none-any.whl", hash = "sha256:6206c13fc20f332703ca7375bea7c191c82f95d6781c29936c6982d86599b359", size = 724747, upload_time = "2026-02-11T23:46:26.697Z" }, ] [[package]] @@ -1134,9 +1142,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-crc32c" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload-time = "2025-11-17T15:38:06.659Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload_time = "2025-11-17T15:38:06.659Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload-time = "2025-11-17T15:38:05.594Z" }, + { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload_time = "2025-11-17T15:38:05.594Z" }, ] [[package]] @@ -1146,9 +1154,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload_time = "2025-11-06T18:29:24.087Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload_time = "2025-11-06T18:29:13.14Z" }, ] [package.optional-dependencies] @@ -1160,40 +1168,43 @@ grpc = [ name = "graphviz" version = "0.21" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/b3/3ac91e9be6b761a4b30d66ff165e54439dcd48b83f4e20d644867215f6ca/graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78", size = 200434, upload-time = "2025-06-15T09:35:05.824Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b3/3ac91e9be6b761a4b30d66ff165e54439dcd48b83f4e20d644867215f6ca/graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78", size = 200434, upload_time = "2025-06-15T09:35:05.824Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" }, + { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload_time = "2025-06-15T09:35:04.433Z" }, ] [[package]] name = "greenlet" version = "3.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/99/1cd3411c56a410994669062bd73dd58270c00cc074cac15f385a1fd91f8a/greenlet-3.3.1.tar.gz", hash = "sha256:41848f3230b58c08bb43dee542e74a2a2e34d3c59dc3076cec9151aeeedcae98", size = 184690, upload-time = "2026-01-23T15:31:02.076Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/ab/d26750f2b7242c2b90ea2ad71de70cfcd73a948a49513188a0fc0d6fc15a/greenlet-3.3.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:7ab327905cabb0622adca5971e488064e35115430cec2c35a50fd36e72a315b3", size = 275205, upload-time = "2026-01-23T15:30:24.556Z" }, - { url = "https://files.pythonhosted.org/packages/10/d3/be7d19e8fad7c5a78eeefb2d896a08cd4643e1e90c605c4be3b46264998f/greenlet-3.3.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65be2f026ca6a176f88fb935ee23c18333ccea97048076aef4db1ef5bc0713ac", size = 599284, upload-time = "2026-01-23T16:00:58.584Z" }, - { url = "https://files.pythonhosted.org/packages/ae/21/fe703aaa056fdb0f17e5afd4b5c80195bbdab701208918938bd15b00d39b/greenlet-3.3.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7a3ae05b3d225b4155bda56b072ceb09d05e974bc74be6c3fc15463cf69f33fd", size = 610274, upload-time = "2026-01-23T16:05:29.312Z" }, - { url = "https://files.pythonhosted.org/packages/cb/86/5c6ab23bb3c28c21ed6bebad006515cfe08b04613eb105ca0041fecca852/greenlet-3.3.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6423481193bbbe871313de5fd06a082f2649e7ce6e08015d2a76c1e9186ca5b3", size = 612904, upload-time = "2026-01-23T15:32:52.317Z" }, - { url = "https://files.pythonhosted.org/packages/c2/f3/7949994264e22639e40718c2daf6f6df5169bf48fb038c008a489ec53a50/greenlet-3.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:33a956fe78bbbda82bfc95e128d61129b32d66bcf0a20a1f0c08aa4839ffa951", size = 1567316, upload-time = "2026-01-23T16:04:23.316Z" }, - { url = "https://files.pythonhosted.org/packages/8d/6e/d73c94d13b6465e9f7cd6231c68abde838bb22408596c05d9059830b7872/greenlet-3.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b065d3284be43728dd280f6f9a13990b56470b81be20375a207cdc814a983f2", size = 1636549, upload-time = "2026-01-23T15:33:48.643Z" }, - { url = "https://files.pythonhosted.org/packages/5e/b3/c9c23a6478b3bcc91f979ce4ca50879e4d0b2bd7b9a53d8ecded719b92e2/greenlet-3.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:27289986f4e5b0edec7b5a91063c109f0276abb09a7e9bdab08437525977c946", size = 227042, upload-time = "2026-01-23T15:33:58.216Z" }, - { url = "https://files.pythonhosted.org/packages/90/e7/824beda656097edee36ab15809fd063447b200cc03a7f6a24c34d520bc88/greenlet-3.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:2f080e028001c5273e0b42690eaf359aeef9cb1389da0f171ea51a5dc3c7608d", size = 226294, upload-time = "2026-01-23T15:30:52.73Z" }, - { url = "https://files.pythonhosted.org/packages/ae/fb/011c7c717213182caf78084a9bea51c8590b0afda98001f69d9f853a495b/greenlet-3.3.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:bd59acd8529b372775cd0fcbc5f420ae20681c5b045ce25bd453ed8455ab99b5", size = 275737, upload-time = "2026-01-23T15:32:16.889Z" }, - { url = "https://files.pythonhosted.org/packages/41/2e/a3a417d620363fdbb08a48b1dd582956a46a61bf8fd27ee8164f9dfe87c2/greenlet-3.3.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b31c05dd84ef6871dd47120386aed35323c944d86c3d91a17c4b8d23df62f15b", size = 646422, upload-time = "2026-01-23T16:01:00.354Z" }, - { url = "https://files.pythonhosted.org/packages/b4/09/c6c4a0db47defafd2d6bab8ddfe47ad19963b4e30f5bed84d75328059f8c/greenlet-3.3.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:02925a0bfffc41e542c70aa14c7eda3593e4d7e274bfcccca1827e6c0875902e", size = 658219, upload-time = "2026-01-23T16:05:30.956Z" }, - { url = "https://files.pythonhosted.org/packages/80/38/9d42d60dffb04b45f03dbab9430898352dba277758640751dc5cc316c521/greenlet-3.3.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34a729e2e4e4ffe9ae2408d5ecaf12f944853f40ad724929b7585bca808a9d6f", size = 660237, upload-time = "2026-01-23T15:32:53.967Z" }, - { url = "https://files.pythonhosted.org/packages/96/61/373c30b7197f9e756e4c81ae90a8d55dc3598c17673f91f4d31c3c689c3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aec9ab04e82918e623415947921dea15851b152b822661cce3f8e4393c3df683", size = 1615261, upload-time = "2026-01-23T16:04:25.066Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d3/ca534310343f5945316f9451e953dcd89b36fe7a19de652a1dc5a0eeef3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:71c767cf281a80d02b6c1bdc41c9468e1f5a494fb11bc8688c360524e273d7b1", size = 1683719, upload-time = "2026-01-23T15:33:50.61Z" }, - { url = "https://files.pythonhosted.org/packages/52/cb/c21a3fd5d2c9c8b622e7bede6d6d00e00551a5ee474ea6d831b5f567a8b4/greenlet-3.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:96aff77af063b607f2489473484e39a0bbae730f2ea90c9e5606c9b73c44174a", size = 228125, upload-time = "2026-01-23T15:32:45.265Z" }, - { url = "https://files.pythonhosted.org/packages/6a/8e/8a2db6d11491837af1de64b8aff23707c6e85241be13c60ed399a72e2ef8/greenlet-3.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:b066e8b50e28b503f604fa538adc764a638b38cf8e81e025011d26e8a627fa79", size = 227519, upload-time = "2026-01-23T15:31:47.284Z" }, - { url = "https://files.pythonhosted.org/packages/28/24/cbbec49bacdcc9ec652a81d3efef7b59f326697e7edf6ed775a5e08e54c2/greenlet-3.3.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:3e63252943c921b90abb035ebe9de832c436401d9c45f262d80e2d06cc659242", size = 282706, upload-time = "2026-01-23T15:33:05.525Z" }, - { url = "https://files.pythonhosted.org/packages/86/2e/4f2b9323c144c4fe8842a4e0d92121465485c3c2c5b9e9b30a52e80f523f/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:76e39058e68eb125de10c92524573924e827927df5d3891fbc97bd55764a8774", size = 651209, upload-time = "2026-01-23T16:01:01.517Z" }, - { url = "https://files.pythonhosted.org/packages/d9/87/50ca60e515f5bb55a2fbc5f0c9b5b156de7d2fc51a0a69abc9d23914a237/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9f9d5e7a9310b7a2f416dd13d2e3fd8b42d803968ea580b7c0f322ccb389b97", size = 654300, upload-time = "2026-01-23T16:05:32.199Z" }, - { url = "https://files.pythonhosted.org/packages/1d/94/74310866dfa2b73dd08659a3d18762f83985ad3281901ba0ee9a815194fb/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92497c78adf3ac703b57f1e3813c2d874f27f71a178f9ea5887855da413cd6d2", size = 653842, upload-time = "2026-01-23T15:32:55.671Z" }, - { url = "https://files.pythonhosted.org/packages/97/43/8bf0ffa3d498eeee4c58c212a3905dd6146c01c8dc0b0a046481ca29b18c/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ed6b402bc74d6557a705e197d47f9063733091ed6357b3de33619d8a8d93ac53", size = 1614917, upload-time = "2026-01-23T16:04:26.276Z" }, - { url = "https://files.pythonhosted.org/packages/89/90/a3be7a5f378fc6e84abe4dcfb2ba32b07786861172e502388b4c90000d1b/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:59913f1e5ada20fde795ba906916aea25d442abcc0593fba7e26c92b7ad76249", size = 1676092, upload-time = "2026-01-23T15:33:52.176Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2b/98c7f93e6db9977aaee07eb1e51ca63bd5f779b900d362791d3252e60558/greenlet-3.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:301860987846c24cb8964bdec0e31a96ad4a2a801b41b4ef40963c1b44f33451", size = 233181, upload-time = "2026-01-23T15:33:00.29Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/8a/99/1cd3411c56a410994669062bd73dd58270c00cc074cac15f385a1fd91f8a/greenlet-3.3.1.tar.gz", hash = "sha256:41848f3230b58c08bb43dee542e74a2a2e34d3c59dc3076cec9151aeeedcae98", size = 184690, upload_time = "2026-01-23T15:31:02.076Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/ab/d26750f2b7242c2b90ea2ad71de70cfcd73a948a49513188a0fc0d6fc15a/greenlet-3.3.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:7ab327905cabb0622adca5971e488064e35115430cec2c35a50fd36e72a315b3", size = 275205, upload_time = "2026-01-23T15:30:24.556Z" }, + { url = "https://files.pythonhosted.org/packages/10/d3/be7d19e8fad7c5a78eeefb2d896a08cd4643e1e90c605c4be3b46264998f/greenlet-3.3.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65be2f026ca6a176f88fb935ee23c18333ccea97048076aef4db1ef5bc0713ac", size = 599284, upload_time = "2026-01-23T16:00:58.584Z" }, + { url = "https://files.pythonhosted.org/packages/ae/21/fe703aaa056fdb0f17e5afd4b5c80195bbdab701208918938bd15b00d39b/greenlet-3.3.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7a3ae05b3d225b4155bda56b072ceb09d05e974bc74be6c3fc15463cf69f33fd", size = 610274, upload_time = "2026-01-23T16:05:29.312Z" }, + { url = "https://files.pythonhosted.org/packages/06/00/95df0b6a935103c0452dad2203f5be8377e551b8466a29650c4c5a5af6cc/greenlet-3.3.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:12184c61e5d64268a160226fb4818af4df02cfead8379d7f8b99a56c3a54ff3e", size = 624375, upload_time = "2026-01-23T16:15:55.915Z" }, + { url = "https://files.pythonhosted.org/packages/cb/86/5c6ab23bb3c28c21ed6bebad006515cfe08b04613eb105ca0041fecca852/greenlet-3.3.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6423481193bbbe871313de5fd06a082f2649e7ce6e08015d2a76c1e9186ca5b3", size = 612904, upload_time = "2026-01-23T15:32:52.317Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f3/7949994264e22639e40718c2daf6f6df5169bf48fb038c008a489ec53a50/greenlet-3.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:33a956fe78bbbda82bfc95e128d61129b32d66bcf0a20a1f0c08aa4839ffa951", size = 1567316, upload_time = "2026-01-23T16:04:23.316Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6e/d73c94d13b6465e9f7cd6231c68abde838bb22408596c05d9059830b7872/greenlet-3.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b065d3284be43728dd280f6f9a13990b56470b81be20375a207cdc814a983f2", size = 1636549, upload_time = "2026-01-23T15:33:48.643Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b3/c9c23a6478b3bcc91f979ce4ca50879e4d0b2bd7b9a53d8ecded719b92e2/greenlet-3.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:27289986f4e5b0edec7b5a91063c109f0276abb09a7e9bdab08437525977c946", size = 227042, upload_time = "2026-01-23T15:33:58.216Z" }, + { url = "https://files.pythonhosted.org/packages/90/e7/824beda656097edee36ab15809fd063447b200cc03a7f6a24c34d520bc88/greenlet-3.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:2f080e028001c5273e0b42690eaf359aeef9cb1389da0f171ea51a5dc3c7608d", size = 226294, upload_time = "2026-01-23T15:30:52.73Z" }, + { url = "https://files.pythonhosted.org/packages/ae/fb/011c7c717213182caf78084a9bea51c8590b0afda98001f69d9f853a495b/greenlet-3.3.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:bd59acd8529b372775cd0fcbc5f420ae20681c5b045ce25bd453ed8455ab99b5", size = 275737, upload_time = "2026-01-23T15:32:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/41/2e/a3a417d620363fdbb08a48b1dd582956a46a61bf8fd27ee8164f9dfe87c2/greenlet-3.3.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b31c05dd84ef6871dd47120386aed35323c944d86c3d91a17c4b8d23df62f15b", size = 646422, upload_time = "2026-01-23T16:01:00.354Z" }, + { url = "https://files.pythonhosted.org/packages/b4/09/c6c4a0db47defafd2d6bab8ddfe47ad19963b4e30f5bed84d75328059f8c/greenlet-3.3.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:02925a0bfffc41e542c70aa14c7eda3593e4d7e274bfcccca1827e6c0875902e", size = 658219, upload_time = "2026-01-23T16:05:30.956Z" }, + { url = "https://files.pythonhosted.org/packages/e2/89/b95f2ddcc5f3c2bc09c8ee8d77be312df7f9e7175703ab780f2014a0e781/greenlet-3.3.1-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3e0f3878ca3a3ff63ab4ea478585942b53df66ddde327b59ecb191b19dbbd62d", size = 671455, upload_time = "2026-01-23T16:15:57.232Z" }, + { url = "https://files.pythonhosted.org/packages/80/38/9d42d60dffb04b45f03dbab9430898352dba277758640751dc5cc316c521/greenlet-3.3.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34a729e2e4e4ffe9ae2408d5ecaf12f944853f40ad724929b7585bca808a9d6f", size = 660237, upload_time = "2026-01-23T15:32:53.967Z" }, + { url = "https://files.pythonhosted.org/packages/96/61/373c30b7197f9e756e4c81ae90a8d55dc3598c17673f91f4d31c3c689c3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aec9ab04e82918e623415947921dea15851b152b822661cce3f8e4393c3df683", size = 1615261, upload_time = "2026-01-23T16:04:25.066Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d3/ca534310343f5945316f9451e953dcd89b36fe7a19de652a1dc5a0eeef3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:71c767cf281a80d02b6c1bdc41c9468e1f5a494fb11bc8688c360524e273d7b1", size = 1683719, upload_time = "2026-01-23T15:33:50.61Z" }, + { url = "https://files.pythonhosted.org/packages/52/cb/c21a3fd5d2c9c8b622e7bede6d6d00e00551a5ee474ea6d831b5f567a8b4/greenlet-3.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:96aff77af063b607f2489473484e39a0bbae730f2ea90c9e5606c9b73c44174a", size = 228125, upload_time = "2026-01-23T15:32:45.265Z" }, + { url = "https://files.pythonhosted.org/packages/6a/8e/8a2db6d11491837af1de64b8aff23707c6e85241be13c60ed399a72e2ef8/greenlet-3.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:b066e8b50e28b503f604fa538adc764a638b38cf8e81e025011d26e8a627fa79", size = 227519, upload_time = "2026-01-23T15:31:47.284Z" }, + { url = "https://files.pythonhosted.org/packages/28/24/cbbec49bacdcc9ec652a81d3efef7b59f326697e7edf6ed775a5e08e54c2/greenlet-3.3.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:3e63252943c921b90abb035ebe9de832c436401d9c45f262d80e2d06cc659242", size = 282706, upload_time = "2026-01-23T15:33:05.525Z" }, + { url = "https://files.pythonhosted.org/packages/86/2e/4f2b9323c144c4fe8842a4e0d92121465485c3c2c5b9e9b30a52e80f523f/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:76e39058e68eb125de10c92524573924e827927df5d3891fbc97bd55764a8774", size = 651209, upload_time = "2026-01-23T16:01:01.517Z" }, + { url = "https://files.pythonhosted.org/packages/d9/87/50ca60e515f5bb55a2fbc5f0c9b5b156de7d2fc51a0a69abc9d23914a237/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9f9d5e7a9310b7a2f416dd13d2e3fd8b42d803968ea580b7c0f322ccb389b97", size = 654300, upload_time = "2026-01-23T16:05:32.199Z" }, + { url = "https://files.pythonhosted.org/packages/7c/25/c51a63f3f463171e09cb586eb64db0861eb06667ab01a7968371a24c4f3b/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b9721549a95db96689458a1e0ae32412ca18776ed004463df3a9299c1b257ab", size = 662574, upload_time = "2026-01-23T16:15:58.364Z" }, + { url = "https://files.pythonhosted.org/packages/1d/94/74310866dfa2b73dd08659a3d18762f83985ad3281901ba0ee9a815194fb/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92497c78adf3ac703b57f1e3813c2d874f27f71a178f9ea5887855da413cd6d2", size = 653842, upload_time = "2026-01-23T15:32:55.671Z" }, + { url = "https://files.pythonhosted.org/packages/97/43/8bf0ffa3d498eeee4c58c212a3905dd6146c01c8dc0b0a046481ca29b18c/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ed6b402bc74d6557a705e197d47f9063733091ed6357b3de33619d8a8d93ac53", size = 1614917, upload_time = "2026-01-23T16:04:26.276Z" }, + { url = "https://files.pythonhosted.org/packages/89/90/a3be7a5f378fc6e84abe4dcfb2ba32b07786861172e502388b4c90000d1b/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:59913f1e5ada20fde795ba906916aea25d442abcc0593fba7e26c92b7ad76249", size = 1676092, upload_time = "2026-01-23T15:33:52.176Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2b/98c7f93e6db9977aaee07eb1e51ca63bd5f779b900d362791d3252e60558/greenlet-3.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:301860987846c24cb8964bdec0e31a96ad4a2a801b41b4ef40963c1b44f33451", size = 233181, upload_time = "2026-01-23T15:33:00.29Z" }, ] [[package]] @@ -1205,9 +1216,9 @@ dependencies = [ { name = "grpcio" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/1e/1011451679a983f2f5c6771a1682542ecb027776762ad031fd0d7129164b/grpc_google_iam_v1-0.14.3.tar.gz", hash = "sha256:879ac4ef33136c5491a6300e27575a9ec760f6cdf9a2518798c1b8977a5dc389", size = 23745, upload-time = "2025-10-15T21:14:53.318Z" } +sdist = { url = "https://files.pythonhosted.org/packages/76/1e/1011451679a983f2f5c6771a1682542ecb027776762ad031fd0d7129164b/grpc_google_iam_v1-0.14.3.tar.gz", hash = "sha256:879ac4ef33136c5491a6300e27575a9ec760f6cdf9a2518798c1b8977a5dc389", size = 23745, upload_time = "2025-10-15T21:14:53.318Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/bd/330a1bbdb1afe0b96311249e699b6dc9cfc17916394fd4503ac5aca2514b/grpc_google_iam_v1-0.14.3-py3-none-any.whl", hash = "sha256:7a7f697e017a067206a3dfef44e4c634a34d3dee135fe7d7a4613fe3e59217e6", size = 32690, upload-time = "2025-10-15T21:14:51.72Z" }, + { url = "https://files.pythonhosted.org/packages/4a/bd/330a1bbdb1afe0b96311249e699b6dc9cfc17916394fd4503ac5aca2514b/grpc_google_iam_v1-0.14.3-py3-none-any.whl", hash = "sha256:7a7f697e017a067206a3dfef44e4c634a34d3dee135fe7d7a4613fe3e59217e6", size = 32690, upload_time = "2025-10-15T21:14:51.72Z" }, ] [[package]] @@ -1217,9 +1228,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/28/57449d5567adf4c1d3e216aaca545913fbc21a915f2da6790d6734aac76e/grpc-interceptor-0.15.4.tar.gz", hash = "sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926", size = 19322, upload-time = "2023-11-16T02:05:42.459Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/28/57449d5567adf4c1d3e216aaca545913fbc21a915f2da6790d6734aac76e/grpc-interceptor-0.15.4.tar.gz", hash = "sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926", size = 19322, upload_time = "2023-11-16T02:05:42.459Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/ac/8d53f230a7443401ce81791ec50a3b0e54924bf615ad287654fa4a2f5cdc/grpc_interceptor-0.15.4-py3-none-any.whl", hash = "sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d", size = 20848, upload-time = "2023-11-16T02:05:40.913Z" }, + { url = "https://files.pythonhosted.org/packages/15/ac/8d53f230a7443401ce81791ec50a3b0e54924bf615ad287654fa4a2f5cdc/grpc_interceptor-0.15.4-py3-none-any.whl", hash = "sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d", size = 20848, upload_time = "2023-11-16T02:05:40.913Z" }, ] [[package]] @@ -1229,28 +1240,28 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload-time = "2026-02-06T09:55:52.035Z" }, - { url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload-time = "2026-02-06T09:55:55.494Z" }, - { url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload-time = "2026-02-06T09:55:58.533Z" }, - { url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload-time = "2026-02-06T09:56:01.786Z" }, - { url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload-time = "2026-02-06T09:56:04.529Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload-time = "2026-02-06T09:56:08.397Z" }, - { url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload-time = "2026-02-06T09:56:10.914Z" }, - { url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload-time = "2026-02-06T09:56:13.593Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload-time = "2026-02-06T09:56:15.601Z" }, - { url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload-time = "2026-02-06T09:56:17.882Z" }, - { url = "https://files.pythonhosted.org/packages/29/f2/b56e43e3c968bfe822fa6ce5bca10d5c723aa40875b48791ce1029bb78c7/grpcio-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:e87cbc002b6f440482b3519e36e1313eb5443e9e9e73d6a52d43bd2004fcfd8e", size = 5920591, upload-time = "2026-02-06T09:56:20.758Z" }, - { url = "https://files.pythonhosted.org/packages/5d/81/1f3b65bd30c334167bfa8b0d23300a44e2725ce39bba5b76a2460d85f745/grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:c41bc64626db62e72afec66b0c8a0da76491510015417c127bfc53b2fe6d7f7f", size = 11813685, upload-time = "2026-02-06T09:56:24.315Z" }, - { url = "https://files.pythonhosted.org/packages/0e/1c/bbe2f8216a5bd3036119c544d63c2e592bdf4a8ec6e4a1867592f4586b26/grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8dfffba826efcf366b1e3ccc37e67afe676f290e13a3b48d31a46739f80a8724", size = 6487803, upload-time = "2026-02-06T09:56:27.367Z" }, - { url = "https://files.pythonhosted.org/packages/16/5c/a6b2419723ea7ddce6308259a55e8e7593d88464ce8db9f4aa857aba96fa/grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74be1268d1439eaaf552c698cdb11cd594f0c49295ae6bb72c34ee31abbe611b", size = 7173206, upload-time = "2026-02-06T09:56:29.876Z" }, - { url = "https://files.pythonhosted.org/packages/df/1e/b8801345629a415ea7e26c83d75eb5dbe91b07ffe5210cc517348a8d4218/grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be63c88b32e6c0f1429f1398ca5c09bc64b0d80950c8bb7807d7d7fb36fb84c7", size = 6693826, upload-time = "2026-02-06T09:56:32.305Z" }, - { url = "https://files.pythonhosted.org/packages/34/84/0de28eac0377742679a510784f049738a80424b17287739fc47d63c2439e/grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c586ac70e855c721bda8f548d38c3ca66ac791dc49b66a8281a1f99db85e452", size = 7277897, upload-time = "2026-02-06T09:56:34.915Z" }, - { url = "https://files.pythonhosted.org/packages/ca/9c/ad8685cfe20559a9edb66f735afdcb2b7d3de69b13666fdfc542e1916ebd/grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:35eb275bf1751d2ffbd8f57cdbc46058e857cf3971041521b78b7db94bdaf127", size = 8252404, upload-time = "2026-02-06T09:56:37.553Z" }, - { url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" }, - { url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" }, - { url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload_time = "2026-02-06T09:57:18.093Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload_time = "2026-02-06T09:55:52.035Z" }, + { url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload_time = "2026-02-06T09:55:55.494Z" }, + { url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload_time = "2026-02-06T09:55:58.533Z" }, + { url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload_time = "2026-02-06T09:56:01.786Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload_time = "2026-02-06T09:56:04.529Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload_time = "2026-02-06T09:56:08.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload_time = "2026-02-06T09:56:10.914Z" }, + { url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload_time = "2026-02-06T09:56:13.593Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload_time = "2026-02-06T09:56:15.601Z" }, + { url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload_time = "2026-02-06T09:56:17.882Z" }, + { url = "https://files.pythonhosted.org/packages/29/f2/b56e43e3c968bfe822fa6ce5bca10d5c723aa40875b48791ce1029bb78c7/grpcio-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:e87cbc002b6f440482b3519e36e1313eb5443e9e9e73d6a52d43bd2004fcfd8e", size = 5920591, upload_time = "2026-02-06T09:56:20.758Z" }, + { url = "https://files.pythonhosted.org/packages/5d/81/1f3b65bd30c334167bfa8b0d23300a44e2725ce39bba5b76a2460d85f745/grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:c41bc64626db62e72afec66b0c8a0da76491510015417c127bfc53b2fe6d7f7f", size = 11813685, upload_time = "2026-02-06T09:56:24.315Z" }, + { url = "https://files.pythonhosted.org/packages/0e/1c/bbe2f8216a5bd3036119c544d63c2e592bdf4a8ec6e4a1867592f4586b26/grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8dfffba826efcf366b1e3ccc37e67afe676f290e13a3b48d31a46739f80a8724", size = 6487803, upload_time = "2026-02-06T09:56:27.367Z" }, + { url = "https://files.pythonhosted.org/packages/16/5c/a6b2419723ea7ddce6308259a55e8e7593d88464ce8db9f4aa857aba96fa/grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74be1268d1439eaaf552c698cdb11cd594f0c49295ae6bb72c34ee31abbe611b", size = 7173206, upload_time = "2026-02-06T09:56:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/df/1e/b8801345629a415ea7e26c83d75eb5dbe91b07ffe5210cc517348a8d4218/grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be63c88b32e6c0f1429f1398ca5c09bc64b0d80950c8bb7807d7d7fb36fb84c7", size = 6693826, upload_time = "2026-02-06T09:56:32.305Z" }, + { url = "https://files.pythonhosted.org/packages/34/84/0de28eac0377742679a510784f049738a80424b17287739fc47d63c2439e/grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c586ac70e855c721bda8f548d38c3ca66ac791dc49b66a8281a1f99db85e452", size = 7277897, upload_time = "2026-02-06T09:56:34.915Z" }, + { url = "https://files.pythonhosted.org/packages/ca/9c/ad8685cfe20559a9edb66f735afdcb2b7d3de69b13666fdfc542e1916ebd/grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:35eb275bf1751d2ffbd8f57cdbc46058e857cf3971041521b78b7db94bdaf127", size = 8252404, upload_time = "2026-02-06T09:56:37.553Z" }, + { url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload_time = "2026-02-06T09:56:40.173Z" }, + { url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload_time = "2026-02-06T09:56:43.258Z" }, + { url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload_time = "2026-02-06T09:56:45.885Z" }, ] [[package]] @@ -1262,47 +1273,47 @@ dependencies = [ { name = "grpcio" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/cd/89ce482a931b543b92cdd9b2888805518c4620e0094409acb8c81dd4610a/grpcio_status-1.78.0.tar.gz", hash = "sha256:a34cfd28101bfea84b5aa0f936b4b423019e9213882907166af6b3bddc59e189", size = 13808, upload-time = "2026-02-06T10:01:48.034Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/cd/89ce482a931b543b92cdd9b2888805518c4620e0094409acb8c81dd4610a/grpcio_status-1.78.0.tar.gz", hash = "sha256:a34cfd28101bfea84b5aa0f936b4b423019e9213882907166af6b3bddc59e189", size = 13808, upload_time = "2026-02-06T10:01:48.034Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/8a/1241ec22c41028bddd4a052ae9369267b4475265ad0ce7140974548dc3fa/grpcio_status-1.78.0-py3-none-any.whl", hash = "sha256:b492b693d4bf27b47a6c32590701724f1d3b9444b36491878fb71f6208857f34", size = 14523, upload-time = "2026-02-06T10:01:32.584Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/1241ec22c41028bddd4a052ae9369267b4475265ad0ce7140974548dc3fa/grpcio_status-1.78.0-py3-none-any.whl", hash = "sha256:b492b693d4bf27b47a6c32590701724f1d3b9444b36491878fb71f6208857f34", size = 14523, upload_time = "2026-02-06T10:01:32.584Z" }, ] [[package]] name = "h11" version = "0.16.0" 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" } +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" }, + { 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" }, ] [[package]] name = "hf-xet" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" }, - { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" }, - { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" }, - { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" }, - { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" }, - { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, - { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, - { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, - { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, - { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, - { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, - { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload_time = "2025-10-24T19:04:32.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload_time = "2025-10-24T19:04:11.422Z" }, + { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload_time = "2025-10-24T19:04:09.586Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload_time = "2025-10-24T19:04:00.314Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload_time = "2025-10-24T19:03:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload_time = "2025-10-24T19:04:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload_time = "2025-10-24T19:04:22.549Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload_time = "2025-10-24T19:04:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload_time = "2025-10-24T19:04:19.01Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload_time = "2025-10-24T19:04:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload_time = "2025-10-24T19:04:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload_time = "2025-10-24T19:04:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload_time = "2025-10-24T19:04:28.598Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload_time = "2025-10-24T19:04:30.397Z" }, + { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload_time = "2025-10-24T19:04:37.463Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload_time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload_time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload_time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload_time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload_time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload_time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload_time = "2025-10-24T19:04:35.928Z" }, ] [[package]] @@ -1313,9 +1324,9 @@ dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload_time = "2025-04-24T22:06:22.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload_time = "2025-04-24T22:06:20.566Z" }, ] [[package]] @@ -1325,9 +1336,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyparsing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/1f/e86365613582c027dda5ddb64e1010e57a3d53e99ab8a72093fa13d565ec/httplib2-0.31.2.tar.gz", hash = "sha256:385e0869d7397484f4eab426197a4c020b606edd43372492337c0b4010ae5d24", size = 250800, upload-time = "2026-01-23T11:04:44.165Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/1f/e86365613582c027dda5ddb64e1010e57a3d53e99ab8a72093fa13d565ec/httplib2-0.31.2.tar.gz", hash = "sha256:385e0869d7397484f4eab426197a4c020b606edd43372492337c0b4010ae5d24", size = 250800, upload_time = "2026-01-23T11:04:44.165Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/90/fd509079dfcab01102c0fdd87f3a9506894bc70afcf9e9785ef6b2b3aff6/httplib2-0.31.2-py3-none-any.whl", hash = "sha256:dbf0c2fa3862acf3c55c078ea9c0bc4481d7dc5117cae71be9514912cf9f8349", size = 91099, upload-time = "2026-01-23T11:04:42.78Z" }, + { url = "https://files.pythonhosted.org/packages/2f/90/fd509079dfcab01102c0fdd87f3a9506894bc70afcf9e9785ef6b2b3aff6/httplib2-0.31.2-py3-none-any.whl", hash = "sha256:dbf0c2fa3862acf3c55c078ea9c0bc4481d7dc5117cae71be9514912cf9f8349", size = 91099, upload_time = "2026-01-23T11:04:42.78Z" }, ] [[package]] @@ -1340,18 +1351,18 @@ dependencies = [ { name = "httpcore" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload_time = "2024-12-06T15:37:23.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload_time = "2024-12-06T15:37:21.509Z" }, ] [[package]] name = "httpx-sse" version = "0.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload_time = "2025-10-10T21:48:22.271Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, + { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload_time = "2025-10-10T21:48:21.158Z" }, ] [[package]] @@ -1370,18 +1381,18 @@ dependencies = [ { name = "typer-slim" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/fc/eb9bc06130e8bbda6a616e1b80a7aa127681c448d6b49806f61db2670b61/huggingface_hub-1.4.1.tar.gz", hash = "sha256:b41131ec35e631e7383ab26d6146b8d8972abc8b6309b963b306fbcca87f5ed5", size = 642156, upload-time = "2026-02-06T09:20:03.013Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/fc/eb9bc06130e8bbda6a616e1b80a7aa127681c448d6b49806f61db2670b61/huggingface_hub-1.4.1.tar.gz", hash = "sha256:b41131ec35e631e7383ab26d6146b8d8972abc8b6309b963b306fbcca87f5ed5", size = 642156, upload_time = "2026-02-06T09:20:03.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/ae/2f6d96b4e6c5478d87d606a1934b5d436c4a2bce6bb7c6fdece891c128e3/huggingface_hub-1.4.1-py3-none-any.whl", hash = "sha256:9931d075fb7a79af5abc487106414ec5fba2c0ae86104c0c62fd6cae38873d18", size = 553326, upload-time = "2026-02-06T09:20:00.728Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ae/2f6d96b4e6c5478d87d606a1934b5d436c4a2bce6bb7c6fdece891c128e3/huggingface_hub-1.4.1-py3-none-any.whl", hash = "sha256:9931d075fb7a79af5abc487106414ec5fba2c0ae86104c0c62fd6cae38873d18", size = 553326, upload_time = "2026-02-06T09:20:00.728Z" }, ] [[package]] name = "idna" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload_time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload_time = "2025-10-12T14:55:18.883Z" }, ] [[package]] @@ -1391,9 +1402,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload_time = "2025-12-21T10:00:19.278Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload_time = "2025-12-21T10:00:18.329Z" }, ] [[package]] @@ -1403,60 +1414,60 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload_time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload_time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "jiter" version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/5e/4ec91646aee381d01cdb9974e30882c9cd3b8c5d1079d6b5ff4af522439a/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4", size = 164847, upload-time = "2026-02-02T12:37:56.441Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/91/9c/7ee5a6ff4b9991e1a45263bfc46731634c4a2bde27dfda6c8251df2d958c/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf", size = 306897, upload-time = "2026-02-02T12:36:16.748Z" }, - { url = "https://files.pythonhosted.org/packages/7c/02/be5b870d1d2be5dd6a91bdfb90f248fbb7dcbd21338f092c6b89817c3dbf/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a", size = 317507, upload-time = "2026-02-02T12:36:18.351Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/b25d2ec333615f5f284f3a4024f7ce68cfa0604c322c6808b2344c7f5d2b/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb", size = 350560, upload-time = "2026-02-02T12:36:19.746Z" }, - { url = "https://files.pythonhosted.org/packages/be/ec/74dcb99fef0aca9fbe56b303bf79f6bd839010cb18ad41000bf6cc71eec0/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2", size = 363232, upload-time = "2026-02-02T12:36:21.243Z" }, - { url = "https://files.pythonhosted.org/packages/1b/37/f17375e0bb2f6a812d4dd92d7616e41917f740f3e71343627da9db2824ce/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f", size = 483727, upload-time = "2026-02-02T12:36:22.688Z" }, - { url = "https://files.pythonhosted.org/packages/77/d2/a71160a5ae1a1e66c1395b37ef77da67513b0adba73b993a27fbe47eb048/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159", size = 370799, upload-time = "2026-02-02T12:36:24.106Z" }, - { url = "https://files.pythonhosted.org/packages/01/99/ed5e478ff0eb4e8aa5fd998f9d69603c9fd3f32de3bd16c2b1194f68361c/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663", size = 359120, upload-time = "2026-02-02T12:36:25.519Z" }, - { url = "https://files.pythonhosted.org/packages/16/be/7ffd08203277a813f732ba897352797fa9493faf8dc7995b31f3d9cb9488/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa", size = 390664, upload-time = "2026-02-02T12:36:26.866Z" }, - { url = "https://files.pythonhosted.org/packages/d1/84/e0787856196d6d346264d6dcccb01f741e5f0bd014c1d9a2ebe149caf4f3/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820", size = 513543, upload-time = "2026-02-02T12:36:28.217Z" }, - { url = "https://files.pythonhosted.org/packages/65/50/ecbd258181c4313cf79bca6c88fb63207d04d5bf5e4f65174114d072aa55/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68", size = 547262, upload-time = "2026-02-02T12:36:29.678Z" }, - { url = "https://files.pythonhosted.org/packages/27/da/68f38d12e7111d2016cd198161b36e1f042bd115c169255bcb7ec823a3bf/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72", size = 200630, upload-time = "2026-02-02T12:36:31.808Z" }, - { url = "https://files.pythonhosted.org/packages/25/65/3bd1a972c9a08ecd22eb3b08a95d1941ebe6938aea620c246cf426ae09c2/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc", size = 202602, upload-time = "2026-02-02T12:36:33.679Z" }, - { url = "https://files.pythonhosted.org/packages/15/fe/13bd3678a311aa67686bb303654792c48206a112068f8b0b21426eb6851e/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b", size = 185939, upload-time = "2026-02-02T12:36:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/49/19/a929ec002ad3228bc97ca01dbb14f7632fffdc84a95ec92ceaf4145688ae/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10", size = 316616, upload-time = "2026-02-02T12:36:36.579Z" }, - { url = "https://files.pythonhosted.org/packages/52/56/d19a9a194afa37c1728831e5fb81b7722c3de18a3109e8f282bfc23e587a/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef", size = 346850, upload-time = "2026-02-02T12:36:38.058Z" }, - { url = "https://files.pythonhosted.org/packages/36/4a/94e831c6bf287754a8a019cb966ed39ff8be6ab78cadecf08df3bb02d505/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6", size = 358551, upload-time = "2026-02-02T12:36:39.417Z" }, - { url = "https://files.pythonhosted.org/packages/a2/ec/a4c72c822695fa80e55d2b4142b73f0012035d9fcf90eccc56bc060db37c/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d", size = 201950, upload-time = "2026-02-02T12:36:40.791Z" }, - { url = "https://files.pythonhosted.org/packages/b6/00/393553ec27b824fbc29047e9c7cd4a3951d7fbe4a76743f17e44034fa4e4/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d", size = 185852, upload-time = "2026-02-02T12:36:42.077Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f5/f1997e987211f6f9bd71b8083047b316208b4aca0b529bb5f8c96c89ef3e/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0", size = 308804, upload-time = "2026-02-02T12:36:43.496Z" }, - { url = "https://files.pythonhosted.org/packages/cd/8f/5482a7677731fd44881f0204981ce2d7175db271f82cba2085dd2212e095/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91", size = 318787, upload-time = "2026-02-02T12:36:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b9/7257ac59778f1cd025b26a23c5520a36a424f7f1b068f2442a5b499b7464/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09", size = 353880, upload-time = "2026-02-02T12:36:47.365Z" }, - { url = "https://files.pythonhosted.org/packages/c3/87/719eec4a3f0841dad99e3d3604ee4cba36af4419a76f3cb0b8e2e691ad67/jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607", size = 366702, upload-time = "2026-02-02T12:36:48.871Z" }, - { url = "https://files.pythonhosted.org/packages/d2/65/415f0a75cf6921e43365a1bc227c565cb949caca8b7532776e430cbaa530/jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66", size = 486319, upload-time = "2026-02-02T12:36:53.006Z" }, - { url = "https://files.pythonhosted.org/packages/54/a2/9e12b48e82c6bbc6081fd81abf915e1443add1b13d8fc586e1d90bb02bb8/jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2", size = 372289, upload-time = "2026-02-02T12:36:54.593Z" }, - { url = "https://files.pythonhosted.org/packages/4e/c1/e4693f107a1789a239c759a432e9afc592366f04e901470c2af89cfd28e1/jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad", size = 360165, upload-time = "2026-02-02T12:36:56.112Z" }, - { url = "https://files.pythonhosted.org/packages/17/08/91b9ea976c1c758240614bd88442681a87672eebc3d9a6dde476874e706b/jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d", size = 389634, upload-time = "2026-02-02T12:36:57.495Z" }, - { url = "https://files.pythonhosted.org/packages/18/23/58325ef99390d6d40427ed6005bf1ad54f2577866594bcf13ce55675f87d/jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df", size = 514933, upload-time = "2026-02-02T12:36:58.909Z" }, - { url = "https://files.pythonhosted.org/packages/5b/25/69f1120c7c395fd276c3996bb8adefa9c6b84c12bb7111e5c6ccdcd8526d/jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d", size = 548842, upload-time = "2026-02-02T12:37:00.433Z" }, - { url = "https://files.pythonhosted.org/packages/18/05/981c9669d86850c5fbb0d9e62bba144787f9fba84546ba43d624ee27ef29/jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6", size = 202108, upload-time = "2026-02-02T12:37:01.718Z" }, - { url = "https://files.pythonhosted.org/packages/8d/96/cdcf54dd0b0341db7d25413229888a346c7130bd20820530905fdb65727b/jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f", size = 204027, upload-time = "2026-02-02T12:37:03.075Z" }, - { url = "https://files.pythonhosted.org/packages/fb/f9/724bcaaab7a3cd727031fe4f6995cb86c4bd344909177c186699c8dec51a/jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d", size = 187199, upload-time = "2026-02-02T12:37:04.414Z" }, - { url = "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0", size = 318423, upload-time = "2026-02-02T12:37:05.806Z" }, - { url = "https://files.pythonhosted.org/packages/4f/3b/f77d342a54d4ebcd128e520fc58ec2f5b30a423b0fd26acdfc0c6fef8e26/jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40", size = 351438, upload-time = "2026-02-02T12:37:07.189Z" }, - { url = "https://files.pythonhosted.org/packages/76/b3/ba9a69f0e4209bd3331470c723c2f5509e6f0482e416b612431a5061ed71/jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202", size = 364774, upload-time = "2026-02-02T12:37:08.579Z" }, - { url = "https://files.pythonhosted.org/packages/b3/16/6cdb31fa342932602458dbb631bfbd47f601e03d2e4950740e0b2100b570/jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0", size = 487238, upload-time = "2026-02-02T12:37:10.066Z" }, - { url = "https://files.pythonhosted.org/packages/ed/b1/956cc7abaca8d95c13aa8d6c9b3f3797241c246cd6e792934cc4c8b250d2/jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95", size = 372892, upload-time = "2026-02-02T12:37:11.656Z" }, - { url = "https://files.pythonhosted.org/packages/26/c4/97ecde8b1e74f67b8598c57c6fccf6df86ea7861ed29da84629cdbba76c4/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59", size = 360309, upload-time = "2026-02-02T12:37:13.244Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d7/eabe3cf46715854ccc80be2cd78dd4c36aedeb30751dbf85a1d08c14373c/jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe", size = 389607, upload-time = "2026-02-02T12:37:14.881Z" }, - { url = "https://files.pythonhosted.org/packages/df/2d/03963fc0804e6109b82decfb9974eb92df3797fe7222428cae12f8ccaa0c/jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939", size = 514986, upload-time = "2026-02-02T12:37:16.326Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/8c83b45eb3eb1c1e18d841fe30b4b5bc5619d781267ca9bc03e005d8fd0a/jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9", size = 548756, upload-time = "2026-02-02T12:37:17.736Z" }, - { url = "https://files.pythonhosted.org/packages/47/66/eea81dfff765ed66c68fd2ed8c96245109e13c896c2a5015c7839c92367e/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6", size = 201196, upload-time = "2026-02-02T12:37:19.101Z" }, - { url = "https://files.pythonhosted.org/packages/ff/32/4ac9c7a76402f8f00d00842a7f6b83b284d0cf7c1e9d4227bc95aa6d17fa/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8", size = 204215, upload-time = "2026-02-02T12:37:20.495Z" }, - { url = "https://files.pythonhosted.org/packages/f9/8e/7def204fea9f9be8b3c21a6f2dd6c020cf56c7d5ff753e0e23ed7f9ea57e/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024", size = 187152, upload-time = "2026-02-02T12:37:22.124Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0d/5e/4ec91646aee381d01cdb9974e30882c9cd3b8c5d1079d6b5ff4af522439a/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4", size = 164847, upload_time = "2026-02-02T12:37:56.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/9c/7ee5a6ff4b9991e1a45263bfc46731634c4a2bde27dfda6c8251df2d958c/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf", size = 306897, upload_time = "2026-02-02T12:36:16.748Z" }, + { url = "https://files.pythonhosted.org/packages/7c/02/be5b870d1d2be5dd6a91bdfb90f248fbb7dcbd21338f092c6b89817c3dbf/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a", size = 317507, upload_time = "2026-02-02T12:36:18.351Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/b25d2ec333615f5f284f3a4024f7ce68cfa0604c322c6808b2344c7f5d2b/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb", size = 350560, upload_time = "2026-02-02T12:36:19.746Z" }, + { url = "https://files.pythonhosted.org/packages/be/ec/74dcb99fef0aca9fbe56b303bf79f6bd839010cb18ad41000bf6cc71eec0/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2", size = 363232, upload_time = "2026-02-02T12:36:21.243Z" }, + { url = "https://files.pythonhosted.org/packages/1b/37/f17375e0bb2f6a812d4dd92d7616e41917f740f3e71343627da9db2824ce/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f", size = 483727, upload_time = "2026-02-02T12:36:22.688Z" }, + { url = "https://files.pythonhosted.org/packages/77/d2/a71160a5ae1a1e66c1395b37ef77da67513b0adba73b993a27fbe47eb048/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159", size = 370799, upload_time = "2026-02-02T12:36:24.106Z" }, + { url = "https://files.pythonhosted.org/packages/01/99/ed5e478ff0eb4e8aa5fd998f9d69603c9fd3f32de3bd16c2b1194f68361c/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663", size = 359120, upload_time = "2026-02-02T12:36:25.519Z" }, + { url = "https://files.pythonhosted.org/packages/16/be/7ffd08203277a813f732ba897352797fa9493faf8dc7995b31f3d9cb9488/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa", size = 390664, upload_time = "2026-02-02T12:36:26.866Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/e0787856196d6d346264d6dcccb01f741e5f0bd014c1d9a2ebe149caf4f3/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820", size = 513543, upload_time = "2026-02-02T12:36:28.217Z" }, + { url = "https://files.pythonhosted.org/packages/65/50/ecbd258181c4313cf79bca6c88fb63207d04d5bf5e4f65174114d072aa55/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68", size = 547262, upload_time = "2026-02-02T12:36:29.678Z" }, + { url = "https://files.pythonhosted.org/packages/27/da/68f38d12e7111d2016cd198161b36e1f042bd115c169255bcb7ec823a3bf/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72", size = 200630, upload_time = "2026-02-02T12:36:31.808Z" }, + { url = "https://files.pythonhosted.org/packages/25/65/3bd1a972c9a08ecd22eb3b08a95d1941ebe6938aea620c246cf426ae09c2/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc", size = 202602, upload_time = "2026-02-02T12:36:33.679Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/13bd3678a311aa67686bb303654792c48206a112068f8b0b21426eb6851e/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b", size = 185939, upload_time = "2026-02-02T12:36:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/49/19/a929ec002ad3228bc97ca01dbb14f7632fffdc84a95ec92ceaf4145688ae/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10", size = 316616, upload_time = "2026-02-02T12:36:36.579Z" }, + { url = "https://files.pythonhosted.org/packages/52/56/d19a9a194afa37c1728831e5fb81b7722c3de18a3109e8f282bfc23e587a/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef", size = 346850, upload_time = "2026-02-02T12:36:38.058Z" }, + { url = "https://files.pythonhosted.org/packages/36/4a/94e831c6bf287754a8a019cb966ed39ff8be6ab78cadecf08df3bb02d505/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6", size = 358551, upload_time = "2026-02-02T12:36:39.417Z" }, + { url = "https://files.pythonhosted.org/packages/a2/ec/a4c72c822695fa80e55d2b4142b73f0012035d9fcf90eccc56bc060db37c/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d", size = 201950, upload_time = "2026-02-02T12:36:40.791Z" }, + { url = "https://files.pythonhosted.org/packages/b6/00/393553ec27b824fbc29047e9c7cd4a3951d7fbe4a76743f17e44034fa4e4/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d", size = 185852, upload_time = "2026-02-02T12:36:42.077Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f5/f1997e987211f6f9bd71b8083047b316208b4aca0b529bb5f8c96c89ef3e/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0", size = 308804, upload_time = "2026-02-02T12:36:43.496Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8f/5482a7677731fd44881f0204981ce2d7175db271f82cba2085dd2212e095/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91", size = 318787, upload_time = "2026-02-02T12:36:45.071Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b9/7257ac59778f1cd025b26a23c5520a36a424f7f1b068f2442a5b499b7464/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09", size = 353880, upload_time = "2026-02-02T12:36:47.365Z" }, + { url = "https://files.pythonhosted.org/packages/c3/87/719eec4a3f0841dad99e3d3604ee4cba36af4419a76f3cb0b8e2e691ad67/jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607", size = 366702, upload_time = "2026-02-02T12:36:48.871Z" }, + { url = "https://files.pythonhosted.org/packages/d2/65/415f0a75cf6921e43365a1bc227c565cb949caca8b7532776e430cbaa530/jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66", size = 486319, upload_time = "2026-02-02T12:36:53.006Z" }, + { url = "https://files.pythonhosted.org/packages/54/a2/9e12b48e82c6bbc6081fd81abf915e1443add1b13d8fc586e1d90bb02bb8/jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2", size = 372289, upload_time = "2026-02-02T12:36:54.593Z" }, + { url = "https://files.pythonhosted.org/packages/4e/c1/e4693f107a1789a239c759a432e9afc592366f04e901470c2af89cfd28e1/jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad", size = 360165, upload_time = "2026-02-02T12:36:56.112Z" }, + { url = "https://files.pythonhosted.org/packages/17/08/91b9ea976c1c758240614bd88442681a87672eebc3d9a6dde476874e706b/jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d", size = 389634, upload_time = "2026-02-02T12:36:57.495Z" }, + { url = "https://files.pythonhosted.org/packages/18/23/58325ef99390d6d40427ed6005bf1ad54f2577866594bcf13ce55675f87d/jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df", size = 514933, upload_time = "2026-02-02T12:36:58.909Z" }, + { url = "https://files.pythonhosted.org/packages/5b/25/69f1120c7c395fd276c3996bb8adefa9c6b84c12bb7111e5c6ccdcd8526d/jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d", size = 548842, upload_time = "2026-02-02T12:37:00.433Z" }, + { url = "https://files.pythonhosted.org/packages/18/05/981c9669d86850c5fbb0d9e62bba144787f9fba84546ba43d624ee27ef29/jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6", size = 202108, upload_time = "2026-02-02T12:37:01.718Z" }, + { url = "https://files.pythonhosted.org/packages/8d/96/cdcf54dd0b0341db7d25413229888a346c7130bd20820530905fdb65727b/jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f", size = 204027, upload_time = "2026-02-02T12:37:03.075Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f9/724bcaaab7a3cd727031fe4f6995cb86c4bd344909177c186699c8dec51a/jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d", size = 187199, upload_time = "2026-02-02T12:37:04.414Z" }, + { url = "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0", size = 318423, upload_time = "2026-02-02T12:37:05.806Z" }, + { url = "https://files.pythonhosted.org/packages/4f/3b/f77d342a54d4ebcd128e520fc58ec2f5b30a423b0fd26acdfc0c6fef8e26/jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40", size = 351438, upload_time = "2026-02-02T12:37:07.189Z" }, + { url = "https://files.pythonhosted.org/packages/76/b3/ba9a69f0e4209bd3331470c723c2f5509e6f0482e416b612431a5061ed71/jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202", size = 364774, upload_time = "2026-02-02T12:37:08.579Z" }, + { url = "https://files.pythonhosted.org/packages/b3/16/6cdb31fa342932602458dbb631bfbd47f601e03d2e4950740e0b2100b570/jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0", size = 487238, upload_time = "2026-02-02T12:37:10.066Z" }, + { url = "https://files.pythonhosted.org/packages/ed/b1/956cc7abaca8d95c13aa8d6c9b3f3797241c246cd6e792934cc4c8b250d2/jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95", size = 372892, upload_time = "2026-02-02T12:37:11.656Z" }, + { url = "https://files.pythonhosted.org/packages/26/c4/97ecde8b1e74f67b8598c57c6fccf6df86ea7861ed29da84629cdbba76c4/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59", size = 360309, upload_time = "2026-02-02T12:37:13.244Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d7/eabe3cf46715854ccc80be2cd78dd4c36aedeb30751dbf85a1d08c14373c/jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe", size = 389607, upload_time = "2026-02-02T12:37:14.881Z" }, + { url = "https://files.pythonhosted.org/packages/df/2d/03963fc0804e6109b82decfb9974eb92df3797fe7222428cae12f8ccaa0c/jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939", size = 514986, upload_time = "2026-02-02T12:37:16.326Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/8c83b45eb3eb1c1e18d841fe30b4b5bc5619d781267ca9bc03e005d8fd0a/jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9", size = 548756, upload_time = "2026-02-02T12:37:17.736Z" }, + { url = "https://files.pythonhosted.org/packages/47/66/eea81dfff765ed66c68fd2ed8c96245109e13c896c2a5015c7839c92367e/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6", size = 201196, upload_time = "2026-02-02T12:37:19.101Z" }, + { url = "https://files.pythonhosted.org/packages/ff/32/4ac9c7a76402f8f00d00842a7f6b83b284d0cf7c1e9d4227bc95aa6d17fa/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8", size = 204215, upload_time = "2026-02-02T12:37:20.495Z" }, + { url = "https://files.pythonhosted.org/packages/f9/8e/7def204fea9f9be8b3c21a6f2dd6c020cf56c7d5ff753e0e23ed7f9ea57e/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024", size = 187152, upload_time = "2026-02-02T12:37:22.124Z" }, ] [[package]] @@ -1469,9 +1480,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload_time = "2026-01-07T13:41:07.246Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload_time = "2026-01-07T13:41:05.306Z" }, ] [[package]] @@ -1481,9 +1492,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload_time = "2025-09-08T01:34:59.186Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload_time = "2025-09-08T01:34:57.871Z" }, ] [[package]] @@ -1504,9 +1515,9 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/fc/78887158b4057835ba2c647a1bd4da650fd79142f8412c6d0bbe6d8c6081/litellm-1.81.10.tar.gz", hash = "sha256:8d769a7200888e1295592af5ce5cb0ff035832250bd0102a4ca50acf5820ca50", size = 16297572, upload-time = "2026-02-11T00:17:47.347Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/fc/78887158b4057835ba2c647a1bd4da650fd79142f8412c6d0bbe6d8c6081/litellm-1.81.10.tar.gz", hash = "sha256:8d769a7200888e1295592af5ce5cb0ff035832250bd0102a4ca50acf5820ca50", size = 16297572, upload_time = "2026-02-11T00:17:47.347Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/bb/3f3cc3d79657bc9daaa1319ec3a9d75e4889fc88d07e327f0ac02cd2ac7d/litellm-1.81.10-py3-none-any.whl", hash = "sha256:9efa1cbe61ac051f6500c267b173d988ff2d511c2eecf1c8f2ee546c0870747c", size = 14457931, upload-time = "2026-02-11T00:17:43.431Z" }, + { url = "https://files.pythonhosted.org/packages/b1/bb/3f3cc3d79657bc9daaa1319ec3a9d75e4889fc88d07e327f0ac02cd2ac7d/litellm-1.81.10-py3-none-any.whl", hash = "sha256:9efa1cbe61ac051f6500c267b173d988ff2d511c2eecf1c8f2ee546c0870747c", size = 14457931, upload_time = "2026-02-11T00:17:43.431Z" }, ] [[package]] @@ -1516,9 +1527,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload_time = "2025-04-10T12:44:31.16Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload_time = "2025-04-10T12:50:53.297Z" }, ] [[package]] @@ -1528,61 +1539,61 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload_time = "2025-08-11T12:57:52.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload_time = "2025-08-11T12:57:51.923Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, - { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, - { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, - { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, - { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, - { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, - { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, - { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, - { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, - { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, - { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, - { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, - { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, - { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, - { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, - { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, - { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, - { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, - { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, - { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, - { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, - { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, - { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, - { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, - { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, - { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, - { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, - { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, - { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, - { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, - { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, - { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, - { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, - { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload_time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload_time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload_time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload_time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload_time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload_time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload_time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload_time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload_time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload_time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload_time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload_time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload_time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload_time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload_time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload_time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload_time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload_time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload_time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload_time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload_time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload_time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload_time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload_time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload_time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload_time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload_time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload_time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload_time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload_time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload_time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload_time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload_time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload_time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload_time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload_time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload_time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload_time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload_time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload_time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload_time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload_time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload_time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload_time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload_time = "2025-09-27T18:37:28.327Z" }, ] [[package]] @@ -1605,172 +1616,172 @@ dependencies = [ { name = "typing-inspection" }, { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/6d/62e76bbb8144d6ed86e202b5edd8a4cb631e7c8130f3f4893c3f90262b10/mcp-1.26.0.tar.gz", hash = "sha256:db6e2ef491eecc1a0d93711a76f28dec2e05999f93afd48795da1c1137142c66", size = 608005, upload-time = "2026-01-24T19:40:32.468Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/6d/62e76bbb8144d6ed86e202b5edd8a4cb631e7c8130f3f4893c3f90262b10/mcp-1.26.0.tar.gz", hash = "sha256:db6e2ef491eecc1a0d93711a76f28dec2e05999f93afd48795da1c1137142c66", size = 608005, upload_time = "2026-01-24T19:40:32.468Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl", hash = "sha256:904a21c33c25aa98ddbeb47273033c435e595bbacfdb177f4bd87f6dceebe1ca", size = 233615, upload-time = "2026-01-24T19:40:30.652Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl", hash = "sha256:904a21c33c25aa98ddbeb47273033c435e595bbacfdb177f4bd87f6dceebe1ca", size = 233615, upload_time = "2026-01-24T19:40:30.652Z" }, ] [[package]] name = "mdurl" version = "0.1.2" 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" } +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" }, + { 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" }, ] [[package]] name = "mmh3" version = "5.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload-time = "2025-07-29T07:43:48.49Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/fa/27f6ab93995ef6ad9f940e96593c5dd24744d61a7389532b0fec03745607/mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065", size = 40874, upload-time = "2025-07-29T07:42:30.662Z" }, - { url = "https://files.pythonhosted.org/packages/11/9c/03d13bcb6a03438bc8cac3d2e50f80908d159b31a4367c2e1a7a077ded32/mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de", size = 42012, upload-time = "2025-07-29T07:42:31.539Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/0865d9765408a7d504f1789944e678f74e0888b96a766d578cb80b040999/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044", size = 39197, upload-time = "2025-07-29T07:42:32.374Z" }, - { url = "https://files.pythonhosted.org/packages/3e/12/76c3207bd186f98b908b6706c2317abb73756d23a4e68ea2bc94825b9015/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73", size = 39840, upload-time = "2025-07-29T07:42:33.227Z" }, - { url = "https://files.pythonhosted.org/packages/5d/0d/574b6cce5555c9f2b31ea189ad44986755eb14e8862db28c8b834b8b64dc/mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504", size = 40644, upload-time = "2025-07-29T07:42:34.099Z" }, - { url = "https://files.pythonhosted.org/packages/52/82/3731f8640b79c46707f53ed72034a58baad400be908c87b0088f1f89f986/mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b", size = 56153, upload-time = "2025-07-29T07:42:35.031Z" }, - { url = "https://files.pythonhosted.org/packages/4f/34/e02dca1d4727fd9fdeaff9e2ad6983e1552804ce1d92cc796e5b052159bb/mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05", size = 40684, upload-time = "2025-07-29T07:42:35.914Z" }, - { url = "https://files.pythonhosted.org/packages/8f/36/3dee40767356e104967e6ed6d102ba47b0b1ce2a89432239b95a94de1b89/mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814", size = 40057, upload-time = "2025-07-29T07:42:36.755Z" }, - { url = "https://files.pythonhosted.org/packages/31/58/228c402fccf76eb39a0a01b8fc470fecf21965584e66453b477050ee0e99/mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093", size = 97344, upload-time = "2025-07-29T07:42:37.675Z" }, - { url = "https://files.pythonhosted.org/packages/34/82/fc5ce89006389a6426ef28e326fc065b0fbaaed230373b62d14c889f47ea/mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54", size = 103325, upload-time = "2025-07-29T07:42:38.591Z" }, - { url = "https://files.pythonhosted.org/packages/09/8c/261e85777c6aee1ebd53f2f17e210e7481d5b0846cd0b4a5c45f1e3761b8/mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a", size = 106240, upload-time = "2025-07-29T07:42:39.563Z" }, - { url = "https://files.pythonhosted.org/packages/70/73/2f76b3ad8a3d431824e9934403df36c0ddacc7831acf82114bce3c4309c8/mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908", size = 113060, upload-time = "2025-07-29T07:42:40.585Z" }, - { url = "https://files.pythonhosted.org/packages/9f/b9/7ea61a34e90e50a79a9d87aa1c0b8139a7eaf4125782b34b7d7383472633/mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5", size = 120781, upload-time = "2025-07-29T07:42:41.618Z" }, - { url = "https://files.pythonhosted.org/packages/0f/5b/ae1a717db98c7894a37aeedbd94b3f99e6472a836488f36b6849d003485b/mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a", size = 99174, upload-time = "2025-07-29T07:42:42.587Z" }, - { url = "https://files.pythonhosted.org/packages/e3/de/000cce1d799fceebb6d4487ae29175dd8e81b48e314cba7b4da90bcf55d7/mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266", size = 98734, upload-time = "2025-07-29T07:42:43.996Z" }, - { url = "https://files.pythonhosted.org/packages/79/19/0dc364391a792b72fbb22becfdeacc5add85cc043cd16986e82152141883/mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5", size = 106493, upload-time = "2025-07-29T07:42:45.07Z" }, - { url = "https://files.pythonhosted.org/packages/3c/b1/bc8c28e4d6e807bbb051fefe78e1156d7f104b89948742ad310612ce240d/mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9", size = 110089, upload-time = "2025-07-29T07:42:46.122Z" }, - { url = "https://files.pythonhosted.org/packages/3b/a2/d20f3f5c95e9c511806686c70d0a15479cc3941c5f322061697af1c1ff70/mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290", size = 97571, upload-time = "2025-07-29T07:42:47.18Z" }, - { url = "https://files.pythonhosted.org/packages/7b/23/665296fce4f33488deec39a750ffd245cfc07aafb0e3ef37835f91775d14/mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051", size = 40806, upload-time = "2025-07-29T07:42:48.166Z" }, - { url = "https://files.pythonhosted.org/packages/59/b0/92e7103f3b20646e255b699e2d0327ce53a3f250e44367a99dc8be0b7c7a/mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081", size = 41600, upload-time = "2025-07-29T07:42:49.371Z" }, - { url = "https://files.pythonhosted.org/packages/99/22/0b2bd679a84574647de538c5b07ccaa435dbccc37815067fe15b90fe8dad/mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b", size = 39349, upload-time = "2025-07-29T07:42:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ca/a20db059a8a47048aaf550da14a145b56e9c7386fb8280d3ce2962dcebf7/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078", size = 39209, upload-time = "2025-07-29T07:42:51.559Z" }, - { url = "https://files.pythonhosted.org/packages/98/dd/e5094799d55c7482d814b979a0fd608027d0af1b274bfb4c3ea3e950bfd5/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501", size = 39843, upload-time = "2025-07-29T07:42:52.536Z" }, - { url = "https://files.pythonhosted.org/packages/f4/6b/7844d7f832c85400e7cc89a1348e4e1fdd38c5a38415bb5726bbb8fcdb6c/mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b", size = 40648, upload-time = "2025-07-29T07:42:53.392Z" }, - { url = "https://files.pythonhosted.org/packages/1f/bf/71f791f48a21ff3190ba5225807cbe4f7223360e96862c376e6e3fb7efa7/mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770", size = 56164, upload-time = "2025-07-29T07:42:54.267Z" }, - { url = "https://files.pythonhosted.org/packages/70/1f/f87e3d34d83032b4f3f0f528c6d95a98290fcacf019da61343a49dccfd51/mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110", size = 40692, upload-time = "2025-07-29T07:42:55.234Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e2/db849eaed07117086f3452feca8c839d30d38b830ac59fe1ce65af8be5ad/mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647", size = 40068, upload-time = "2025-07-29T07:42:56.158Z" }, - { url = "https://files.pythonhosted.org/packages/df/6b/209af927207af77425b044e32f77f49105a0b05d82ff88af6971d8da4e19/mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63", size = 97367, upload-time = "2025-07-29T07:42:57.037Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e0/78adf4104c425606a9ce33fb351f790c76a6c2314969c4a517d1ffc92196/mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12", size = 103306, upload-time = "2025-07-29T07:42:58.522Z" }, - { url = "https://files.pythonhosted.org/packages/a3/79/c2b89f91b962658b890104745b1b6c9ce38d50a889f000b469b91eeb1b9e/mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22", size = 106312, upload-time = "2025-07-29T07:42:59.552Z" }, - { url = "https://files.pythonhosted.org/packages/4b/14/659d4095528b1a209be90934778c5ffe312177d51e365ddcbca2cac2ec7c/mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5", size = 113135, upload-time = "2025-07-29T07:43:00.745Z" }, - { url = "https://files.pythonhosted.org/packages/8d/6f/cd7734a779389a8a467b5c89a48ff476d6f2576e78216a37551a97e9e42a/mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07", size = 120775, upload-time = "2025-07-29T07:43:02.124Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ca/8256e3b96944408940de3f9291d7e38a283b5761fe9614d4808fcf27bd62/mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935", size = 99178, upload-time = "2025-07-29T07:43:03.182Z" }, - { url = "https://files.pythonhosted.org/packages/8a/32/39e2b3cf06b6e2eb042c984dab8680841ac2a0d3ca6e0bea30db1f27b565/mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7", size = 98738, upload-time = "2025-07-29T07:43:04.207Z" }, - { url = "https://files.pythonhosted.org/packages/61/d3/7bbc8e0e8cf65ebbe1b893ffa0467b7ecd1bd07c3bbf6c9db4308ada22ec/mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5", size = 106510, upload-time = "2025-07-29T07:43:05.656Z" }, - { url = "https://files.pythonhosted.org/packages/10/99/b97e53724b52374e2f3859046f0eb2425192da356cb19784d64bc17bb1cf/mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384", size = 110053, upload-time = "2025-07-29T07:43:07.204Z" }, - { url = "https://files.pythonhosted.org/packages/ac/62/3688c7d975ed195155671df68788c83fed6f7909b6ec4951724c6860cb97/mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e", size = 97546, upload-time = "2025-07-29T07:43:08.226Z" }, - { url = "https://files.pythonhosted.org/packages/ca/3b/c6153250f03f71a8b7634cded82939546cdfba02e32f124ff51d52c6f991/mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0", size = 41422, upload-time = "2025-07-29T07:43:09.216Z" }, - { url = "https://files.pythonhosted.org/packages/74/01/a27d98bab083a435c4c07e9d1d720d4c8a578bf4c270bae373760b1022be/mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b", size = 42135, upload-time = "2025-07-29T07:43:10.183Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c9/dbba5507e95429b8b380e2ba091eff5c20a70a59560934dff0ad8392b8c8/mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115", size = 39879, upload-time = "2025-07-29T07:43:11.106Z" }, - { url = "https://files.pythonhosted.org/packages/b5/d1/c8c0ef839c17258b9de41b84f663574fabcf8ac2007b7416575e0f65ff6e/mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932", size = 57696, upload-time = "2025-07-29T07:43:11.989Z" }, - { url = "https://files.pythonhosted.org/packages/2f/55/95e2b9ff201e89f9fe37036037ab61a6c941942b25cdb7b6a9df9b931993/mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c", size = 41421, upload-time = "2025-07-29T07:43:13.269Z" }, - { url = "https://files.pythonhosted.org/packages/77/79/9be23ad0b7001a4b22752e7693be232428ecc0a35068a4ff5c2f14ef8b20/mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be", size = 40853, upload-time = "2025-07-29T07:43:14.888Z" }, - { url = "https://files.pythonhosted.org/packages/ac/1b/96b32058eda1c1dee8264900c37c359a7325c1f11f5ff14fd2be8e24eff9/mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb", size = 109694, upload-time = "2025-07-29T07:43:15.816Z" }, - { url = "https://files.pythonhosted.org/packages/8d/6f/a2ae44cd7dad697b6dea48390cbc977b1e5ca58fda09628cbcb2275af064/mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65", size = 117438, upload-time = "2025-07-29T07:43:16.865Z" }, - { url = "https://files.pythonhosted.org/packages/a0/08/bfb75451c83f05224a28afeaf3950c7b793c0b71440d571f8e819cfb149a/mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991", size = 120409, upload-time = "2025-07-29T07:43:18.207Z" }, - { url = "https://files.pythonhosted.org/packages/9f/ea/8b118b69b2ff8df568f742387d1a159bc654a0f78741b31437dd047ea28e/mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645", size = 125909, upload-time = "2025-07-29T07:43:19.39Z" }, - { url = "https://files.pythonhosted.org/packages/3e/11/168cc0b6a30650032e351a3b89b8a47382da541993a03af91e1ba2501234/mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3", size = 135331, upload-time = "2025-07-29T07:43:20.435Z" }, - { url = "https://files.pythonhosted.org/packages/31/05/e3a9849b1c18a7934c64e831492c99e67daebe84a8c2f2c39a7096a830e3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279", size = 110085, upload-time = "2025-07-29T07:43:21.92Z" }, - { url = "https://files.pythonhosted.org/packages/d9/d5/a96bcc306e3404601418b2a9a370baec92af84204528ba659fdfe34c242f/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513", size = 111195, upload-time = "2025-07-29T07:43:23.066Z" }, - { url = "https://files.pythonhosted.org/packages/af/29/0fd49801fec5bff37198684e0849b58e0dab3a2a68382a357cfffb0fafc3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db", size = 116919, upload-time = "2025-07-29T07:43:24.178Z" }, - { url = "https://files.pythonhosted.org/packages/2d/04/4f3c32b0a2ed762edca45d8b46568fc3668e34f00fb1e0a3b5451ec1281c/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667", size = 123160, upload-time = "2025-07-29T07:43:25.26Z" }, - { url = "https://files.pythonhosted.org/packages/91/76/3d29eaa38821730633d6a240d36fa8ad2807e9dfd432c12e1a472ed211eb/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5", size = 110206, upload-time = "2025-07-29T07:43:26.699Z" }, - { url = "https://files.pythonhosted.org/packages/44/1c/ccf35892684d3a408202e296e56843743e0b4fb1629e59432ea88cdb3909/mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7", size = 41970, upload-time = "2025-07-29T07:43:27.666Z" }, - { url = "https://files.pythonhosted.org/packages/75/b2/b9e4f1e5adb5e21eb104588fcee2cd1eaa8308255173481427d5ecc4284e/mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d", size = 43063, upload-time = "2025-07-29T07:43:28.582Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fc/0e61d9a4e29c8679356795a40e48f647b4aad58d71bfc969f0f8f56fb912/mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9", size = 40455, upload-time = "2025-07-29T07:43:29.563Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload_time = "2025-07-29T07:43:48.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/fa/27f6ab93995ef6ad9f940e96593c5dd24744d61a7389532b0fec03745607/mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065", size = 40874, upload_time = "2025-07-29T07:42:30.662Z" }, + { url = "https://files.pythonhosted.org/packages/11/9c/03d13bcb6a03438bc8cac3d2e50f80908d159b31a4367c2e1a7a077ded32/mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de", size = 42012, upload_time = "2025-07-29T07:42:31.539Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/0865d9765408a7d504f1789944e678f74e0888b96a766d578cb80b040999/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044", size = 39197, upload_time = "2025-07-29T07:42:32.374Z" }, + { url = "https://files.pythonhosted.org/packages/3e/12/76c3207bd186f98b908b6706c2317abb73756d23a4e68ea2bc94825b9015/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73", size = 39840, upload_time = "2025-07-29T07:42:33.227Z" }, + { url = "https://files.pythonhosted.org/packages/5d/0d/574b6cce5555c9f2b31ea189ad44986755eb14e8862db28c8b834b8b64dc/mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504", size = 40644, upload_time = "2025-07-29T07:42:34.099Z" }, + { url = "https://files.pythonhosted.org/packages/52/82/3731f8640b79c46707f53ed72034a58baad400be908c87b0088f1f89f986/mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b", size = 56153, upload_time = "2025-07-29T07:42:35.031Z" }, + { url = "https://files.pythonhosted.org/packages/4f/34/e02dca1d4727fd9fdeaff9e2ad6983e1552804ce1d92cc796e5b052159bb/mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05", size = 40684, upload_time = "2025-07-29T07:42:35.914Z" }, + { url = "https://files.pythonhosted.org/packages/8f/36/3dee40767356e104967e6ed6d102ba47b0b1ce2a89432239b95a94de1b89/mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814", size = 40057, upload_time = "2025-07-29T07:42:36.755Z" }, + { url = "https://files.pythonhosted.org/packages/31/58/228c402fccf76eb39a0a01b8fc470fecf21965584e66453b477050ee0e99/mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093", size = 97344, upload_time = "2025-07-29T07:42:37.675Z" }, + { url = "https://files.pythonhosted.org/packages/34/82/fc5ce89006389a6426ef28e326fc065b0fbaaed230373b62d14c889f47ea/mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54", size = 103325, upload_time = "2025-07-29T07:42:38.591Z" }, + { url = "https://files.pythonhosted.org/packages/09/8c/261e85777c6aee1ebd53f2f17e210e7481d5b0846cd0b4a5c45f1e3761b8/mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a", size = 106240, upload_time = "2025-07-29T07:42:39.563Z" }, + { url = "https://files.pythonhosted.org/packages/70/73/2f76b3ad8a3d431824e9934403df36c0ddacc7831acf82114bce3c4309c8/mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908", size = 113060, upload_time = "2025-07-29T07:42:40.585Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b9/7ea61a34e90e50a79a9d87aa1c0b8139a7eaf4125782b34b7d7383472633/mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5", size = 120781, upload_time = "2025-07-29T07:42:41.618Z" }, + { url = "https://files.pythonhosted.org/packages/0f/5b/ae1a717db98c7894a37aeedbd94b3f99e6472a836488f36b6849d003485b/mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a", size = 99174, upload_time = "2025-07-29T07:42:42.587Z" }, + { url = "https://files.pythonhosted.org/packages/e3/de/000cce1d799fceebb6d4487ae29175dd8e81b48e314cba7b4da90bcf55d7/mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266", size = 98734, upload_time = "2025-07-29T07:42:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/79/19/0dc364391a792b72fbb22becfdeacc5add85cc043cd16986e82152141883/mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5", size = 106493, upload_time = "2025-07-29T07:42:45.07Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b1/bc8c28e4d6e807bbb051fefe78e1156d7f104b89948742ad310612ce240d/mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9", size = 110089, upload_time = "2025-07-29T07:42:46.122Z" }, + { url = "https://files.pythonhosted.org/packages/3b/a2/d20f3f5c95e9c511806686c70d0a15479cc3941c5f322061697af1c1ff70/mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290", size = 97571, upload_time = "2025-07-29T07:42:47.18Z" }, + { url = "https://files.pythonhosted.org/packages/7b/23/665296fce4f33488deec39a750ffd245cfc07aafb0e3ef37835f91775d14/mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051", size = 40806, upload_time = "2025-07-29T07:42:48.166Z" }, + { url = "https://files.pythonhosted.org/packages/59/b0/92e7103f3b20646e255b699e2d0327ce53a3f250e44367a99dc8be0b7c7a/mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081", size = 41600, upload_time = "2025-07-29T07:42:49.371Z" }, + { url = "https://files.pythonhosted.org/packages/99/22/0b2bd679a84574647de538c5b07ccaa435dbccc37815067fe15b90fe8dad/mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b", size = 39349, upload_time = "2025-07-29T07:42:50.268Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ca/a20db059a8a47048aaf550da14a145b56e9c7386fb8280d3ce2962dcebf7/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078", size = 39209, upload_time = "2025-07-29T07:42:51.559Z" }, + { url = "https://files.pythonhosted.org/packages/98/dd/e5094799d55c7482d814b979a0fd608027d0af1b274bfb4c3ea3e950bfd5/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501", size = 39843, upload_time = "2025-07-29T07:42:52.536Z" }, + { url = "https://files.pythonhosted.org/packages/f4/6b/7844d7f832c85400e7cc89a1348e4e1fdd38c5a38415bb5726bbb8fcdb6c/mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b", size = 40648, upload_time = "2025-07-29T07:42:53.392Z" }, + { url = "https://files.pythonhosted.org/packages/1f/bf/71f791f48a21ff3190ba5225807cbe4f7223360e96862c376e6e3fb7efa7/mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770", size = 56164, upload_time = "2025-07-29T07:42:54.267Z" }, + { url = "https://files.pythonhosted.org/packages/70/1f/f87e3d34d83032b4f3f0f528c6d95a98290fcacf019da61343a49dccfd51/mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110", size = 40692, upload_time = "2025-07-29T07:42:55.234Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e2/db849eaed07117086f3452feca8c839d30d38b830ac59fe1ce65af8be5ad/mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647", size = 40068, upload_time = "2025-07-29T07:42:56.158Z" }, + { url = "https://files.pythonhosted.org/packages/df/6b/209af927207af77425b044e32f77f49105a0b05d82ff88af6971d8da4e19/mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63", size = 97367, upload_time = "2025-07-29T07:42:57.037Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e0/78adf4104c425606a9ce33fb351f790c76a6c2314969c4a517d1ffc92196/mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12", size = 103306, upload_time = "2025-07-29T07:42:58.522Z" }, + { url = "https://files.pythonhosted.org/packages/a3/79/c2b89f91b962658b890104745b1b6c9ce38d50a889f000b469b91eeb1b9e/mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22", size = 106312, upload_time = "2025-07-29T07:42:59.552Z" }, + { url = "https://files.pythonhosted.org/packages/4b/14/659d4095528b1a209be90934778c5ffe312177d51e365ddcbca2cac2ec7c/mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5", size = 113135, upload_time = "2025-07-29T07:43:00.745Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/cd7734a779389a8a467b5c89a48ff476d6f2576e78216a37551a97e9e42a/mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07", size = 120775, upload_time = "2025-07-29T07:43:02.124Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ca/8256e3b96944408940de3f9291d7e38a283b5761fe9614d4808fcf27bd62/mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935", size = 99178, upload_time = "2025-07-29T07:43:03.182Z" }, + { url = "https://files.pythonhosted.org/packages/8a/32/39e2b3cf06b6e2eb042c984dab8680841ac2a0d3ca6e0bea30db1f27b565/mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7", size = 98738, upload_time = "2025-07-29T07:43:04.207Z" }, + { url = "https://files.pythonhosted.org/packages/61/d3/7bbc8e0e8cf65ebbe1b893ffa0467b7ecd1bd07c3bbf6c9db4308ada22ec/mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5", size = 106510, upload_time = "2025-07-29T07:43:05.656Z" }, + { url = "https://files.pythonhosted.org/packages/10/99/b97e53724b52374e2f3859046f0eb2425192da356cb19784d64bc17bb1cf/mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384", size = 110053, upload_time = "2025-07-29T07:43:07.204Z" }, + { url = "https://files.pythonhosted.org/packages/ac/62/3688c7d975ed195155671df68788c83fed6f7909b6ec4951724c6860cb97/mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e", size = 97546, upload_time = "2025-07-29T07:43:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/ca/3b/c6153250f03f71a8b7634cded82939546cdfba02e32f124ff51d52c6f991/mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0", size = 41422, upload_time = "2025-07-29T07:43:09.216Z" }, + { url = "https://files.pythonhosted.org/packages/74/01/a27d98bab083a435c4c07e9d1d720d4c8a578bf4c270bae373760b1022be/mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b", size = 42135, upload_time = "2025-07-29T07:43:10.183Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c9/dbba5507e95429b8b380e2ba091eff5c20a70a59560934dff0ad8392b8c8/mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115", size = 39879, upload_time = "2025-07-29T07:43:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d1/c8c0ef839c17258b9de41b84f663574fabcf8ac2007b7416575e0f65ff6e/mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932", size = 57696, upload_time = "2025-07-29T07:43:11.989Z" }, + { url = "https://files.pythonhosted.org/packages/2f/55/95e2b9ff201e89f9fe37036037ab61a6c941942b25cdb7b6a9df9b931993/mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c", size = 41421, upload_time = "2025-07-29T07:43:13.269Z" }, + { url = "https://files.pythonhosted.org/packages/77/79/9be23ad0b7001a4b22752e7693be232428ecc0a35068a4ff5c2f14ef8b20/mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be", size = 40853, upload_time = "2025-07-29T07:43:14.888Z" }, + { url = "https://files.pythonhosted.org/packages/ac/1b/96b32058eda1c1dee8264900c37c359a7325c1f11f5ff14fd2be8e24eff9/mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb", size = 109694, upload_time = "2025-07-29T07:43:15.816Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/a2ae44cd7dad697b6dea48390cbc977b1e5ca58fda09628cbcb2275af064/mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65", size = 117438, upload_time = "2025-07-29T07:43:16.865Z" }, + { url = "https://files.pythonhosted.org/packages/a0/08/bfb75451c83f05224a28afeaf3950c7b793c0b71440d571f8e819cfb149a/mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991", size = 120409, upload_time = "2025-07-29T07:43:18.207Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ea/8b118b69b2ff8df568f742387d1a159bc654a0f78741b31437dd047ea28e/mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645", size = 125909, upload_time = "2025-07-29T07:43:19.39Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/168cc0b6a30650032e351a3b89b8a47382da541993a03af91e1ba2501234/mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3", size = 135331, upload_time = "2025-07-29T07:43:20.435Z" }, + { url = "https://files.pythonhosted.org/packages/31/05/e3a9849b1c18a7934c64e831492c99e67daebe84a8c2f2c39a7096a830e3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279", size = 110085, upload_time = "2025-07-29T07:43:21.92Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d5/a96bcc306e3404601418b2a9a370baec92af84204528ba659fdfe34c242f/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513", size = 111195, upload_time = "2025-07-29T07:43:23.066Z" }, + { url = "https://files.pythonhosted.org/packages/af/29/0fd49801fec5bff37198684e0849b58e0dab3a2a68382a357cfffb0fafc3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db", size = 116919, upload_time = "2025-07-29T07:43:24.178Z" }, + { url = "https://files.pythonhosted.org/packages/2d/04/4f3c32b0a2ed762edca45d8b46568fc3668e34f00fb1e0a3b5451ec1281c/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667", size = 123160, upload_time = "2025-07-29T07:43:25.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/76/3d29eaa38821730633d6a240d36fa8ad2807e9dfd432c12e1a472ed211eb/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5", size = 110206, upload_time = "2025-07-29T07:43:26.699Z" }, + { url = "https://files.pythonhosted.org/packages/44/1c/ccf35892684d3a408202e296e56843743e0b4fb1629e59432ea88cdb3909/mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7", size = 41970, upload_time = "2025-07-29T07:43:27.666Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/b9e4f1e5adb5e21eb104588fcee2cd1eaa8308255173481427d5ecc4284e/mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d", size = 43063, upload_time = "2025-07-29T07:43:28.582Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0e61d9a4e29c8679356795a40e48f647b4aad58d71bfc969f0f8f56fb912/mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9", size = 40455, upload_time = "2025-07-29T07:43:29.563Z" }, ] [[package]] name = "multidict" version = "6.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload-time = "2026-01-26T02:44:18.509Z" }, - { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload-time = "2026-01-26T02:44:19.745Z" }, - { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload-time = "2026-01-26T02:44:21.571Z" }, - { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload-time = "2026-01-26T02:44:22.803Z" }, - { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload-time = "2026-01-26T02:44:24.306Z" }, - { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload-time = "2026-01-26T02:44:25.772Z" }, - { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload-time = "2026-01-26T02:44:27.648Z" }, - { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload-time = "2026-01-26T02:44:29.588Z" }, - { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload-time = "2026-01-26T02:44:30.902Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload-time = "2026-01-26T02:44:32.31Z" }, - { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload-time = "2026-01-26T02:44:33.734Z" }, - { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload-time = "2026-01-26T02:44:35.222Z" }, - { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload-time = "2026-01-26T02:44:36.604Z" }, - { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload-time = "2026-01-26T02:44:38.008Z" }, - { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload-time = "2026-01-26T02:44:39.386Z" }, - { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload-time = "2026-01-26T02:44:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload-time = "2026-01-26T02:44:42.488Z" }, - { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload-time = "2026-01-26T02:44:43.664Z" }, - { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload-time = "2026-01-26T02:44:44.894Z" }, - { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload-time = "2026-01-26T02:44:46.106Z" }, - { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload-time = "2026-01-26T02:44:47.278Z" }, - { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload-time = "2026-01-26T02:44:48.604Z" }, - { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload-time = "2026-01-26T02:44:50.544Z" }, - { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload-time = "2026-01-26T02:44:51.951Z" }, - { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload-time = "2026-01-26T02:44:53.902Z" }, - { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload-time = "2026-01-26T02:44:55.316Z" }, - { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload-time = "2026-01-26T02:44:56.783Z" }, - { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload-time = "2026-01-26T02:44:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload-time = "2026-01-26T02:44:59.57Z" }, - { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload-time = "2026-01-26T02:45:01.054Z" }, - { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload-time = "2026-01-26T02:45:02.484Z" }, - { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload-time = "2026-01-26T02:45:03.862Z" }, - { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload-time = "2026-01-26T02:45:05.296Z" }, - { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload-time = "2026-01-26T02:45:06.754Z" }, - { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload-time = "2026-01-26T02:45:08.044Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload-time = "2026-01-26T02:45:09.349Z" }, - { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" }, - { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" }, - { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" }, - { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" }, - { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" }, - { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" }, - { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" }, - { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" }, - { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" }, - { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" }, - { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" }, - { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" }, - { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" }, - { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" }, - { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" }, - { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" }, - { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" }, - { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" }, - { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" }, - { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" }, - { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" }, - { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" }, - { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" }, - { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" }, - { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" }, - { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" }, - { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" }, - { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" }, - { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" }, - { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" }, - { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload_time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload_time = "2026-01-26T02:44:18.509Z" }, + { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload_time = "2026-01-26T02:44:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload_time = "2026-01-26T02:44:21.571Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload_time = "2026-01-26T02:44:22.803Z" }, + { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload_time = "2026-01-26T02:44:24.306Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload_time = "2026-01-26T02:44:25.772Z" }, + { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload_time = "2026-01-26T02:44:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload_time = "2026-01-26T02:44:29.588Z" }, + { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload_time = "2026-01-26T02:44:30.902Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload_time = "2026-01-26T02:44:32.31Z" }, + { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload_time = "2026-01-26T02:44:33.734Z" }, + { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload_time = "2026-01-26T02:44:35.222Z" }, + { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload_time = "2026-01-26T02:44:36.604Z" }, + { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload_time = "2026-01-26T02:44:38.008Z" }, + { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload_time = "2026-01-26T02:44:39.386Z" }, + { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload_time = "2026-01-26T02:44:41.318Z" }, + { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload_time = "2026-01-26T02:44:42.488Z" }, + { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload_time = "2026-01-26T02:44:43.664Z" }, + { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload_time = "2026-01-26T02:44:44.894Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload_time = "2026-01-26T02:44:46.106Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload_time = "2026-01-26T02:44:47.278Z" }, + { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload_time = "2026-01-26T02:44:48.604Z" }, + { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload_time = "2026-01-26T02:44:50.544Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload_time = "2026-01-26T02:44:51.951Z" }, + { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload_time = "2026-01-26T02:44:53.902Z" }, + { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload_time = "2026-01-26T02:44:55.316Z" }, + { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload_time = "2026-01-26T02:44:56.783Z" }, + { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload_time = "2026-01-26T02:44:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload_time = "2026-01-26T02:44:59.57Z" }, + { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload_time = "2026-01-26T02:45:01.054Z" }, + { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload_time = "2026-01-26T02:45:02.484Z" }, + { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload_time = "2026-01-26T02:45:03.862Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload_time = "2026-01-26T02:45:05.296Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload_time = "2026-01-26T02:45:06.754Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload_time = "2026-01-26T02:45:08.044Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload_time = "2026-01-26T02:45:09.349Z" }, + { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload_time = "2026-01-26T02:45:10.651Z" }, + { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload_time = "2026-01-26T02:45:11.938Z" }, + { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload_time = "2026-01-26T02:45:14.346Z" }, + { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload_time = "2026-01-26T02:45:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload_time = "2026-01-26T02:45:17.293Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload_time = "2026-01-26T02:45:19.356Z" }, + { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload_time = "2026-01-26T02:45:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload_time = "2026-01-26T02:45:22.818Z" }, + { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload_time = "2026-01-26T02:45:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload_time = "2026-01-26T02:45:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload_time = "2026-01-26T02:45:27.487Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload_time = "2026-01-26T02:45:28.991Z" }, + { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload_time = "2026-01-26T02:45:30.503Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload_time = "2026-01-26T02:45:32.603Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload_time = "2026-01-26T02:45:34.043Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload_time = "2026-01-26T02:45:36.278Z" }, + { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload_time = "2026-01-26T02:45:37.546Z" }, + { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload_time = "2026-01-26T02:45:38.889Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload_time = "2026-01-26T02:45:40.254Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload_time = "2026-01-26T02:45:41.635Z" }, + { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload_time = "2026-01-26T02:45:42.99Z" }, + { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload_time = "2026-01-26T02:45:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload_time = "2026-01-26T02:45:47.167Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload_time = "2026-01-26T02:45:48.698Z" }, + { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload_time = "2026-01-26T02:45:50.164Z" }, + { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload_time = "2026-01-26T02:45:51.779Z" }, + { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload_time = "2026-01-26T02:45:53.27Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload_time = "2026-01-26T02:45:54.919Z" }, + { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload_time = "2026-01-26T02:45:56.981Z" }, + { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload_time = "2026-01-26T02:45:58.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload_time = "2026-01-26T02:46:00.862Z" }, + { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload_time = "2026-01-26T02:46:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload_time = "2026-01-26T02:46:05.898Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload_time = "2026-01-26T02:46:07.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload_time = "2026-01-26T02:46:08.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload_time = "2026-01-26T02:46:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload_time = "2026-01-26T02:46:44.004Z" }, ] [[package]] name = "mypy-extensions" version = "1.1.0" 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" } +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" }, + { 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" }, ] [[package]] @@ -1787,9 +1798,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6e/5a/f495777c02625bfa18212b6e3b73f1893094f2bf660976eb4bc6f43a1ca2/openai-2.20.0.tar.gz", hash = "sha256:2654a689208cd0bf1098bb9462e8d722af5cbe961e6bba54e6f19fb843d88db1", size = 642355, upload-time = "2026-02-10T19:02:54.145Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/5a/f495777c02625bfa18212b6e3b73f1893094f2bf660976eb4bc6f43a1ca2/openai-2.20.0.tar.gz", hash = "sha256:2654a689208cd0bf1098bb9462e8d722af5cbe961e6bba54e6f19fb843d88db1", size = 642355, upload_time = "2026-02-10T19:02:54.145Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/a0/cf4297aa51bbc21e83ef0ac018947fa06aea8f2364aad7c96cbf148590e6/openai-2.20.0-py3-none-any.whl", hash = "sha256:38d989c4b1075cd1f76abc68364059d822327cf1a932531d429795f4fc18be99", size = 1098479, upload-time = "2026-02-10T19:02:52.157Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a0/cf4297aa51bbc21e83ef0ac018947fa06aea8f2364aad7c96cbf148590e6/openai-2.20.0-py3-none-any.whl", hash = "sha256:38d989c4b1075cd1f76abc68364059d822327cf1a932531d429795f4fc18be99", size = 1098479, upload_time = "2026-02-10T19:02:52.157Z" }, ] [[package]] @@ -1800,9 +1811,9 @@ dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/04/05040d7ce33a907a2a02257e601992f0cdf11c73b33f13c4492bf6c3d6d5/opentelemetry_api-1.37.0.tar.gz", hash = "sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7", size = 64923, upload-time = "2025-09-11T10:29:01.662Z" } +sdist = { url = "https://files.pythonhosted.org/packages/63/04/05040d7ce33a907a2a02257e601992f0cdf11c73b33f13c4492bf6c3d6d5/opentelemetry_api-1.37.0.tar.gz", hash = "sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7", size = 64923, upload_time = "2025-09-11T10:29:01.662Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/48/28ed9e55dcf2f453128df738210a980e09f4e468a456fa3c763dbc8be70a/opentelemetry_api-1.37.0-py3-none-any.whl", hash = "sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47", size = 65732, upload-time = "2025-09-11T10:28:41.826Z" }, + { url = "https://files.pythonhosted.org/packages/91/48/28ed9e55dcf2f453128df738210a980e09f4e468a456fa3c763dbc8be70a/opentelemetry_api-1.37.0-py3-none-any.whl", hash = "sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47", size = 65732, upload_time = "2025-09-11T10:28:41.826Z" }, ] [[package]] @@ -1815,9 +1826,9 @@ dependencies = [ { name = "opentelemetry-resourcedetector-gcp" }, { name = "opentelemetry-sdk" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/2d/6aa7063b009768d8f9415b36a29ae9b3eb1e2c5eff70f58ca15e104c245f/opentelemetry_exporter_gcp_logging-1.11.0a0.tar.gz", hash = "sha256:58496f11b930c84570060ffbd4343cd0b597ea13c7bc5c879df01163dd552f14", size = 22400, upload-time = "2025-11-04T19:32:13.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/2d/6aa7063b009768d8f9415b36a29ae9b3eb1e2c5eff70f58ca15e104c245f/opentelemetry_exporter_gcp_logging-1.11.0a0.tar.gz", hash = "sha256:58496f11b930c84570060ffbd4343cd0b597ea13c7bc5c879df01163dd552f14", size = 22400, upload_time = "2025-11-04T19:32:13.812Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/b7/2d3df53fa39bfd52f88c78a60367d45a7b1adbf8a756cce62d6ac149d49a/opentelemetry_exporter_gcp_logging-1.11.0a0-py3-none-any.whl", hash = "sha256:f8357c552947cb9c0101c4575a7702b8d3268e28bdeefdd1405cf838e128c6ef", size = 14168, upload-time = "2025-11-04T19:32:07.073Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b7/2d3df53fa39bfd52f88c78a60367d45a7b1adbf8a756cce62d6ac149d49a/opentelemetry_exporter_gcp_logging-1.11.0a0-py3-none-any.whl", hash = "sha256:f8357c552947cb9c0101c4575a7702b8d3268e28bdeefdd1405cf838e128c6ef", size = 14168, upload_time = "2025-11-04T19:32:07.073Z" }, ] [[package]] @@ -1830,9 +1841,9 @@ dependencies = [ { name = "opentelemetry-resourcedetector-gcp" }, { name = "opentelemetry-sdk" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/48/d1c7d2380bb1754d1eb6a011a2e0de08c6868cb6c0f34bcda0444fa0d614/opentelemetry_exporter_gcp_monitoring-1.11.0a0.tar.gz", hash = "sha256:386276eddbbd978a6f30fafd3397975beeb02a1302bdad554185242a8e2c343c", size = 20828, upload-time = "2025-11-04T19:32:14.522Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/48/d1c7d2380bb1754d1eb6a011a2e0de08c6868cb6c0f34bcda0444fa0d614/opentelemetry_exporter_gcp_monitoring-1.11.0a0.tar.gz", hash = "sha256:386276eddbbd978a6f30fafd3397975beeb02a1302bdad554185242a8e2c343c", size = 20828, upload_time = "2025-11-04T19:32:14.522Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/8c/03a6e73e270a9c890dbd6cc1c47c83d86b8a8a974a9168d92e043c6277cc/opentelemetry_exporter_gcp_monitoring-1.11.0a0-py3-none-any.whl", hash = "sha256:b6740cba61b2f9555274829fe87a58447b64d0378f1067a4faebb4f5b364ca22", size = 13611, upload-time = "2025-11-04T19:32:08.212Z" }, + { url = "https://files.pythonhosted.org/packages/8c/8c/03a6e73e270a9c890dbd6cc1c47c83d86b8a8a974a9168d92e043c6277cc/opentelemetry_exporter_gcp_monitoring-1.11.0a0-py3-none-any.whl", hash = "sha256:b6740cba61b2f9555274829fe87a58447b64d0378f1067a4faebb4f5b364ca22", size = 13611, upload_time = "2025-11-04T19:32:08.212Z" }, ] [[package]] @@ -1845,9 +1856,9 @@ dependencies = [ { name = "opentelemetry-resourcedetector-gcp" }, { name = "opentelemetry-sdk" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/10/9c/4c3b26e5494f8b53c7873732a2317df905abe2b8ab33e9edfcbd5a8ff79b/opentelemetry_exporter_gcp_trace-1.11.0.tar.gz", hash = "sha256:c947ab4ab53e16517ade23d6fe71fe88cf7ca3f57a42c9f0e4162d2b929fecb6", size = 18770, upload-time = "2025-11-04T19:32:15.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/9c/4c3b26e5494f8b53c7873732a2317df905abe2b8ab33e9edfcbd5a8ff79b/opentelemetry_exporter_gcp_trace-1.11.0.tar.gz", hash = "sha256:c947ab4ab53e16517ade23d6fe71fe88cf7ca3f57a42c9f0e4162d2b929fecb6", size = 18770, upload_time = "2025-11-04T19:32:15.109Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/4a/876703e8c5845198d95cd4006c8d1b2e3b129a9e288558e33133360f8d5d/opentelemetry_exporter_gcp_trace-1.11.0-py3-none-any.whl", hash = "sha256:b3dcb314e1a9985e9185cb7720b693eb393886fde98ae4c095ffc0893de6cefa", size = 14016, upload-time = "2025-11-04T19:32:09.009Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4a/876703e8c5845198d95cd4006c8d1b2e3b129a9e288558e33133360f8d5d/opentelemetry_exporter_gcp_trace-1.11.0-py3-none-any.whl", hash = "sha256:b3dcb314e1a9985e9185cb7720b693eb393886fde98ae4c095ffc0893de6cefa", size = 14016, upload_time = "2025-11-04T19:32:09.009Z" }, ] [[package]] @@ -1857,9 +1868,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/6c/10018cbcc1e6fff23aac67d7fd977c3d692dbe5f9ef9bb4db5c1268726cc/opentelemetry_exporter_otlp_proto_common-1.37.0.tar.gz", hash = "sha256:c87a1bdd9f41fdc408d9cc9367bb53f8d2602829659f2b90be9f9d79d0bfe62c", size = 20430, upload-time = "2025-09-11T10:29:03.605Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/6c/10018cbcc1e6fff23aac67d7fd977c3d692dbe5f9ef9bb4db5c1268726cc/opentelemetry_exporter_otlp_proto_common-1.37.0.tar.gz", hash = "sha256:c87a1bdd9f41fdc408d9cc9367bb53f8d2602829659f2b90be9f9d79d0bfe62c", size = 20430, upload_time = "2025-09-11T10:29:03.605Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/13/b4ef09837409a777f3c0af2a5b4ba9b7af34872bc43609dda0c209e4060d/opentelemetry_exporter_otlp_proto_common-1.37.0-py3-none-any.whl", hash = "sha256:53038428449c559b0c564b8d718df3314da387109c4d36bd1b94c9a641b0292e", size = 18359, upload-time = "2025-09-11T10:28:44.939Z" }, + { url = "https://files.pythonhosted.org/packages/08/13/b4ef09837409a777f3c0af2a5b4ba9b7af34872bc43609dda0c209e4060d/opentelemetry_exporter_otlp_proto_common-1.37.0-py3-none-any.whl", hash = "sha256:53038428449c559b0c564b8d718df3314da387109c4d36bd1b94c9a641b0292e", size = 18359, upload_time = "2025-09-11T10:28:44.939Z" }, ] [[package]] @@ -1875,9 +1886,9 @@ dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5d/e3/6e320aeb24f951449e73867e53c55542bebbaf24faeee7623ef677d66736/opentelemetry_exporter_otlp_proto_http-1.37.0.tar.gz", hash = "sha256:e52e8600f1720d6de298419a802108a8f5afa63c96809ff83becb03f874e44ac", size = 17281, upload-time = "2025-09-11T10:29:04.844Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5d/e3/6e320aeb24f951449e73867e53c55542bebbaf24faeee7623ef677d66736/opentelemetry_exporter_otlp_proto_http-1.37.0.tar.gz", hash = "sha256:e52e8600f1720d6de298419a802108a8f5afa63c96809ff83becb03f874e44ac", size = 17281, upload_time = "2025-09-11T10:29:04.844Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/e9/70d74a664d83976556cec395d6bfedd9b85ec1498b778367d5f93e373397/opentelemetry_exporter_otlp_proto_http-1.37.0-py3-none-any.whl", hash = "sha256:54c42b39945a6cc9d9a2a33decb876eabb9547e0dcb49df090122773447f1aef", size = 19576, upload-time = "2025-09-11T10:28:46.726Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/70d74a664d83976556cec395d6bfedd9b85ec1498b778367d5f93e373397/opentelemetry_exporter_otlp_proto_http-1.37.0-py3-none-any.whl", hash = "sha256:54c42b39945a6cc9d9a2a33decb876eabb9547e0dcb49df090122773447f1aef", size = 19576, upload_time = "2025-09-11T10:28:46.726Z" }, ] [[package]] @@ -1887,9 +1898,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/ea/a75f36b463a36f3c5a10c0b5292c58b31dbdde74f6f905d3d0ab2313987b/opentelemetry_proto-1.37.0.tar.gz", hash = "sha256:30f5c494faf66f77faeaefa35ed4443c5edb3b0aa46dad073ed7210e1a789538", size = 46151, upload-time = "2025-09-11T10:29:11.04Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/ea/a75f36b463a36f3c5a10c0b5292c58b31dbdde74f6f905d3d0ab2313987b/opentelemetry_proto-1.37.0.tar.gz", hash = "sha256:30f5c494faf66f77faeaefa35ed4443c5edb3b0aa46dad073ed7210e1a789538", size = 46151, upload_time = "2025-09-11T10:29:11.04Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/25/f89ea66c59bd7687e218361826c969443c4fa15dfe89733f3bf1e2a9e971/opentelemetry_proto-1.37.0-py3-none-any.whl", hash = "sha256:8ed8c066ae8828bbf0c39229979bdf583a126981142378a9cbe9d6fd5701c6e2", size = 72534, upload-time = "2025-09-11T10:28:56.831Z" }, + { url = "https://files.pythonhosted.org/packages/c4/25/f89ea66c59bd7687e218361826c969443c4fa15dfe89733f3bf1e2a9e971/opentelemetry_proto-1.37.0-py3-none-any.whl", hash = "sha256:8ed8c066ae8828bbf0c39229979bdf583a126981142378a9cbe9d6fd5701c6e2", size = 72534, upload_time = "2025-09-11T10:28:56.831Z" }, ] [[package]] @@ -1902,9 +1913,9 @@ dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/5d/2b3240d914b87b6dd9cd5ca2ef1ccaf1d0626b897d4c06877e22c8c10fcf/opentelemetry_resourcedetector_gcp-1.11.0a0.tar.gz", hash = "sha256:915a1d6fd15daca9eedd3fc52b0f705375054f2ef140e2e7a6b4cca95a47cdb1", size = 18796, upload-time = "2025-11-04T19:32:16.59Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/5d/2b3240d914b87b6dd9cd5ca2ef1ccaf1d0626b897d4c06877e22c8c10fcf/opentelemetry_resourcedetector_gcp-1.11.0a0.tar.gz", hash = "sha256:915a1d6fd15daca9eedd3fc52b0f705375054f2ef140e2e7a6b4cca95a47cdb1", size = 18796, upload_time = "2025-11-04T19:32:16.59Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/6c/1e13fe142a7ca3dc6489167203a1209d32430cca12775e1df9c9a41c54b2/opentelemetry_resourcedetector_gcp-1.11.0a0-py3-none-any.whl", hash = "sha256:5d65a2a039b1d40c6f41421dbb08d5f441368275ac6de6e76a8fccd1f6acb67e", size = 18798, upload-time = "2025-11-04T19:32:10.915Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/1e13fe142a7ca3dc6489167203a1209d32430cca12775e1df9c9a41c54b2/opentelemetry_resourcedetector_gcp-1.11.0a0-py3-none-any.whl", hash = "sha256:5d65a2a039b1d40c6f41421dbb08d5f441368275ac6de6e76a8fccd1f6acb67e", size = 18798, upload_time = "2025-11-04T19:32:10.915Z" }, ] [[package]] @@ -1916,9 +1927,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/62/2e0ca80d7fe94f0b193135375da92c640d15fe81f636658d2acf373086bc/opentelemetry_sdk-1.37.0.tar.gz", hash = "sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5", size = 170404, upload-time = "2025-09-11T10:29:11.779Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/62/2e0ca80d7fe94f0b193135375da92c640d15fe81f636658d2acf373086bc/opentelemetry_sdk-1.37.0.tar.gz", hash = "sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5", size = 170404, upload_time = "2025-09-11T10:29:11.779Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/62/9f4ad6a54126fb00f7ed4bb5034964c6e4f00fcd5a905e115bd22707e20d/opentelemetry_sdk-1.37.0-py3-none-any.whl", hash = "sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c", size = 131941, upload-time = "2025-09-11T10:28:57.83Z" }, + { url = "https://files.pythonhosted.org/packages/9f/62/9f4ad6a54126fb00f7ed4bb5034964c6e4f00fcd5a905e115bd22707e20d/opentelemetry_sdk-1.37.0-py3-none-any.whl", hash = "sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c", size = 131941, upload_time = "2025-09-11T10:28:57.83Z" }, ] [[package]] @@ -1929,9 +1940,9 @@ dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/1b/90701d91e6300d9f2fb352153fb1721ed99ed1f6ea14fa992c756016e63a/opentelemetry_semantic_conventions-0.58b0.tar.gz", hash = "sha256:6bd46f51264279c433755767bb44ad00f1c9e2367e1b42af563372c5a6fa0c25", size = 129867, upload-time = "2025-09-11T10:29:12.597Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/1b/90701d91e6300d9f2fb352153fb1721ed99ed1f6ea14fa992c756016e63a/opentelemetry_semantic_conventions-0.58b0.tar.gz", hash = "sha256:6bd46f51264279c433755767bb44ad00f1c9e2367e1b42af563372c5a6fa0c25", size = 129867, upload_time = "2025-09-11T10:29:12.597Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/90/68152b7465f50285d3ce2481b3aec2f82822e3f52e5152eeeaf516bab841/opentelemetry_semantic_conventions-0.58b0-py3-none-any.whl", hash = "sha256:5564905ab1458b96684db1340232729fce3b5375a06e140e8904c78e4f815b28", size = 207954, upload-time = "2025-09-11T10:28:59.218Z" }, + { url = "https://files.pythonhosted.org/packages/07/90/68152b7465f50285d3ce2481b3aec2f82822e3f52e5152eeeaf516bab841/opentelemetry_semantic_conventions-0.58b0-py3-none-any.whl", hash = "sha256:5564905ab1458b96684db1340232729fce3b5375a06e140e8904c78e4f815b28", size = 207954, upload_time = "2025-09-11T10:28:59.218Z" }, ] [[package]] @@ -1965,96 +1976,96 @@ requires-dist = [ name = "packaging" version = "26.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload_time = "2026-01-21T20:50:39.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload_time = "2026-01-21T20:50:37.788Z" }, ] [[package]] name = "pathspec" version = "1.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload_time = "2026-01-27T03:59:46.938Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload_time = "2026-01-27T03:59:45.137Z" }, ] [[package]] name = "platformdirs" version = "4.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload_time = "2025-12-05T13:52:58.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload_time = "2025-12-05T13:52:56.823Z" }, ] [[package]] name = "propcache" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, - { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, - { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, - { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, - { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, - { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, - { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, - { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, - { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, - { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, - { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, - { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, - { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, - { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, - { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, - { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, - { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, - { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, - { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, - { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, - { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, - { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, - { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, - { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, - { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, - { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, - { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, - { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, - { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, - { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, - { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, - { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, - { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, - { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, - { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, - { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, - { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, - { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, - { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, - { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, - { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, - { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, - { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, - { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, - { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, - { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, - { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload_time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload_time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload_time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload_time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload_time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload_time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload_time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload_time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload_time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload_time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload_time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload_time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload_time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload_time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload_time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload_time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload_time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload_time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload_time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload_time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload_time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload_time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload_time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload_time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload_time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload_time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload_time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload_time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload_time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload_time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload_time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload_time = "2025-10-08T19:47:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload_time = "2025-10-08T19:47:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload_time = "2025-10-08T19:47:54.073Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload_time = "2025-10-08T19:47:55.715Z" }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload_time = "2025-10-08T19:47:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload_time = "2025-10-08T19:47:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload_time = "2025-10-08T19:48:00.67Z" }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload_time = "2025-10-08T19:48:02.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload_time = "2025-10-08T19:48:04.499Z" }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload_time = "2025-10-08T19:48:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload_time = "2025-10-08T19:48:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload_time = "2025-10-08T19:48:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload_time = "2025-10-08T19:48:11.232Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload_time = "2025-10-08T19:48:12.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload_time = "2025-10-08T19:48:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload_time = "2025-10-08T19:48:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload_time = "2025-10-08T19:48:16.424Z" }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload_time = "2025-10-08T19:48:17.577Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload_time = "2025-10-08T19:48:18.901Z" }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload_time = "2025-10-08T19:48:20.762Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload_time = "2025-10-08T19:48:22.592Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload_time = "2025-10-08T19:48:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload_time = "2025-10-08T19:48:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload_time = "2025-10-08T19:48:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload_time = "2025-10-08T19:48:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload_time = "2025-10-08T19:48:30.133Z" }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload_time = "2025-10-08T19:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload_time = "2025-10-08T19:48:32.872Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload_time = "2025-10-08T19:48:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload_time = "2025-10-08T19:48:35.441Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload_time = "2025-10-08T19:49:00.792Z" }, ] [[package]] @@ -2064,69 +2075,69 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3a/02/8832cde80e7380c600fbf55090b6ab7b62bd6825dbedde6d6657c15a1f8e/proto_plus-1.27.1.tar.gz", hash = "sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147", size = 56929, upload-time = "2026-02-02T17:34:49.035Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/02/8832cde80e7380c600fbf55090b6ab7b62bd6825dbedde6d6657c15a1f8e/proto_plus-1.27.1.tar.gz", hash = "sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147", size = 56929, upload_time = "2026-02-02T17:34:49.035Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/79/ac273cbbf744691821a9cca88957257f41afe271637794975ca090b9588b/proto_plus-1.27.1-py3-none-any.whl", hash = "sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc", size = 50480, upload-time = "2026-02-02T17:34:47.339Z" }, + { url = "https://files.pythonhosted.org/packages/5d/79/ac273cbbf744691821a9cca88957257f41afe271637794975ca090b9588b/proto_plus-1.27.1-py3-none-any.whl", hash = "sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc", size = 50480, upload_time = "2026-02-02T17:34:47.339Z" }, ] [[package]] name = "protobuf" version = "6.33.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload_time = "2026-01-29T21:51:33.494Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" }, - { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" }, - { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" }, - { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" }, - { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload_time = "2026-01-29T21:51:21.751Z" }, + { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload_time = "2026-01-29T21:51:24.022Z" }, + { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload_time = "2026-01-29T21:51:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload_time = "2026-01-29T21:51:26.423Z" }, + { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload_time = "2026-01-29T21:51:27.446Z" }, + { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload_time = "2026-01-29T21:51:28.925Z" }, + { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload_time = "2026-01-29T21:51:32.557Z" }, ] [[package]] name = "pyarrow" version = "23.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/33/ffd9c3eb087fa41dd79c3cf20c4c0ae3cdb877c4f8e1107a446006344924/pyarrow-23.0.0.tar.gz", hash = "sha256:180e3150e7edfcd182d3d9afba72f7cf19839a497cc76555a8dce998a8f67615", size = 1167185, upload-time = "2026-01-18T16:19:42.218Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/66/34/564db447d083ec7ff93e0a883a597d2f214e552823bfc178a2d0b1f2c257/pyarrow-23.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:ad96a597547af7827342ffb3c503c8316e5043bb09b47a84885ce39394c96e00", size = 34184630, upload-time = "2026-01-18T16:16:22.141Z" }, - { url = "https://files.pythonhosted.org/packages/aa/3a/3999daebcb5e6119690c92a621c4d78eef2ffba7a0a1b56386d2875fcd77/pyarrow-23.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:b9edf990df77c2901e79608f08c13fbde60202334a4fcadb15c1f57bf7afee43", size = 35796820, upload-time = "2026-01-18T16:16:29.441Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/39195233056c6a8d0976d7d1ac1cd4fe21fb0ec534eca76bc23ef3f60e11/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:36d1b5bc6ddcaff0083ceec7e2561ed61a51f49cce8be079ee8ed406acb6fdef", size = 44438735, upload-time = "2026-01-18T16:16:38.79Z" }, - { url = "https://files.pythonhosted.org/packages/2c/41/6a7328ee493527e7afc0c88d105ecca69a3580e29f2faaeac29308369fd7/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4292b889cd224f403304ddda8b63a36e60f92911f89927ec8d98021845ea21be", size = 47557263, upload-time = "2026-01-18T16:16:46.248Z" }, - { url = "https://files.pythonhosted.org/packages/c6/ee/34e95b21ee84db494eae60083ddb4383477b31fb1fd19fd866d794881696/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dfd9e133e60eaa847fd80530a1b89a052f09f695d0b9c34c235ea6b2e0924cf7", size = 48153529, upload-time = "2026-01-18T16:16:53.412Z" }, - { url = "https://files.pythonhosted.org/packages/52/88/8a8d83cea30f4563efa1b7bf51d241331ee5cd1b185a7e063f5634eca415/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832141cc09fac6aab1cd3719951d23301396968de87080c57c9a7634e0ecd068", size = 50598851, upload-time = "2026-01-18T16:17:01.133Z" }, - { url = "https://files.pythonhosted.org/packages/c6/4c/2929c4be88723ba025e7b3453047dc67e491c9422965c141d24bab6b5962/pyarrow-23.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:7a7d067c9a88faca655c71bcc30ee2782038d59c802d57950826a07f60d83c4c", size = 27577747, upload-time = "2026-01-18T16:18:02.413Z" }, - { url = "https://files.pythonhosted.org/packages/64/52/564a61b0b82d72bd68ec3aef1adda1e3eba776f89134b9ebcb5af4b13cb6/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:ce9486e0535a843cf85d990e2ec5820a47918235183a5c7b8b97ed7e92c2d47d", size = 34446038, upload-time = "2026-01-18T16:17:07.861Z" }, - { url = "https://files.pythonhosted.org/packages/cc/c9/232d4f9855fd1de0067c8a7808a363230d223c83aeee75e0fe6eab851ba9/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:075c29aeaa685fd1182992a9ed2499c66f084ee54eea47da3eb76e125e06064c", size = 35921142, upload-time = "2026-01-18T16:17:15.401Z" }, - { url = "https://files.pythonhosted.org/packages/96/f2/60af606a3748367b906bb82d41f0032e059f075444445d47e32a7ff1df62/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:799965a5379589510d888be3094c2296efd186a17ca1cef5b77703d4d5121f53", size = 44490374, upload-time = "2026-01-18T16:17:23.93Z" }, - { url = "https://files.pythonhosted.org/packages/ff/2d/7731543050a678ea3a413955a2d5d80d2a642f270aa57a3cb7d5a86e3f46/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ef7cac8fe6fccd8b9e7617bfac785b0371a7fe26af59463074e4882747145d40", size = 47527896, upload-time = "2026-01-18T16:17:33.393Z" }, - { url = "https://files.pythonhosted.org/packages/5a/90/f3342553b7ac9879413aed46500f1637296f3c8222107523a43a1c08b42a/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15a414f710dc927132dd67c361f78c194447479555af57317066ee5116b90e9e", size = 48210401, upload-time = "2026-01-18T16:17:42.012Z" }, - { url = "https://files.pythonhosted.org/packages/f3/da/9862ade205ecc46c172b6ce5038a74b5151c7401e36255f15975a45878b2/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e0d2e6915eca7d786be6a77bf227fbc06d825a75b5b5fe9bcbef121dec32685", size = 50579677, upload-time = "2026-01-18T16:17:50.241Z" }, - { url = "https://files.pythonhosted.org/packages/c2/4c/f11f371f5d4740a5dafc2e11c76bcf42d03dfdb2d68696da97de420b6963/pyarrow-23.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4b317ea6e800b5704e5e5929acb6e2dc13e9276b708ea97a39eb8b345aa2658b", size = 27631889, upload-time = "2026-01-18T16:17:56.55Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/15aec78bcf43a0c004067bd33eb5352836a29a49db8581fc56f2b6ca88b7/pyarrow-23.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:20b187ed9550d233a872074159f765f52f9d92973191cd4b93f293a19efbe377", size = 34213265, upload-time = "2026-01-18T16:18:07.904Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/deb2c594bbba41c37c5d9aa82f510376998352aa69dfcb886cb4b18ad80f/pyarrow-23.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:18ec84e839b493c3886b9b5e06861962ab4adfaeb79b81c76afbd8d84c7d5fda", size = 35819211, upload-time = "2026-01-18T16:18:13.94Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e5/ee82af693cb7b5b2b74f6524cdfede0e6ace779d7720ebca24d68b57c36b/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e438dd3f33894e34fd02b26bd12a32d30d006f5852315f611aa4add6c7fab4bc", size = 44502313, upload-time = "2026-01-18T16:18:20.367Z" }, - { url = "https://files.pythonhosted.org/packages/9c/86/95c61ad82236495f3c31987e85135926ba3ec7f3819296b70a68d8066b49/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:a244279f240c81f135631be91146d7fa0e9e840e1dfed2aba8483eba25cd98e6", size = 47585886, upload-time = "2026-01-18T16:18:27.544Z" }, - { url = "https://files.pythonhosted.org/packages/bb/6e/a72d901f305201802f016d015de1e05def7706fff68a1dedefef5dc7eff7/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c4692e83e42438dba512a570c6eaa42be2f8b6c0f492aea27dec54bdc495103a", size = 48207055, upload-time = "2026-01-18T16:18:35.425Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e5/5de029c537630ca18828db45c30e2a78da03675a70ac6c3528203c416fe3/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae7f30f898dfe44ea69654a35c93e8da4cef6606dc4c72394068fd95f8e9f54a", size = 50619812, upload-time = "2026-01-18T16:18:43.553Z" }, - { url = "https://files.pythonhosted.org/packages/59/8d/2af846cd2412e67a087f5bda4a8e23dfd4ebd570f777db2e8686615dafc1/pyarrow-23.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:5b86bb649e4112fb0614294b7d0a175c7513738876b89655605ebb87c804f861", size = 28263851, upload-time = "2026-01-18T16:19:38.567Z" }, - { url = "https://files.pythonhosted.org/packages/7b/7f/caab863e587041156f6786c52e64151b7386742c8c27140f637176e9230e/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:ebc017d765d71d80a3f8584ca0566b53e40464586585ac64176115baa0ada7d3", size = 34463240, upload-time = "2026-01-18T16:18:49.755Z" }, - { url = "https://files.pythonhosted.org/packages/c9/fa/3a5b8c86c958e83622b40865e11af0857c48ec763c11d472c87cd518283d/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:0800cc58a6d17d159df823f87ad66cefebf105b982493d4bad03ee7fab84b993", size = 35935712, upload-time = "2026-01-18T16:18:55.626Z" }, - { url = "https://files.pythonhosted.org/packages/c5/08/17a62078fc1a53decb34a9aa79cf9009efc74d63d2422e5ade9fed2f99e3/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3a7c68c722da9bb5b0f8c10e3eae71d9825a4b429b40b32709df5d1fa55beb3d", size = 44503523, upload-time = "2026-01-18T16:19:03.958Z" }, - { url = "https://files.pythonhosted.org/packages/cc/70/84d45c74341e798aae0323d33b7c39194e23b1abc439ceaf60a68a7a969a/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:bd5556c24622df90551063ea41f559b714aa63ca953db884cfb958559087a14e", size = 47542490, upload-time = "2026-01-18T16:19:11.208Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/d1274b0e6f19e235de17441e53224f4716574b2ca837022d55702f24d71d/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54810f6e6afc4ffee7c2e0051b61722fbea9a4961b46192dcfae8ea12fa09059", size = 48233605, upload-time = "2026-01-18T16:19:19.544Z" }, - { url = "https://files.pythonhosted.org/packages/39/07/e4e2d568cb57543d84482f61e510732820cddb0f47c4bb7df629abfed852/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:14de7d48052cf4b0ed174533eafa3cfe0711b8076ad70bede32cf59f744f0d7c", size = 50603979, upload-time = "2026-01-18T16:19:26.717Z" }, - { url = "https://files.pythonhosted.org/packages/72/9c/47693463894b610f8439b2e970b82ef81e9599c757bf2049365e40ff963c/pyarrow-23.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:427deac1f535830a744a4f04a6ac183a64fcac4341b3f618e693c41b7b98d2b0", size = 28338905, upload-time = "2026-01-18T16:19:32.93Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/01/33/ffd9c3eb087fa41dd79c3cf20c4c0ae3cdb877c4f8e1107a446006344924/pyarrow-23.0.0.tar.gz", hash = "sha256:180e3150e7edfcd182d3d9afba72f7cf19839a497cc76555a8dce998a8f67615", size = 1167185, upload_time = "2026-01-18T16:19:42.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/34/564db447d083ec7ff93e0a883a597d2f214e552823bfc178a2d0b1f2c257/pyarrow-23.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:ad96a597547af7827342ffb3c503c8316e5043bb09b47a84885ce39394c96e00", size = 34184630, upload_time = "2026-01-18T16:16:22.141Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3a/3999daebcb5e6119690c92a621c4d78eef2ffba7a0a1b56386d2875fcd77/pyarrow-23.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:b9edf990df77c2901e79608f08c13fbde60202334a4fcadb15c1f57bf7afee43", size = 35796820, upload_time = "2026-01-18T16:16:29.441Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/39195233056c6a8d0976d7d1ac1cd4fe21fb0ec534eca76bc23ef3f60e11/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:36d1b5bc6ddcaff0083ceec7e2561ed61a51f49cce8be079ee8ed406acb6fdef", size = 44438735, upload_time = "2026-01-18T16:16:38.79Z" }, + { url = "https://files.pythonhosted.org/packages/2c/41/6a7328ee493527e7afc0c88d105ecca69a3580e29f2faaeac29308369fd7/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4292b889cd224f403304ddda8b63a36e60f92911f89927ec8d98021845ea21be", size = 47557263, upload_time = "2026-01-18T16:16:46.248Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ee/34e95b21ee84db494eae60083ddb4383477b31fb1fd19fd866d794881696/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dfd9e133e60eaa847fd80530a1b89a052f09f695d0b9c34c235ea6b2e0924cf7", size = 48153529, upload_time = "2026-01-18T16:16:53.412Z" }, + { url = "https://files.pythonhosted.org/packages/52/88/8a8d83cea30f4563efa1b7bf51d241331ee5cd1b185a7e063f5634eca415/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832141cc09fac6aab1cd3719951d23301396968de87080c57c9a7634e0ecd068", size = 50598851, upload_time = "2026-01-18T16:17:01.133Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4c/2929c4be88723ba025e7b3453047dc67e491c9422965c141d24bab6b5962/pyarrow-23.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:7a7d067c9a88faca655c71bcc30ee2782038d59c802d57950826a07f60d83c4c", size = 27577747, upload_time = "2026-01-18T16:18:02.413Z" }, + { url = "https://files.pythonhosted.org/packages/64/52/564a61b0b82d72bd68ec3aef1adda1e3eba776f89134b9ebcb5af4b13cb6/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:ce9486e0535a843cf85d990e2ec5820a47918235183a5c7b8b97ed7e92c2d47d", size = 34446038, upload_time = "2026-01-18T16:17:07.861Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c9/232d4f9855fd1de0067c8a7808a363230d223c83aeee75e0fe6eab851ba9/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:075c29aeaa685fd1182992a9ed2499c66f084ee54eea47da3eb76e125e06064c", size = 35921142, upload_time = "2026-01-18T16:17:15.401Z" }, + { url = "https://files.pythonhosted.org/packages/96/f2/60af606a3748367b906bb82d41f0032e059f075444445d47e32a7ff1df62/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:799965a5379589510d888be3094c2296efd186a17ca1cef5b77703d4d5121f53", size = 44490374, upload_time = "2026-01-18T16:17:23.93Z" }, + { url = "https://files.pythonhosted.org/packages/ff/2d/7731543050a678ea3a413955a2d5d80d2a642f270aa57a3cb7d5a86e3f46/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ef7cac8fe6fccd8b9e7617bfac785b0371a7fe26af59463074e4882747145d40", size = 47527896, upload_time = "2026-01-18T16:17:33.393Z" }, + { url = "https://files.pythonhosted.org/packages/5a/90/f3342553b7ac9879413aed46500f1637296f3c8222107523a43a1c08b42a/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15a414f710dc927132dd67c361f78c194447479555af57317066ee5116b90e9e", size = 48210401, upload_time = "2026-01-18T16:17:42.012Z" }, + { url = "https://files.pythonhosted.org/packages/f3/da/9862ade205ecc46c172b6ce5038a74b5151c7401e36255f15975a45878b2/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e0d2e6915eca7d786be6a77bf227fbc06d825a75b5b5fe9bcbef121dec32685", size = 50579677, upload_time = "2026-01-18T16:17:50.241Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4c/f11f371f5d4740a5dafc2e11c76bcf42d03dfdb2d68696da97de420b6963/pyarrow-23.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4b317ea6e800b5704e5e5929acb6e2dc13e9276b708ea97a39eb8b345aa2658b", size = 27631889, upload_time = "2026-01-18T16:17:56.55Z" }, + { url = "https://files.pythonhosted.org/packages/97/bb/15aec78bcf43a0c004067bd33eb5352836a29a49db8581fc56f2b6ca88b7/pyarrow-23.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:20b187ed9550d233a872074159f765f52f9d92973191cd4b93f293a19efbe377", size = 34213265, upload_time = "2026-01-18T16:18:07.904Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/deb2c594bbba41c37c5d9aa82f510376998352aa69dfcb886cb4b18ad80f/pyarrow-23.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:18ec84e839b493c3886b9b5e06861962ab4adfaeb79b81c76afbd8d84c7d5fda", size = 35819211, upload_time = "2026-01-18T16:18:13.94Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/ee82af693cb7b5b2b74f6524cdfede0e6ace779d7720ebca24d68b57c36b/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e438dd3f33894e34fd02b26bd12a32d30d006f5852315f611aa4add6c7fab4bc", size = 44502313, upload_time = "2026-01-18T16:18:20.367Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/95c61ad82236495f3c31987e85135926ba3ec7f3819296b70a68d8066b49/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:a244279f240c81f135631be91146d7fa0e9e840e1dfed2aba8483eba25cd98e6", size = 47585886, upload_time = "2026-01-18T16:18:27.544Z" }, + { url = "https://files.pythonhosted.org/packages/bb/6e/a72d901f305201802f016d015de1e05def7706fff68a1dedefef5dc7eff7/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c4692e83e42438dba512a570c6eaa42be2f8b6c0f492aea27dec54bdc495103a", size = 48207055, upload_time = "2026-01-18T16:18:35.425Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/5de029c537630ca18828db45c30e2a78da03675a70ac6c3528203c416fe3/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae7f30f898dfe44ea69654a35c93e8da4cef6606dc4c72394068fd95f8e9f54a", size = 50619812, upload_time = "2026-01-18T16:18:43.553Z" }, + { url = "https://files.pythonhosted.org/packages/59/8d/2af846cd2412e67a087f5bda4a8e23dfd4ebd570f777db2e8686615dafc1/pyarrow-23.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:5b86bb649e4112fb0614294b7d0a175c7513738876b89655605ebb87c804f861", size = 28263851, upload_time = "2026-01-18T16:19:38.567Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7f/caab863e587041156f6786c52e64151b7386742c8c27140f637176e9230e/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:ebc017d765d71d80a3f8584ca0566b53e40464586585ac64176115baa0ada7d3", size = 34463240, upload_time = "2026-01-18T16:18:49.755Z" }, + { url = "https://files.pythonhosted.org/packages/c9/fa/3a5b8c86c958e83622b40865e11af0857c48ec763c11d472c87cd518283d/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:0800cc58a6d17d159df823f87ad66cefebf105b982493d4bad03ee7fab84b993", size = 35935712, upload_time = "2026-01-18T16:18:55.626Z" }, + { url = "https://files.pythonhosted.org/packages/c5/08/17a62078fc1a53decb34a9aa79cf9009efc74d63d2422e5ade9fed2f99e3/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3a7c68c722da9bb5b0f8c10e3eae71d9825a4b429b40b32709df5d1fa55beb3d", size = 44503523, upload_time = "2026-01-18T16:19:03.958Z" }, + { url = "https://files.pythonhosted.org/packages/cc/70/84d45c74341e798aae0323d33b7c39194e23b1abc439ceaf60a68a7a969a/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:bd5556c24622df90551063ea41f559b714aa63ca953db884cfb958559087a14e", size = 47542490, upload_time = "2026-01-18T16:19:11.208Z" }, + { url = "https://files.pythonhosted.org/packages/61/d9/d1274b0e6f19e235de17441e53224f4716574b2ca837022d55702f24d71d/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54810f6e6afc4ffee7c2e0051b61722fbea9a4961b46192dcfae8ea12fa09059", size = 48233605, upload_time = "2026-01-18T16:19:19.544Z" }, + { url = "https://files.pythonhosted.org/packages/39/07/e4e2d568cb57543d84482f61e510732820cddb0f47c4bb7df629abfed852/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:14de7d48052cf4b0ed174533eafa3cfe0711b8076ad70bede32cf59f744f0d7c", size = 50603979, upload_time = "2026-01-18T16:19:26.717Z" }, + { url = "https://files.pythonhosted.org/packages/72/9c/47693463894b610f8439b2e970b82ef81e9599c757bf2049365e40ff963c/pyarrow-23.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:427deac1f535830a744a4f04a6ac183a64fcac4341b3f618e693c41b7b98d2b0", size = 28338905, upload_time = "2026-01-18T16:19:32.93Z" }, ] [[package]] name = "pyasn1" version = "0.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/b6/6e630dff89739fcd427e3f72b3d905ce0acb85a45d4ec3e2678718a3487f/pyasn1-0.6.2.tar.gz", hash = "sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b", size = 146586, upload-time = "2026-01-16T18:04:18.534Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/b6/6e630dff89739fcd427e3f72b3d905ce0acb85a45d4ec3e2678718a3487f/pyasn1-0.6.2.tar.gz", hash = "sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b", size = 146586, upload_time = "2026-01-16T18:04:18.534Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl", hash = "sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf", size = 83371, upload-time = "2026-01-16T18:04:17.174Z" }, + { url = "https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl", hash = "sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf", size = 83371, upload_time = "2026-01-16T18:04:17.174Z" }, ] [[package]] @@ -2136,18 +2147,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload_time = "2025-03-28T02:41:22.17Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload_time = "2025-03-28T02:41:19.028Z" }, ] [[package]] name = "pycparser" version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload_time = "2026-01-21T14:26:51.89Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload_time = "2026-01-21T14:26:50.693Z" }, ] [[package]] @@ -2160,9 +2171,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload_time = "2025-11-26T15:11:46.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload_time = "2025-11-26T15:11:44.605Z" }, ] [[package]] @@ -2172,50 +2183,50 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, - { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, - { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, - { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, - { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, - { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, - { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, - { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, - { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, - { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, - { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, - { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, - { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, - { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, - { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, - { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, - { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, - { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, - { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, - { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, - { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, - { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, - { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, - { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, - { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, - { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, - { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, - { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, - { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, - { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, - { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, - { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, - { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload_time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload_time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload_time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload_time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload_time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload_time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload_time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload_time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload_time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload_time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload_time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload_time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload_time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload_time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload_time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload_time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload_time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload_time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload_time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload_time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload_time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload_time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload_time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload_time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload_time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload_time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload_time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload_time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload_time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload_time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload_time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload_time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload_time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload_time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload_time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload_time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload_time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload_time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload_time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload_time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload_time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload_time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload_time = "2025-11-04T13:42:01.186Z" }, ] [[package]] @@ -2227,18 +2238,18 @@ dependencies = [ { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload_time = "2025-11-10T14:25:47.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload_time = "2025-11-10T14:25:45.546Z" }, ] [[package]] name = "pygments" version = "2.19.2" 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" } +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" }, + { 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" }, ] [[package]] @@ -2254,18 +2265,18 @@ dependencies = [ { name = "platformdirs" }, { name = "pytokens" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/31/45/5940abea3a364768b267ff4c73d898f7d692f649540e613a8fe67089abcc/pyink-25.12.0.tar.gz", hash = "sha256:930a913fed2824ffbbd3c10847fad1171c2b075dd709a13dc435caea851de7b8", size = 279674, upload-time = "2026-01-02T15:02:22.259Z" } +sdist = { url = "https://files.pythonhosted.org/packages/31/45/5940abea3a364768b267ff4c73d898f7d692f649540e613a8fe67089abcc/pyink-25.12.0.tar.gz", hash = "sha256:930a913fed2824ffbbd3c10847fad1171c2b075dd709a13dc435caea851de7b8", size = 279674, upload_time = "2026-01-02T15:02:22.259Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/0b/209f6cde8f7c2ad8a47a2b5e41da101e6af782f8896d99f6cf2620c87ba7/pyink-25.12.0-py3-none-any.whl", hash = "sha256:3c9ed8c6f1f6f4a7f3a6a3a31bff5a7ab6b3c88954dc456273c8e71ce6ff0508", size = 143528, upload-time = "2026-01-02T15:02:20.385Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0b/209f6cde8f7c2ad8a47a2b5e41da101e6af782f8896d99f6cf2620c87ba7/pyink-25.12.0-py3-none-any.whl", hash = "sha256:3c9ed8c6f1f6f4a7f3a6a3a31bff5a7ab6b3c88954dc456273c8e71ce6ff0508", size = 143528, upload_time = "2026-01-02T15:02:20.385Z" }, ] [[package]] name = "pyjwt" version = "2.11.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload_time = "2026-01-30T19:59:55.694Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" }, + { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload_time = "2026-01-30T19:59:54.539Z" }, ] [package.optional-dependencies] @@ -2277,9 +2288,9 @@ crypto = [ name = "pyparsing" version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload_time = "2026-01-21T03:57:59.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload_time = "2026-01-21T03:57:55.912Z" }, ] [[package]] @@ -2289,51 +2300,51 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload_time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload_time = "2024-03-01T18:36:18.57Z" }, ] [[package]] name = "python-dotenv" version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload_time = "2025-10-26T15:12:10.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload_time = "2025-10-26T15:12:09.109Z" }, ] [[package]] name = "python-multipart" version = "0.0.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload_time = "2026-01-25T10:15:56.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, + { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload_time = "2026-01-25T10:15:54.811Z" }, ] [[package]] name = "pytokens" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload_time = "2026-01-30T01:03:45.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload-time = "2026-01-30T01:03:13.843Z" }, - { url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload-time = "2026-01-30T01:03:14.886Z" }, - { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" }, - { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" }, - { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" }, - { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" }, - { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" }, - { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" }, - { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" }, - { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" }, - { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" }, - { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" }, - { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, - { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, - { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, - { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, + { url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload_time = "2026-01-30T01:03:13.843Z" }, + { url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload_time = "2026-01-30T01:03:14.886Z" }, + { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload_time = "2026-01-30T01:03:15.936Z" }, + { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload_time = "2026-01-30T01:03:17.458Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload_time = "2026-01-30T01:03:18.652Z" }, + { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload_time = "2026-01-30T01:03:19.684Z" }, + { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload_time = "2026-01-30T01:03:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload_time = "2026-01-30T01:03:21.888Z" }, + { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload_time = "2026-01-30T01:03:23.633Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload_time = "2026-01-30T01:03:24.788Z" }, + { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload_time = "2026-01-30T01:03:26.428Z" }, + { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload_time = "2026-01-30T01:03:27.415Z" }, + { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload_time = "2026-01-30T01:03:28.558Z" }, + { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload_time = "2026-01-30T01:03:29.653Z" }, + { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload_time = "2026-01-30T01:03:30.912Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload_time = "2026-01-30T01:03:45.029Z" }, ] [[package]] @@ -2341,48 +2352,48 @@ name = "pywin32" version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, - { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, - { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, - { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload_time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload_time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload_time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload_time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload_time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload_time = "2025-07-14T20:13:36.379Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, - { 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" }, +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload_time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload_time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload_time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload_time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload_time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload_time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload_time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload_time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload_time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload_time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload_time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload_time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload_time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload_time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload_time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload_time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload_time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload_time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload_time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload_time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload_time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload_time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload_time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload_time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload_time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload_time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload_time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload_time = "2025-09-25T21:32:55.767Z" }, + { 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]] @@ -2393,81 +2404,81 @@ dependencies = [ { name = "attrs" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload_time = "2025-10-13T15:30:48.871Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload_time = "2025-10-13T15:30:47.625Z" }, ] [[package]] name = "regex" version = "2026.1.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/86/07d5056945f9ec4590b518171c4254a5925832eb727b56d3c38a7476f316/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5", size = 414811, upload-time = "2026-01-14T23:18:02.775Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/2e/6870bb16e982669b674cce3ee9ff2d1d46ab80528ee6bcc20fb2292efb60/regex-2026.1.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e69d0deeb977ffe7ed3d2e4439360089f9c3f217ada608f0f88ebd67afb6385e", size = 489164, upload-time = "2026-01-14T23:15:13.962Z" }, - { url = "https://files.pythonhosted.org/packages/dc/67/9774542e203849b0286badf67199970a44ebdb0cc5fb739f06e47ada72f8/regex-2026.1.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3601ffb5375de85a16f407854d11cca8fe3f5febbe3ac78fb2866bb220c74d10", size = 291218, upload-time = "2026-01-14T23:15:15.647Z" }, - { url = "https://files.pythonhosted.org/packages/b2/87/b0cda79f22b8dee05f774922a214da109f9a4c0eca5da2c9d72d77ea062c/regex-2026.1.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4c5ef43b5c2d4114eb8ea424bb8c9cec01d5d17f242af88b2448f5ee81caadbc", size = 288895, upload-time = "2026-01-14T23:15:17.788Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/0041f0a2170d32be01ab981d6346c83a8934277d82c780d60b127331f264/regex-2026.1.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:968c14d4f03e10b2fd960f1d5168c1f0ac969381d3c1fcc973bc45fb06346599", size = 798680, upload-time = "2026-01-14T23:15:19.342Z" }, - { url = "https://files.pythonhosted.org/packages/58/de/30e1cfcdbe3e891324aa7568b7c968771f82190df5524fabc1138cb2d45a/regex-2026.1.15-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56a5595d0f892f214609c9f76b41b7428bed439d98dc961efafdd1354d42baae", size = 864210, upload-time = "2026-01-14T23:15:22.005Z" }, - { url = "https://files.pythonhosted.org/packages/64/44/4db2f5c5ca0ccd40ff052ae7b1e9731352fcdad946c2b812285a7505ca75/regex-2026.1.15-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf650f26087363434c4e560011f8e4e738f6f3e029b85d4904c50135b86cfa5", size = 912358, upload-time = "2026-01-14T23:15:24.569Z" }, - { url = "https://files.pythonhosted.org/packages/79/b6/e6a5665d43a7c42467138c8a2549be432bad22cbd206f5ec87162de74bd7/regex-2026.1.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18388a62989c72ac24de75f1449d0fb0b04dfccd0a1a7c1c43af5eb503d890f6", size = 803583, upload-time = "2026-01-14T23:15:26.526Z" }, - { url = "https://files.pythonhosted.org/packages/e7/53/7cd478222169d85d74d7437e74750005e993f52f335f7c04ff7adfda3310/regex-2026.1.15-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d220a2517f5893f55daac983bfa9fe998a7dbcaee4f5d27a88500f8b7873788", size = 775782, upload-time = "2026-01-14T23:15:29.352Z" }, - { url = "https://files.pythonhosted.org/packages/ca/b5/75f9a9ee4b03a7c009fe60500fe550b45df94f0955ca29af16333ef557c5/regex-2026.1.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9c08c2fbc6120e70abff5d7f28ffb4d969e14294fb2143b4b5c7d20e46d1714", size = 787978, upload-time = "2026-01-14T23:15:31.295Z" }, - { url = "https://files.pythonhosted.org/packages/72/b3/79821c826245bbe9ccbb54f6eadb7879c722fd3e0248c17bfc90bf54e123/regex-2026.1.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7ef7d5d4bd49ec7364315167a4134a015f61e8266c6d446fc116a9ac4456e10d", size = 858550, upload-time = "2026-01-14T23:15:33.558Z" }, - { url = "https://files.pythonhosted.org/packages/4a/85/2ab5f77a1c465745bfbfcb3ad63178a58337ae8d5274315e2cc623a822fa/regex-2026.1.15-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e42844ad64194fa08d5ccb75fe6a459b9b08e6d7296bd704460168d58a388f3", size = 763747, upload-time = "2026-01-14T23:15:35.206Z" }, - { url = "https://files.pythonhosted.org/packages/6d/84/c27df502d4bfe2873a3e3a7cf1bdb2b9cc10284d1a44797cf38bed790470/regex-2026.1.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cfecdaa4b19f9ca534746eb3b55a5195d5c95b88cac32a205e981ec0a22b7d31", size = 850615, upload-time = "2026-01-14T23:15:37.523Z" }, - { url = "https://files.pythonhosted.org/packages/7d/b7/658a9782fb253680aa8ecb5ccbb51f69e088ed48142c46d9f0c99b46c575/regex-2026.1.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:08df9722d9b87834a3d701f3fca570b2be115654dbfd30179f30ab2f39d606d3", size = 789951, upload-time = "2026-01-14T23:15:39.582Z" }, - { url = "https://files.pythonhosted.org/packages/fc/2a/5928af114441e059f15b2f63e188bd00c6529b3051c974ade7444b85fcda/regex-2026.1.15-cp313-cp313-win32.whl", hash = "sha256:d426616dae0967ca225ab12c22274eb816558f2f99ccb4a1d52ca92e8baf180f", size = 266275, upload-time = "2026-01-14T23:15:42.108Z" }, - { url = "https://files.pythonhosted.org/packages/4f/16/5bfbb89e435897bff28cf0352a992ca719d9e55ebf8b629203c96b6ce4f7/regex-2026.1.15-cp313-cp313-win_amd64.whl", hash = "sha256:febd38857b09867d3ed3f4f1af7d241c5c50362e25ef43034995b77a50df494e", size = 277145, upload-time = "2026-01-14T23:15:44.244Z" }, - { url = "https://files.pythonhosted.org/packages/56/c1/a09ff7392ef4233296e821aec5f78c51be5e91ffde0d163059e50fd75835/regex-2026.1.15-cp313-cp313-win_arm64.whl", hash = "sha256:8e32f7896f83774f91499d239e24cebfadbc07639c1494bb7213983842348337", size = 270411, upload-time = "2026-01-14T23:15:45.858Z" }, - { url = "https://files.pythonhosted.org/packages/3c/38/0cfd5a78e5c6db00e6782fdae70458f89850ce95baa5e8694ab91d89744f/regex-2026.1.15-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ec94c04149b6a7b8120f9f44565722c7ae31b7a6d2275569d2eefa76b83da3be", size = 492068, upload-time = "2026-01-14T23:15:47.616Z" }, - { url = "https://files.pythonhosted.org/packages/50/72/6c86acff16cb7c959c4355826bbf06aad670682d07c8f3998d9ef4fee7cd/regex-2026.1.15-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40c86d8046915bb9aeb15d3f3f15b6fd500b8ea4485b30e1bbc799dab3fe29f8", size = 292756, upload-time = "2026-01-14T23:15:49.307Z" }, - { url = "https://files.pythonhosted.org/packages/4e/58/df7fb69eadfe76526ddfce28abdc0af09ffe65f20c2c90932e89d705153f/regex-2026.1.15-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:726ea4e727aba21643205edad8f2187ec682d3305d790f73b7a51c7587b64bdd", size = 291114, upload-time = "2026-01-14T23:15:51.484Z" }, - { url = "https://files.pythonhosted.org/packages/ed/6c/a4011cd1cf96b90d2cdc7e156f91efbd26531e822a7fbb82a43c1016678e/regex-2026.1.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cb740d044aff31898804e7bf1181cc72c03d11dfd19932b9911ffc19a79070a", size = 807524, upload-time = "2026-01-14T23:15:53.102Z" }, - { url = "https://files.pythonhosted.org/packages/1d/25/a53ffb73183f69c3e9f4355c4922b76d2840aee160af6af5fac229b6201d/regex-2026.1.15-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05d75a668e9ea16f832390d22131fe1e8acc8389a694c8febc3e340b0f810b93", size = 873455, upload-time = "2026-01-14T23:15:54.956Z" }, - { url = "https://files.pythonhosted.org/packages/66/0b/8b47fc2e8f97d9b4a851736f3890a5f786443aa8901061c55f24c955f45b/regex-2026.1.15-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d991483606f3dbec93287b9f35596f41aa2e92b7c2ebbb935b63f409e243c9af", size = 915007, upload-time = "2026-01-14T23:15:57.041Z" }, - { url = "https://files.pythonhosted.org/packages/c2/fa/97de0d681e6d26fabe71968dbee06dd52819e9a22fdce5dac7256c31ed84/regex-2026.1.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:194312a14819d3e44628a44ed6fea6898fdbecb0550089d84c403475138d0a09", size = 812794, upload-time = "2026-01-14T23:15:58.916Z" }, - { url = "https://files.pythonhosted.org/packages/22/38/e752f94e860d429654aa2b1c51880bff8dfe8f084268258adf9151cf1f53/regex-2026.1.15-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe2fda4110a3d0bc163c2e0664be44657431440722c5c5315c65155cab92f9e5", size = 781159, upload-time = "2026-01-14T23:16:00.817Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a7/d739ffaef33c378fc888302a018d7f81080393d96c476b058b8c64fd2b0d/regex-2026.1.15-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:124dc36c85d34ef2d9164da41a53c1c8c122cfb1f6e1ec377a1f27ee81deb794", size = 795558, upload-time = "2026-01-14T23:16:03.267Z" }, - { url = "https://files.pythonhosted.org/packages/3e/c4/542876f9a0ac576100fc73e9c75b779f5c31e3527576cfc9cb3009dcc58a/regex-2026.1.15-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1774cd1981cd212506a23a14dba7fdeaee259f5deba2df6229966d9911e767a", size = 868427, upload-time = "2026-01-14T23:16:05.646Z" }, - { url = "https://files.pythonhosted.org/packages/fc/0f/d5655bea5b22069e32ae85a947aa564912f23758e112cdb74212848a1a1b/regex-2026.1.15-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b5f7d8d2867152cdb625e72a530d2ccb48a3d199159144cbdd63870882fb6f80", size = 769939, upload-time = "2026-01-14T23:16:07.542Z" }, - { url = "https://files.pythonhosted.org/packages/20/06/7e18a4fa9d326daeda46d471a44ef94201c46eaa26dbbb780b5d92cbfdda/regex-2026.1.15-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:492534a0ab925d1db998defc3c302dae3616a2fc3fe2e08db1472348f096ddf2", size = 854753, upload-time = "2026-01-14T23:16:10.395Z" }, - { url = "https://files.pythonhosted.org/packages/3b/67/dc8946ef3965e166f558ef3b47f492bc364e96a265eb4a2bb3ca765c8e46/regex-2026.1.15-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c661fc820cfb33e166bf2450d3dadbda47c8d8981898adb9b6fe24e5e582ba60", size = 799559, upload-time = "2026-01-14T23:16:12.347Z" }, - { url = "https://files.pythonhosted.org/packages/a5/61/1bba81ff6d50c86c65d9fd84ce9699dd106438ee4cdb105bf60374ee8412/regex-2026.1.15-cp313-cp313t-win32.whl", hash = "sha256:99ad739c3686085e614bf77a508e26954ff1b8f14da0e3765ff7abbf7799f952", size = 268879, upload-time = "2026-01-14T23:16:14.049Z" }, - { url = "https://files.pythonhosted.org/packages/e9/5e/cef7d4c5fb0ea3ac5c775fd37db5747f7378b29526cc83f572198924ff47/regex-2026.1.15-cp313-cp313t-win_amd64.whl", hash = "sha256:32655d17905e7ff8ba5c764c43cb124e34a9245e45b83c22e81041e1071aee10", size = 280317, upload-time = "2026-01-14T23:16:15.718Z" }, - { url = "https://files.pythonhosted.org/packages/b4/52/4317f7a5988544e34ab57b4bde0f04944c4786128c933fb09825924d3e82/regex-2026.1.15-cp313-cp313t-win_arm64.whl", hash = "sha256:b2a13dd6a95e95a489ca242319d18fc02e07ceb28fa9ad146385194d95b3c829", size = 271551, upload-time = "2026-01-14T23:16:17.533Z" }, - { url = "https://files.pythonhosted.org/packages/52/0a/47fa888ec7cbbc7d62c5f2a6a888878e76169170ead271a35239edd8f0e8/regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac", size = 489170, upload-time = "2026-01-14T23:16:19.835Z" }, - { url = "https://files.pythonhosted.org/packages/ac/c4/d000e9b7296c15737c9301708e9e7fbdea009f8e93541b6b43bdb8219646/regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6", size = 291146, upload-time = "2026-01-14T23:16:21.541Z" }, - { url = "https://files.pythonhosted.org/packages/f9/b6/921cc61982e538682bdf3bdf5b2c6ab6b34368da1f8e98a6c1ddc503c9cf/regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2", size = 288986, upload-time = "2026-01-14T23:16:23.381Z" }, - { url = "https://files.pythonhosted.org/packages/ca/33/eb7383dde0bbc93f4fb9d03453aab97e18ad4024ac7e26cef8d1f0a2cff0/regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846", size = 799098, upload-time = "2026-01-14T23:16:25.088Z" }, - { url = "https://files.pythonhosted.org/packages/27/56/b664dccae898fc8d8b4c23accd853f723bde0f026c747b6f6262b688029c/regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b", size = 864980, upload-time = "2026-01-14T23:16:27.297Z" }, - { url = "https://files.pythonhosted.org/packages/16/40/0999e064a170eddd237bae9ccfcd8f28b3aa98a38bf727a086425542a4fc/regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e", size = 911607, upload-time = "2026-01-14T23:16:29.235Z" }, - { url = "https://files.pythonhosted.org/packages/07/78/c77f644b68ab054e5a674fb4da40ff7bffb2c88df58afa82dbf86573092d/regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde", size = 803358, upload-time = "2026-01-14T23:16:31.369Z" }, - { url = "https://files.pythonhosted.org/packages/27/31/d4292ea8566eaa551fafc07797961c5963cf5235c797cc2ae19b85dfd04d/regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5", size = 775833, upload-time = "2026-01-14T23:16:33.141Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b2/cff3bf2fea4133aa6fb0d1e370b37544d18c8350a2fa118c7e11d1db0e14/regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34", size = 788045, upload-time = "2026-01-14T23:16:35.005Z" }, - { url = "https://files.pythonhosted.org/packages/8d/99/2cb9b69045372ec877b6f5124bda4eb4253bc58b8fe5848c973f752bc52c/regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75", size = 859374, upload-time = "2026-01-14T23:16:36.919Z" }, - { url = "https://files.pythonhosted.org/packages/09/16/710b0a5abe8e077b1729a562d2f297224ad079f3a66dce46844c193416c8/regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e", size = 763940, upload-time = "2026-01-14T23:16:38.685Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d1/7585c8e744e40eb3d32f119191969b91de04c073fca98ec14299041f6e7e/regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160", size = 850112, upload-time = "2026-01-14T23:16:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/af/d6/43e1dd85df86c49a347aa57c1f69d12c652c7b60e37ec162e3096194a278/regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1", size = 789586, upload-time = "2026-01-14T23:16:42.799Z" }, - { url = "https://files.pythonhosted.org/packages/93/38/77142422f631e013f316aaae83234c629555729a9fbc952b8a63ac91462a/regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1", size = 271691, upload-time = "2026-01-14T23:16:44.671Z" }, - { url = "https://files.pythonhosted.org/packages/4a/a9/ab16b4649524ca9e05213c1cdbb7faa85cc2aa90a0230d2f796cbaf22736/regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903", size = 280422, upload-time = "2026-01-14T23:16:46.607Z" }, - { url = "https://files.pythonhosted.org/packages/be/2a/20fd057bf3521cb4791f69f869635f73e0aaf2b9ad2d260f728144f9047c/regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705", size = 273467, upload-time = "2026-01-14T23:16:48.967Z" }, - { url = "https://files.pythonhosted.org/packages/ad/77/0b1e81857060b92b9cad239104c46507dd481b3ff1fa79f8e7f865aae38a/regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8", size = 492073, upload-time = "2026-01-14T23:16:51.154Z" }, - { url = "https://files.pythonhosted.org/packages/70/f3/f8302b0c208b22c1e4f423147e1913fd475ddd6230565b299925353de644/regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf", size = 292757, upload-time = "2026-01-14T23:16:53.08Z" }, - { url = "https://files.pythonhosted.org/packages/bf/f0/ef55de2460f3b4a6da9d9e7daacd0cb79d4ef75c64a2af316e68447f0df0/regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d", size = 291122, upload-time = "2026-01-14T23:16:55.383Z" }, - { url = "https://files.pythonhosted.org/packages/cf/55/bb8ccbacabbc3a11d863ee62a9f18b160a83084ea95cdfc5d207bfc3dd75/regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84", size = 807761, upload-time = "2026-01-14T23:16:57.251Z" }, - { url = "https://files.pythonhosted.org/packages/8f/84/f75d937f17f81e55679a0509e86176e29caa7298c38bd1db7ce9c0bf6075/regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df", size = 873538, upload-time = "2026-01-14T23:16:59.349Z" }, - { url = "https://files.pythonhosted.org/packages/b8/d9/0da86327df70349aa8d86390da91171bd3ca4f0e7c1d1d453a9c10344da3/regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434", size = 915066, upload-time = "2026-01-14T23:17:01.607Z" }, - { url = "https://files.pythonhosted.org/packages/2a/5e/f660fb23fc77baa2a61aa1f1fe3a4eea2bbb8a286ddec148030672e18834/regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a", size = 812938, upload-time = "2026-01-14T23:17:04.366Z" }, - { url = "https://files.pythonhosted.org/packages/69/33/a47a29bfecebbbfd1e5cd3f26b28020a97e4820f1c5148e66e3b7d4b4992/regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10", size = 781314, upload-time = "2026-01-14T23:17:06.378Z" }, - { url = "https://files.pythonhosted.org/packages/65/ec/7ec2bbfd4c3f4e494a24dec4c6943a668e2030426b1b8b949a6462d2c17b/regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac", size = 795652, upload-time = "2026-01-14T23:17:08.521Z" }, - { url = "https://files.pythonhosted.org/packages/46/79/a5d8651ae131fe27d7c521ad300aa7f1c7be1dbeee4d446498af5411b8a9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea", size = 868550, upload-time = "2026-01-14T23:17:10.573Z" }, - { url = "https://files.pythonhosted.org/packages/06/b7/25635d2809664b79f183070786a5552dd4e627e5aedb0065f4e3cf8ee37d/regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e", size = 769981, upload-time = "2026-01-14T23:17:12.871Z" }, - { url = "https://files.pythonhosted.org/packages/16/8b/fc3fcbb2393dcfa4a6c5ffad92dc498e842df4581ea9d14309fcd3c55fb9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521", size = 854780, upload-time = "2026-01-14T23:17:14.837Z" }, - { url = "https://files.pythonhosted.org/packages/d0/38/dde117c76c624713c8a2842530be9c93ca8b606c0f6102d86e8cd1ce8bea/regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db", size = 799778, upload-time = "2026-01-14T23:17:17.369Z" }, - { url = "https://files.pythonhosted.org/packages/e3/0d/3a6cfa9ae99606afb612d8fb7a66b245a9d5ff0f29bb347c8a30b6ad561b/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e", size = 274667, upload-time = "2026-01-14T23:17:19.301Z" }, - { url = "https://files.pythonhosted.org/packages/5b/b2/297293bb0742fd06b8d8e2572db41a855cdf1cae0bf009b1cb74fe07e196/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf", size = 284386, upload-time = "2026-01-14T23:17:21.231Z" }, - { url = "https://files.pythonhosted.org/packages/95/e4/a3b9480c78cf8ee86626cb06f8d931d74d775897d44201ccb813097ae697/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70", size = 274837, upload-time = "2026-01-14T23:17:23.146Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0b/86/07d5056945f9ec4590b518171c4254a5925832eb727b56d3c38a7476f316/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5", size = 414811, upload_time = "2026-01-14T23:18:02.775Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/2e/6870bb16e982669b674cce3ee9ff2d1d46ab80528ee6bcc20fb2292efb60/regex-2026.1.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e69d0deeb977ffe7ed3d2e4439360089f9c3f217ada608f0f88ebd67afb6385e", size = 489164, upload_time = "2026-01-14T23:15:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/9774542e203849b0286badf67199970a44ebdb0cc5fb739f06e47ada72f8/regex-2026.1.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3601ffb5375de85a16f407854d11cca8fe3f5febbe3ac78fb2866bb220c74d10", size = 291218, upload_time = "2026-01-14T23:15:15.647Z" }, + { url = "https://files.pythonhosted.org/packages/b2/87/b0cda79f22b8dee05f774922a214da109f9a4c0eca5da2c9d72d77ea062c/regex-2026.1.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4c5ef43b5c2d4114eb8ea424bb8c9cec01d5d17f242af88b2448f5ee81caadbc", size = 288895, upload_time = "2026-01-14T23:15:17.788Z" }, + { url = "https://files.pythonhosted.org/packages/3b/6a/0041f0a2170d32be01ab981d6346c83a8934277d82c780d60b127331f264/regex-2026.1.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:968c14d4f03e10b2fd960f1d5168c1f0ac969381d3c1fcc973bc45fb06346599", size = 798680, upload_time = "2026-01-14T23:15:19.342Z" }, + { url = "https://files.pythonhosted.org/packages/58/de/30e1cfcdbe3e891324aa7568b7c968771f82190df5524fabc1138cb2d45a/regex-2026.1.15-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56a5595d0f892f214609c9f76b41b7428bed439d98dc961efafdd1354d42baae", size = 864210, upload_time = "2026-01-14T23:15:22.005Z" }, + { url = "https://files.pythonhosted.org/packages/64/44/4db2f5c5ca0ccd40ff052ae7b1e9731352fcdad946c2b812285a7505ca75/regex-2026.1.15-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf650f26087363434c4e560011f8e4e738f6f3e029b85d4904c50135b86cfa5", size = 912358, upload_time = "2026-01-14T23:15:24.569Z" }, + { url = "https://files.pythonhosted.org/packages/79/b6/e6a5665d43a7c42467138c8a2549be432bad22cbd206f5ec87162de74bd7/regex-2026.1.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18388a62989c72ac24de75f1449d0fb0b04dfccd0a1a7c1c43af5eb503d890f6", size = 803583, upload_time = "2026-01-14T23:15:26.526Z" }, + { url = "https://files.pythonhosted.org/packages/e7/53/7cd478222169d85d74d7437e74750005e993f52f335f7c04ff7adfda3310/regex-2026.1.15-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d220a2517f5893f55daac983bfa9fe998a7dbcaee4f5d27a88500f8b7873788", size = 775782, upload_time = "2026-01-14T23:15:29.352Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b5/75f9a9ee4b03a7c009fe60500fe550b45df94f0955ca29af16333ef557c5/regex-2026.1.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9c08c2fbc6120e70abff5d7f28ffb4d969e14294fb2143b4b5c7d20e46d1714", size = 787978, upload_time = "2026-01-14T23:15:31.295Z" }, + { url = "https://files.pythonhosted.org/packages/72/b3/79821c826245bbe9ccbb54f6eadb7879c722fd3e0248c17bfc90bf54e123/regex-2026.1.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7ef7d5d4bd49ec7364315167a4134a015f61e8266c6d446fc116a9ac4456e10d", size = 858550, upload_time = "2026-01-14T23:15:33.558Z" }, + { url = "https://files.pythonhosted.org/packages/4a/85/2ab5f77a1c465745bfbfcb3ad63178a58337ae8d5274315e2cc623a822fa/regex-2026.1.15-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e42844ad64194fa08d5ccb75fe6a459b9b08e6d7296bd704460168d58a388f3", size = 763747, upload_time = "2026-01-14T23:15:35.206Z" }, + { url = "https://files.pythonhosted.org/packages/6d/84/c27df502d4bfe2873a3e3a7cf1bdb2b9cc10284d1a44797cf38bed790470/regex-2026.1.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cfecdaa4b19f9ca534746eb3b55a5195d5c95b88cac32a205e981ec0a22b7d31", size = 850615, upload_time = "2026-01-14T23:15:37.523Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b7/658a9782fb253680aa8ecb5ccbb51f69e088ed48142c46d9f0c99b46c575/regex-2026.1.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:08df9722d9b87834a3d701f3fca570b2be115654dbfd30179f30ab2f39d606d3", size = 789951, upload_time = "2026-01-14T23:15:39.582Z" }, + { url = "https://files.pythonhosted.org/packages/fc/2a/5928af114441e059f15b2f63e188bd00c6529b3051c974ade7444b85fcda/regex-2026.1.15-cp313-cp313-win32.whl", hash = "sha256:d426616dae0967ca225ab12c22274eb816558f2f99ccb4a1d52ca92e8baf180f", size = 266275, upload_time = "2026-01-14T23:15:42.108Z" }, + { url = "https://files.pythonhosted.org/packages/4f/16/5bfbb89e435897bff28cf0352a992ca719d9e55ebf8b629203c96b6ce4f7/regex-2026.1.15-cp313-cp313-win_amd64.whl", hash = "sha256:febd38857b09867d3ed3f4f1af7d241c5c50362e25ef43034995b77a50df494e", size = 277145, upload_time = "2026-01-14T23:15:44.244Z" }, + { url = "https://files.pythonhosted.org/packages/56/c1/a09ff7392ef4233296e821aec5f78c51be5e91ffde0d163059e50fd75835/regex-2026.1.15-cp313-cp313-win_arm64.whl", hash = "sha256:8e32f7896f83774f91499d239e24cebfadbc07639c1494bb7213983842348337", size = 270411, upload_time = "2026-01-14T23:15:45.858Z" }, + { url = "https://files.pythonhosted.org/packages/3c/38/0cfd5a78e5c6db00e6782fdae70458f89850ce95baa5e8694ab91d89744f/regex-2026.1.15-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ec94c04149b6a7b8120f9f44565722c7ae31b7a6d2275569d2eefa76b83da3be", size = 492068, upload_time = "2026-01-14T23:15:47.616Z" }, + { url = "https://files.pythonhosted.org/packages/50/72/6c86acff16cb7c959c4355826bbf06aad670682d07c8f3998d9ef4fee7cd/regex-2026.1.15-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40c86d8046915bb9aeb15d3f3f15b6fd500b8ea4485b30e1bbc799dab3fe29f8", size = 292756, upload_time = "2026-01-14T23:15:49.307Z" }, + { url = "https://files.pythonhosted.org/packages/4e/58/df7fb69eadfe76526ddfce28abdc0af09ffe65f20c2c90932e89d705153f/regex-2026.1.15-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:726ea4e727aba21643205edad8f2187ec682d3305d790f73b7a51c7587b64bdd", size = 291114, upload_time = "2026-01-14T23:15:51.484Z" }, + { url = "https://files.pythonhosted.org/packages/ed/6c/a4011cd1cf96b90d2cdc7e156f91efbd26531e822a7fbb82a43c1016678e/regex-2026.1.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cb740d044aff31898804e7bf1181cc72c03d11dfd19932b9911ffc19a79070a", size = 807524, upload_time = "2026-01-14T23:15:53.102Z" }, + { url = "https://files.pythonhosted.org/packages/1d/25/a53ffb73183f69c3e9f4355c4922b76d2840aee160af6af5fac229b6201d/regex-2026.1.15-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05d75a668e9ea16f832390d22131fe1e8acc8389a694c8febc3e340b0f810b93", size = 873455, upload_time = "2026-01-14T23:15:54.956Z" }, + { url = "https://files.pythonhosted.org/packages/66/0b/8b47fc2e8f97d9b4a851736f3890a5f786443aa8901061c55f24c955f45b/regex-2026.1.15-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d991483606f3dbec93287b9f35596f41aa2e92b7c2ebbb935b63f409e243c9af", size = 915007, upload_time = "2026-01-14T23:15:57.041Z" }, + { url = "https://files.pythonhosted.org/packages/c2/fa/97de0d681e6d26fabe71968dbee06dd52819e9a22fdce5dac7256c31ed84/regex-2026.1.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:194312a14819d3e44628a44ed6fea6898fdbecb0550089d84c403475138d0a09", size = 812794, upload_time = "2026-01-14T23:15:58.916Z" }, + { url = "https://files.pythonhosted.org/packages/22/38/e752f94e860d429654aa2b1c51880bff8dfe8f084268258adf9151cf1f53/regex-2026.1.15-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe2fda4110a3d0bc163c2e0664be44657431440722c5c5315c65155cab92f9e5", size = 781159, upload_time = "2026-01-14T23:16:00.817Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a7/d739ffaef33c378fc888302a018d7f81080393d96c476b058b8c64fd2b0d/regex-2026.1.15-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:124dc36c85d34ef2d9164da41a53c1c8c122cfb1f6e1ec377a1f27ee81deb794", size = 795558, upload_time = "2026-01-14T23:16:03.267Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c4/542876f9a0ac576100fc73e9c75b779f5c31e3527576cfc9cb3009dcc58a/regex-2026.1.15-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1774cd1981cd212506a23a14dba7fdeaee259f5deba2df6229966d9911e767a", size = 868427, upload_time = "2026-01-14T23:16:05.646Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0f/d5655bea5b22069e32ae85a947aa564912f23758e112cdb74212848a1a1b/regex-2026.1.15-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b5f7d8d2867152cdb625e72a530d2ccb48a3d199159144cbdd63870882fb6f80", size = 769939, upload_time = "2026-01-14T23:16:07.542Z" }, + { url = "https://files.pythonhosted.org/packages/20/06/7e18a4fa9d326daeda46d471a44ef94201c46eaa26dbbb780b5d92cbfdda/regex-2026.1.15-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:492534a0ab925d1db998defc3c302dae3616a2fc3fe2e08db1472348f096ddf2", size = 854753, upload_time = "2026-01-14T23:16:10.395Z" }, + { url = "https://files.pythonhosted.org/packages/3b/67/dc8946ef3965e166f558ef3b47f492bc364e96a265eb4a2bb3ca765c8e46/regex-2026.1.15-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c661fc820cfb33e166bf2450d3dadbda47c8d8981898adb9b6fe24e5e582ba60", size = 799559, upload_time = "2026-01-14T23:16:12.347Z" }, + { url = "https://files.pythonhosted.org/packages/a5/61/1bba81ff6d50c86c65d9fd84ce9699dd106438ee4cdb105bf60374ee8412/regex-2026.1.15-cp313-cp313t-win32.whl", hash = "sha256:99ad739c3686085e614bf77a508e26954ff1b8f14da0e3765ff7abbf7799f952", size = 268879, upload_time = "2026-01-14T23:16:14.049Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/cef7d4c5fb0ea3ac5c775fd37db5747f7378b29526cc83f572198924ff47/regex-2026.1.15-cp313-cp313t-win_amd64.whl", hash = "sha256:32655d17905e7ff8ba5c764c43cb124e34a9245e45b83c22e81041e1071aee10", size = 280317, upload_time = "2026-01-14T23:16:15.718Z" }, + { url = "https://files.pythonhosted.org/packages/b4/52/4317f7a5988544e34ab57b4bde0f04944c4786128c933fb09825924d3e82/regex-2026.1.15-cp313-cp313t-win_arm64.whl", hash = "sha256:b2a13dd6a95e95a489ca242319d18fc02e07ceb28fa9ad146385194d95b3c829", size = 271551, upload_time = "2026-01-14T23:16:17.533Z" }, + { url = "https://files.pythonhosted.org/packages/52/0a/47fa888ec7cbbc7d62c5f2a6a888878e76169170ead271a35239edd8f0e8/regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac", size = 489170, upload_time = "2026-01-14T23:16:19.835Z" }, + { url = "https://files.pythonhosted.org/packages/ac/c4/d000e9b7296c15737c9301708e9e7fbdea009f8e93541b6b43bdb8219646/regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6", size = 291146, upload_time = "2026-01-14T23:16:21.541Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b6/921cc61982e538682bdf3bdf5b2c6ab6b34368da1f8e98a6c1ddc503c9cf/regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2", size = 288986, upload_time = "2026-01-14T23:16:23.381Z" }, + { url = "https://files.pythonhosted.org/packages/ca/33/eb7383dde0bbc93f4fb9d03453aab97e18ad4024ac7e26cef8d1f0a2cff0/regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846", size = 799098, upload_time = "2026-01-14T23:16:25.088Z" }, + { url = "https://files.pythonhosted.org/packages/27/56/b664dccae898fc8d8b4c23accd853f723bde0f026c747b6f6262b688029c/regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b", size = 864980, upload_time = "2026-01-14T23:16:27.297Z" }, + { url = "https://files.pythonhosted.org/packages/16/40/0999e064a170eddd237bae9ccfcd8f28b3aa98a38bf727a086425542a4fc/regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e", size = 911607, upload_time = "2026-01-14T23:16:29.235Z" }, + { url = "https://files.pythonhosted.org/packages/07/78/c77f644b68ab054e5a674fb4da40ff7bffb2c88df58afa82dbf86573092d/regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde", size = 803358, upload_time = "2026-01-14T23:16:31.369Z" }, + { url = "https://files.pythonhosted.org/packages/27/31/d4292ea8566eaa551fafc07797961c5963cf5235c797cc2ae19b85dfd04d/regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5", size = 775833, upload_time = "2026-01-14T23:16:33.141Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b2/cff3bf2fea4133aa6fb0d1e370b37544d18c8350a2fa118c7e11d1db0e14/regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34", size = 788045, upload_time = "2026-01-14T23:16:35.005Z" }, + { url = "https://files.pythonhosted.org/packages/8d/99/2cb9b69045372ec877b6f5124bda4eb4253bc58b8fe5848c973f752bc52c/regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75", size = 859374, upload_time = "2026-01-14T23:16:36.919Z" }, + { url = "https://files.pythonhosted.org/packages/09/16/710b0a5abe8e077b1729a562d2f297224ad079f3a66dce46844c193416c8/regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e", size = 763940, upload_time = "2026-01-14T23:16:38.685Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d1/7585c8e744e40eb3d32f119191969b91de04c073fca98ec14299041f6e7e/regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160", size = 850112, upload_time = "2026-01-14T23:16:40.646Z" }, + { url = "https://files.pythonhosted.org/packages/af/d6/43e1dd85df86c49a347aa57c1f69d12c652c7b60e37ec162e3096194a278/regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1", size = 789586, upload_time = "2026-01-14T23:16:42.799Z" }, + { url = "https://files.pythonhosted.org/packages/93/38/77142422f631e013f316aaae83234c629555729a9fbc952b8a63ac91462a/regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1", size = 271691, upload_time = "2026-01-14T23:16:44.671Z" }, + { url = "https://files.pythonhosted.org/packages/4a/a9/ab16b4649524ca9e05213c1cdbb7faa85cc2aa90a0230d2f796cbaf22736/regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903", size = 280422, upload_time = "2026-01-14T23:16:46.607Z" }, + { url = "https://files.pythonhosted.org/packages/be/2a/20fd057bf3521cb4791f69f869635f73e0aaf2b9ad2d260f728144f9047c/regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705", size = 273467, upload_time = "2026-01-14T23:16:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/ad/77/0b1e81857060b92b9cad239104c46507dd481b3ff1fa79f8e7f865aae38a/regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8", size = 492073, upload_time = "2026-01-14T23:16:51.154Z" }, + { url = "https://files.pythonhosted.org/packages/70/f3/f8302b0c208b22c1e4f423147e1913fd475ddd6230565b299925353de644/regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf", size = 292757, upload_time = "2026-01-14T23:16:53.08Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f0/ef55de2460f3b4a6da9d9e7daacd0cb79d4ef75c64a2af316e68447f0df0/regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d", size = 291122, upload_time = "2026-01-14T23:16:55.383Z" }, + { url = "https://files.pythonhosted.org/packages/cf/55/bb8ccbacabbc3a11d863ee62a9f18b160a83084ea95cdfc5d207bfc3dd75/regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84", size = 807761, upload_time = "2026-01-14T23:16:57.251Z" }, + { url = "https://files.pythonhosted.org/packages/8f/84/f75d937f17f81e55679a0509e86176e29caa7298c38bd1db7ce9c0bf6075/regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df", size = 873538, upload_time = "2026-01-14T23:16:59.349Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d9/0da86327df70349aa8d86390da91171bd3ca4f0e7c1d1d453a9c10344da3/regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434", size = 915066, upload_time = "2026-01-14T23:17:01.607Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5e/f660fb23fc77baa2a61aa1f1fe3a4eea2bbb8a286ddec148030672e18834/regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a", size = 812938, upload_time = "2026-01-14T23:17:04.366Z" }, + { url = "https://files.pythonhosted.org/packages/69/33/a47a29bfecebbbfd1e5cd3f26b28020a97e4820f1c5148e66e3b7d4b4992/regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10", size = 781314, upload_time = "2026-01-14T23:17:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/65/ec/7ec2bbfd4c3f4e494a24dec4c6943a668e2030426b1b8b949a6462d2c17b/regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac", size = 795652, upload_time = "2026-01-14T23:17:08.521Z" }, + { url = "https://files.pythonhosted.org/packages/46/79/a5d8651ae131fe27d7c521ad300aa7f1c7be1dbeee4d446498af5411b8a9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea", size = 868550, upload_time = "2026-01-14T23:17:10.573Z" }, + { url = "https://files.pythonhosted.org/packages/06/b7/25635d2809664b79f183070786a5552dd4e627e5aedb0065f4e3cf8ee37d/regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e", size = 769981, upload_time = "2026-01-14T23:17:12.871Z" }, + { url = "https://files.pythonhosted.org/packages/16/8b/fc3fcbb2393dcfa4a6c5ffad92dc498e842df4581ea9d14309fcd3c55fb9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521", size = 854780, upload_time = "2026-01-14T23:17:14.837Z" }, + { url = "https://files.pythonhosted.org/packages/d0/38/dde117c76c624713c8a2842530be9c93ca8b606c0f6102d86e8cd1ce8bea/regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db", size = 799778, upload_time = "2026-01-14T23:17:17.369Z" }, + { url = "https://files.pythonhosted.org/packages/e3/0d/3a6cfa9ae99606afb612d8fb7a66b245a9d5ff0f29bb347c8a30b6ad561b/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e", size = 274667, upload_time = "2026-01-14T23:17:19.301Z" }, + { url = "https://files.pythonhosted.org/packages/5b/b2/297293bb0742fd06b8d8e2572db41a855cdf1cae0bf009b1cb74fe07e196/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf", size = 284386, upload_time = "2026-01-14T23:17:21.231Z" }, + { url = "https://files.pythonhosted.org/packages/95/e4/a3b9480c78cf8ee86626cb06f8d931d74d775897d44201ccb813097ae697/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70", size = 274837, upload_time = "2026-01-14T23:17:23.146Z" }, ] [[package]] @@ -2480,9 +2491,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload_time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload_time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -2493,9 +2504,9 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload-time = "2026-02-01T16:20:47.908Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload_time = "2026-02-01T16:20:47.908Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963, upload-time = "2026-02-01T16:20:46.078Z" }, + { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963, upload_time = "2026-02-01T16:20:46.078Z" }, ] [[package]] @@ -2529,66 +2540,66 @@ requires-dist = [ name = "rpds-py" version = "0.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" }, - { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" }, - { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" }, - { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" }, - { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" }, - { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" }, - { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" }, - { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" }, - { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" }, - { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" }, - { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" }, - { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" }, - { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" }, - { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" }, - { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" }, - { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" }, - { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" }, - { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" }, - { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" }, - { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" }, - { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" }, - { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" }, - { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" }, - { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" }, - { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, - { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, - { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" }, - { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" }, - { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" }, - { url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload-time = "2025-11-30T20:23:32.209Z" }, - { url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload-time = "2025-11-30T20:23:33.742Z" }, - { url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload-time = "2025-11-30T20:23:35.253Z" }, - { url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload-time = "2025-11-30T20:23:36.842Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload-time = "2025-11-30T20:23:38.343Z" }, - { url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload-time = "2025-11-30T20:23:40.263Z" }, - { url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload-time = "2025-11-30T20:23:42.186Z" }, - { url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload-time = "2025-11-30T20:23:44.086Z" }, - { url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload-time = "2025-11-30T20:23:46.004Z" }, - { url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload-time = "2025-11-30T20:23:47.696Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload-time = "2025-11-30T20:23:49.501Z" }, - { url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload-time = "2025-11-30T20:23:50.96Z" }, - { url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload-time = "2025-11-30T20:23:52.494Z" }, - { url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload-time = "2025-11-30T20:23:54.036Z" }, - { url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload-time = "2025-11-30T20:23:55.556Z" }, - { url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload-time = "2025-11-30T20:23:57.033Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload-time = "2025-11-30T20:23:58.637Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload-time = "2025-11-30T20:24:00.2Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload-time = "2025-11-30T20:24:01.759Z" }, - { url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload-time = "2025-11-30T20:24:03.687Z" }, - { url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload-time = "2025-11-30T20:24:05.232Z" }, - { url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload-time = "2025-11-30T20:24:06.878Z" }, - { url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload-time = "2025-11-30T20:24:08.445Z" }, - { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" }, - { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" }, - { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload_time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload_time = "2025-11-30T20:22:41.812Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload_time = "2025-11-30T20:22:43.479Z" }, + { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload_time = "2025-11-30T20:22:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload_time = "2025-11-30T20:22:46.103Z" }, + { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload_time = "2025-11-30T20:22:47.458Z" }, + { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload_time = "2025-11-30T20:22:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload_time = "2025-11-30T20:22:50.196Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload_time = "2025-11-30T20:22:51.87Z" }, + { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload_time = "2025-11-30T20:22:53.341Z" }, + { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload_time = "2025-11-30T20:22:54.778Z" }, + { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload_time = "2025-11-30T20:22:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload_time = "2025-11-30T20:22:58.2Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload_time = "2025-11-30T20:23:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload_time = "2025-11-30T20:23:02.008Z" }, + { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload_time = "2025-11-30T20:23:03.43Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload_time = "2025-11-30T20:23:04.878Z" }, + { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload_time = "2025-11-30T20:23:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload_time = "2025-11-30T20:23:07.825Z" }, + { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload_time = "2025-11-30T20:23:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload_time = "2025-11-30T20:23:11.186Z" }, + { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload_time = "2025-11-30T20:23:12.864Z" }, + { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload_time = "2025-11-30T20:23:14.638Z" }, + { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload_time = "2025-11-30T20:23:16.105Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload_time = "2025-11-30T20:23:17.539Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload_time = "2025-11-30T20:23:19.029Z" }, + { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload_time = "2025-11-30T20:23:20.885Z" }, + { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload_time = "2025-11-30T20:23:22.488Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload_time = "2025-11-30T20:23:24.449Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload_time = "2025-11-30T20:23:25.908Z" }, + { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload_time = "2025-11-30T20:23:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload_time = "2025-11-30T20:23:29.151Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload_time = "2025-11-30T20:23:30.785Z" }, + { url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload_time = "2025-11-30T20:23:32.209Z" }, + { url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload_time = "2025-11-30T20:23:33.742Z" }, + { url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload_time = "2025-11-30T20:23:35.253Z" }, + { url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload_time = "2025-11-30T20:23:36.842Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload_time = "2025-11-30T20:23:38.343Z" }, + { url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload_time = "2025-11-30T20:23:40.263Z" }, + { url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload_time = "2025-11-30T20:23:42.186Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload_time = "2025-11-30T20:23:44.086Z" }, + { url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload_time = "2025-11-30T20:23:46.004Z" }, + { url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload_time = "2025-11-30T20:23:47.696Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload_time = "2025-11-30T20:23:49.501Z" }, + { url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload_time = "2025-11-30T20:23:50.96Z" }, + { url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload_time = "2025-11-30T20:23:52.494Z" }, + { url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload_time = "2025-11-30T20:23:54.036Z" }, + { url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload_time = "2025-11-30T20:23:55.556Z" }, + { url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload_time = "2025-11-30T20:23:57.033Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload_time = "2025-11-30T20:23:58.637Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload_time = "2025-11-30T20:24:00.2Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload_time = "2025-11-30T20:24:01.759Z" }, + { url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload_time = "2025-11-30T20:24:03.687Z" }, + { url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload_time = "2025-11-30T20:24:05.232Z" }, + { url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload_time = "2025-11-30T20:24:06.878Z" }, + { url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload_time = "2025-11-30T20:24:08.445Z" }, + { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload_time = "2025-11-30T20:24:10.956Z" }, + { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload_time = "2025-11-30T20:24:12.735Z" }, + { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload_time = "2025-11-30T20:24:14.634Z" }, ] [[package]] @@ -2598,36 +2609,36 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload_time = "2025-04-16T09:51:18.218Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload_time = "2025-04-16T09:51:17.142Z" }, ] [[package]] name = "shellingham" version = "1.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload_time = "2023-10-24T04:13:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload_time = "2023-10-24T04:13:38.866Z" }, ] [[package]] name = "six" version = "1.17.0" 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" } +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" }, + { 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" }, ] [[package]] name = "sniffio" version = "1.3.1" 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" } +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" }, + { 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" }, ] [[package]] @@ -2638,31 +2649,31 @@ dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393, upload-time = "2026-01-21T18:03:45.119Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/4b/fa7838fe20bb752810feed60e45625a9a8b0102c0c09971e2d1d95362992/sqlalchemy-2.0.46-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a12da97cca70cea10d4b4fc602589c4511f96c1f8f6c11817620c021d21d00", size = 2150268, upload-time = "2026-01-21T19:05:56.621Z" }, - { url = "https://files.pythonhosted.org/packages/46/c1/b34dccd712e8ea846edf396e00973dda82d598cb93762e55e43e6835eba9/sqlalchemy-2.0.46-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af865c18752d416798dae13f83f38927c52f085c52e2f32b8ab0fef46fdd02c2", size = 3276511, upload-time = "2026-01-21T18:46:49.022Z" }, - { url = "https://files.pythonhosted.org/packages/96/48/a04d9c94753e5d5d096c628c82a98c4793b9c08ca0e7155c3eb7d7db9f24/sqlalchemy-2.0.46-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8d679b5f318423eacb61f933a9a0f75535bfca7056daeadbf6bd5bcee6183aee", size = 3292881, upload-time = "2026-01-21T18:40:13.089Z" }, - { url = "https://files.pythonhosted.org/packages/be/f4/06eda6e91476f90a7d8058f74311cb65a2fb68d988171aced81707189131/sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64901e08c33462acc9ec3bad27fc7a5c2b6491665f2aa57564e57a4f5d7c52ad", size = 3224559, upload-time = "2026-01-21T18:46:50.974Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a2/d2af04095412ca6345ac22b33b89fe8d6f32a481e613ffcb2377d931d8d0/sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8ac45e8f4eaac0f9f8043ea0e224158855c6a4329fd4ee37c45c61e3beb518e", size = 3262728, upload-time = "2026-01-21T18:40:14.883Z" }, - { url = "https://files.pythonhosted.org/packages/31/48/1980c7caa5978a3b8225b4d230e69a2a6538a3562b8b31cea679b6933c83/sqlalchemy-2.0.46-cp313-cp313-win32.whl", hash = "sha256:8d3b44b3d0ab2f1319d71d9863d76eeb46766f8cf9e921ac293511804d39813f", size = 2111295, upload-time = "2026-01-21T18:42:52.366Z" }, - { url = "https://files.pythonhosted.org/packages/2d/54/f8d65bbde3d877617c4720f3c9f60e99bb7266df0d5d78b6e25e7c149f35/sqlalchemy-2.0.46-cp313-cp313-win_amd64.whl", hash = "sha256:77f8071d8fbcbb2dd11b7fd40dedd04e8ebe2eb80497916efedba844298065ef", size = 2137076, upload-time = "2026-01-21T18:42:53.924Z" }, - { url = "https://files.pythonhosted.org/packages/56/ba/9be4f97c7eb2b9d5544f2624adfc2853e796ed51d2bb8aec90bc94b7137e/sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1e8cc6cc01da346dc92d9509a63033b9b1bda4fed7a7a7807ed385c7dccdc10", size = 3556533, upload-time = "2026-01-21T18:33:06.636Z" }, - { url = "https://files.pythonhosted.org/packages/20/a6/b1fc6634564dbb4415b7ed6419cdfeaadefd2c39cdab1e3aa07a5f2474c2/sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96c7cca1a4babaaf3bfff3e4e606e38578856917e52f0384635a95b226c87764", size = 3523208, upload-time = "2026-01-21T18:45:08.436Z" }, - { url = "https://files.pythonhosted.org/packages/a1/d8/41e0bdfc0f930ff236f86fccd12962d8fa03713f17ed57332d38af6a3782/sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b2a9f9aee38039cf4755891a1e50e1effcc42ea6ba053743f452c372c3152b1b", size = 3464292, upload-time = "2026-01-21T18:33:08.208Z" }, - { url = "https://files.pythonhosted.org/packages/f0/8b/9dcbec62d95bea85f5ecad9b8d65b78cc30fb0ffceeb3597961f3712549b/sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:db23b1bf8cfe1f7fda19018e7207b20cdb5168f83c437ff7e95d19e39289c447", size = 3473497, upload-time = "2026-01-21T18:45:10.552Z" }, - { url = "https://files.pythonhosted.org/packages/e9/f8/5ecdfc73383ec496de038ed1614de9e740a82db9ad67e6e4514ebc0708a3/sqlalchemy-2.0.46-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:56bdd261bfd0895452006d5316cbf35739c53b9bb71a170a331fa0ea560b2ada", size = 2152079, upload-time = "2026-01-21T19:05:58.477Z" }, - { url = "https://files.pythonhosted.org/packages/e5/bf/eba3036be7663ce4d9c050bc3d63794dc29fbe01691f2bf5ccb64e048d20/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33e462154edb9493f6c3ad2125931e273bbd0be8ae53f3ecd1c161ea9a1dd366", size = 3272216, upload-time = "2026-01-21T18:46:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/05/45/1256fb597bb83b58a01ddb600c59fe6fdf0e5afe333f0456ed75c0f8d7bd/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcdce05f056622a632f1d44bb47dbdb677f58cad393612280406ce37530eb6d", size = 3277208, upload-time = "2026-01-21T18:40:16.38Z" }, - { url = "https://files.pythonhosted.org/packages/d9/a0/2053b39e4e63b5d7ceb3372cface0859a067c1ddbd575ea7e9985716f771/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e84b09a9b0f19accedcbeff5c2caf36e0dd537341a33aad8d680336152dc34e", size = 3221994, upload-time = "2026-01-21T18:46:54.622Z" }, - { url = "https://files.pythonhosted.org/packages/1e/87/97713497d9502553c68f105a1cb62786ba1ee91dea3852ae4067ed956a50/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4f52f7291a92381e9b4de9050b0a65ce5d6a763333406861e33906b8aa4906bf", size = 3243990, upload-time = "2026-01-21T18:40:18.253Z" }, - { url = "https://files.pythonhosted.org/packages/a8/87/5d1b23548f420ff823c236f8bea36b1a997250fd2f892e44a3838ca424f4/sqlalchemy-2.0.46-cp314-cp314-win32.whl", hash = "sha256:70ed2830b169a9960193f4d4322d22be5c0925357d82cbf485b3369893350908", size = 2114215, upload-time = "2026-01-21T18:42:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/3a/20/555f39cbcf0c10cf452988b6a93c2a12495035f68b3dbd1a408531049d31/sqlalchemy-2.0.46-cp314-cp314-win_amd64.whl", hash = "sha256:3c32e993bc57be6d177f7d5d31edb93f30726d798ad86ff9066d75d9bf2e0b6b", size = 2139867, upload-time = "2026-01-21T18:42:56.474Z" }, - { url = "https://files.pythonhosted.org/packages/3e/f0/f96c8057c982d9d8a7a68f45d69c674bc6f78cad401099692fe16521640a/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4dafb537740eef640c4d6a7c254611dca2df87eaf6d14d6a5fca9d1f4c3fc0fa", size = 3561202, upload-time = "2026-01-21T18:33:10.337Z" }, - { url = "https://files.pythonhosted.org/packages/d7/53/3b37dda0a5b137f21ef608d8dfc77b08477bab0fe2ac9d3e0a66eaeab6fc/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42a1643dc5427b69aca967dae540a90b0fbf57eaf248f13a90ea5930e0966863", size = 3526296, upload-time = "2026-01-21T18:45:12.657Z" }, - { url = "https://files.pythonhosted.org/packages/33/75/f28622ba6dde79cd545055ea7bd4062dc934e0621f7b3be2891f8563f8de/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff33c6e6ad006bbc0f34f5faf941cfc62c45841c64c0a058ac38c799f15b5ede", size = 3470008, upload-time = "2026-01-21T18:33:11.725Z" }, - { url = "https://files.pythonhosted.org/packages/a9/42/4afecbbc38d5e99b18acef446453c76eec6fbd03db0a457a12a056836e22/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82ec52100ec1e6ec671563bbd02d7c7c8d0b9e71a0723c72f22ecf52d1755330", size = 3476137, upload-time = "2026-01-21T18:45:15.001Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882, upload-time = "2026-01-21T18:22:10.456Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393, upload_time = "2026-01-21T18:03:45.119Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/4b/fa7838fe20bb752810feed60e45625a9a8b0102c0c09971e2d1d95362992/sqlalchemy-2.0.46-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a12da97cca70cea10d4b4fc602589c4511f96c1f8f6c11817620c021d21d00", size = 2150268, upload_time = "2026-01-21T19:05:56.621Z" }, + { url = "https://files.pythonhosted.org/packages/46/c1/b34dccd712e8ea846edf396e00973dda82d598cb93762e55e43e6835eba9/sqlalchemy-2.0.46-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af865c18752d416798dae13f83f38927c52f085c52e2f32b8ab0fef46fdd02c2", size = 3276511, upload_time = "2026-01-21T18:46:49.022Z" }, + { url = "https://files.pythonhosted.org/packages/96/48/a04d9c94753e5d5d096c628c82a98c4793b9c08ca0e7155c3eb7d7db9f24/sqlalchemy-2.0.46-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8d679b5f318423eacb61f933a9a0f75535bfca7056daeadbf6bd5bcee6183aee", size = 3292881, upload_time = "2026-01-21T18:40:13.089Z" }, + { url = "https://files.pythonhosted.org/packages/be/f4/06eda6e91476f90a7d8058f74311cb65a2fb68d988171aced81707189131/sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64901e08c33462acc9ec3bad27fc7a5c2b6491665f2aa57564e57a4f5d7c52ad", size = 3224559, upload_time = "2026-01-21T18:46:50.974Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a2/d2af04095412ca6345ac22b33b89fe8d6f32a481e613ffcb2377d931d8d0/sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8ac45e8f4eaac0f9f8043ea0e224158855c6a4329fd4ee37c45c61e3beb518e", size = 3262728, upload_time = "2026-01-21T18:40:14.883Z" }, + { url = "https://files.pythonhosted.org/packages/31/48/1980c7caa5978a3b8225b4d230e69a2a6538a3562b8b31cea679b6933c83/sqlalchemy-2.0.46-cp313-cp313-win32.whl", hash = "sha256:8d3b44b3d0ab2f1319d71d9863d76eeb46766f8cf9e921ac293511804d39813f", size = 2111295, upload_time = "2026-01-21T18:42:52.366Z" }, + { url = "https://files.pythonhosted.org/packages/2d/54/f8d65bbde3d877617c4720f3c9f60e99bb7266df0d5d78b6e25e7c149f35/sqlalchemy-2.0.46-cp313-cp313-win_amd64.whl", hash = "sha256:77f8071d8fbcbb2dd11b7fd40dedd04e8ebe2eb80497916efedba844298065ef", size = 2137076, upload_time = "2026-01-21T18:42:53.924Z" }, + { url = "https://files.pythonhosted.org/packages/56/ba/9be4f97c7eb2b9d5544f2624adfc2853e796ed51d2bb8aec90bc94b7137e/sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1e8cc6cc01da346dc92d9509a63033b9b1bda4fed7a7a7807ed385c7dccdc10", size = 3556533, upload_time = "2026-01-21T18:33:06.636Z" }, + { url = "https://files.pythonhosted.org/packages/20/a6/b1fc6634564dbb4415b7ed6419cdfeaadefd2c39cdab1e3aa07a5f2474c2/sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96c7cca1a4babaaf3bfff3e4e606e38578856917e52f0384635a95b226c87764", size = 3523208, upload_time = "2026-01-21T18:45:08.436Z" }, + { url = "https://files.pythonhosted.org/packages/a1/d8/41e0bdfc0f930ff236f86fccd12962d8fa03713f17ed57332d38af6a3782/sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b2a9f9aee38039cf4755891a1e50e1effcc42ea6ba053743f452c372c3152b1b", size = 3464292, upload_time = "2026-01-21T18:33:08.208Z" }, + { url = "https://files.pythonhosted.org/packages/f0/8b/9dcbec62d95bea85f5ecad9b8d65b78cc30fb0ffceeb3597961f3712549b/sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:db23b1bf8cfe1f7fda19018e7207b20cdb5168f83c437ff7e95d19e39289c447", size = 3473497, upload_time = "2026-01-21T18:45:10.552Z" }, + { url = "https://files.pythonhosted.org/packages/e9/f8/5ecdfc73383ec496de038ed1614de9e740a82db9ad67e6e4514ebc0708a3/sqlalchemy-2.0.46-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:56bdd261bfd0895452006d5316cbf35739c53b9bb71a170a331fa0ea560b2ada", size = 2152079, upload_time = "2026-01-21T19:05:58.477Z" }, + { url = "https://files.pythonhosted.org/packages/e5/bf/eba3036be7663ce4d9c050bc3d63794dc29fbe01691f2bf5ccb64e048d20/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33e462154edb9493f6c3ad2125931e273bbd0be8ae53f3ecd1c161ea9a1dd366", size = 3272216, upload_time = "2026-01-21T18:46:52.634Z" }, + { url = "https://files.pythonhosted.org/packages/05/45/1256fb597bb83b58a01ddb600c59fe6fdf0e5afe333f0456ed75c0f8d7bd/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcdce05f056622a632f1d44bb47dbdb677f58cad393612280406ce37530eb6d", size = 3277208, upload_time = "2026-01-21T18:40:16.38Z" }, + { url = "https://files.pythonhosted.org/packages/d9/a0/2053b39e4e63b5d7ceb3372cface0859a067c1ddbd575ea7e9985716f771/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e84b09a9b0f19accedcbeff5c2caf36e0dd537341a33aad8d680336152dc34e", size = 3221994, upload_time = "2026-01-21T18:46:54.622Z" }, + { url = "https://files.pythonhosted.org/packages/1e/87/97713497d9502553c68f105a1cb62786ba1ee91dea3852ae4067ed956a50/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4f52f7291a92381e9b4de9050b0a65ce5d6a763333406861e33906b8aa4906bf", size = 3243990, upload_time = "2026-01-21T18:40:18.253Z" }, + { url = "https://files.pythonhosted.org/packages/a8/87/5d1b23548f420ff823c236f8bea36b1a997250fd2f892e44a3838ca424f4/sqlalchemy-2.0.46-cp314-cp314-win32.whl", hash = "sha256:70ed2830b169a9960193f4d4322d22be5c0925357d82cbf485b3369893350908", size = 2114215, upload_time = "2026-01-21T18:42:55.232Z" }, + { url = "https://files.pythonhosted.org/packages/3a/20/555f39cbcf0c10cf452988b6a93c2a12495035f68b3dbd1a408531049d31/sqlalchemy-2.0.46-cp314-cp314-win_amd64.whl", hash = "sha256:3c32e993bc57be6d177f7d5d31edb93f30726d798ad86ff9066d75d9bf2e0b6b", size = 2139867, upload_time = "2026-01-21T18:42:56.474Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f0/f96c8057c982d9d8a7a68f45d69c674bc6f78cad401099692fe16521640a/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4dafb537740eef640c4d6a7c254611dca2df87eaf6d14d6a5fca9d1f4c3fc0fa", size = 3561202, upload_time = "2026-01-21T18:33:10.337Z" }, + { url = "https://files.pythonhosted.org/packages/d7/53/3b37dda0a5b137f21ef608d8dfc77b08477bab0fe2ac9d3e0a66eaeab6fc/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42a1643dc5427b69aca967dae540a90b0fbf57eaf248f13a90ea5930e0966863", size = 3526296, upload_time = "2026-01-21T18:45:12.657Z" }, + { url = "https://files.pythonhosted.org/packages/33/75/f28622ba6dde79cd545055ea7bd4062dc934e0621f7b3be2891f8563f8de/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff33c6e6ad006bbc0f34f5faf941cfc62c45841c64c0a058ac38c799f15b5ede", size = 3470008, upload_time = "2026-01-21T18:33:11.725Z" }, + { url = "https://files.pythonhosted.org/packages/a9/42/4afecbbc38d5e99b18acef446453c76eec6fbd03db0a457a12a056836e22/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82ec52100ec1e6ec671563bbd02d7c7c8d0b9e71a0723c72f22ecf52d1755330", size = 3476137, upload_time = "2026-01-21T18:45:15.001Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882, upload_time = "2026-01-21T18:22:10.456Z" }, ] [[package]] @@ -2674,18 +2685,18 @@ dependencies = [ { name = "google-cloud-spanner" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8e/29/21698bb83e542f32e3581886671f39d94b1f7e8b190c24a8bfa994e62fd6/sqlalchemy_spanner-1.17.2.tar.gz", hash = "sha256:56ce4da7168a27442d80ffd71c29ed639b5056d7e69b1e69bb9c1e10190b67c4", size = 82745, upload-time = "2025-12-15T23:30:08.622Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/29/21698bb83e542f32e3581886671f39d94b1f7e8b190c24a8bfa994e62fd6/sqlalchemy_spanner-1.17.2.tar.gz", hash = "sha256:56ce4da7168a27442d80ffd71c29ed639b5056d7e69b1e69bb9c1e10190b67c4", size = 82745, upload_time = "2025-12-15T23:30:08.622Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/87/05be45a086116cea32cfa00fa0059d31b5345360dba7902ee640a1db793b/sqlalchemy_spanner-1.17.2-py3-none-any.whl", hash = "sha256:18713d4d78e0bf048eda0f7a5c80733e08a7b678b34349496415f37652efb12f", size = 31917, upload-time = "2025-12-15T23:30:07.356Z" }, + { url = "https://files.pythonhosted.org/packages/7f/87/05be45a086116cea32cfa00fa0059d31b5345360dba7902ee640a1db793b/sqlalchemy_spanner-1.17.2-py3-none-any.whl", hash = "sha256:18713d4d78e0bf048eda0f7a5c80733e08a7b678b34349496415f37652efb12f", size = 31917, upload_time = "2025-12-15T23:30:07.356Z" }, ] [[package]] name = "sqlparse" version = "0.5.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload_time = "2025-12-19T07:17:45.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload_time = "2025-12-19T07:17:46.573Z" }, ] [[package]] @@ -2696,9 +2707,9 @@ dependencies = [ { name = "anyio" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload_time = "2026-01-17T13:11:05.62Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" }, + { url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload_time = "2026-01-17T13:11:03.775Z" }, ] [[package]] @@ -2708,18 +2719,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload_time = "2025-11-01T15:25:27.516Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload_time = "2025-11-01T15:25:25.461Z" }, ] [[package]] name = "tenacity" version = "9.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload_time = "2026-02-07T10:45:33.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload_time = "2026-02-07T10:45:32.24Z" }, ] [[package]] @@ -2730,36 +2741,36 @@ dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/61/441588ee21e6b5cdf59d6870f86beb9789e532ee9718c251b391b70c68d6/tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3", size = 1050802, upload-time = "2025-10-06T20:22:00.96Z" }, - { url = "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160", size = 993995, upload-time = "2025-10-06T20:22:02.788Z" }, - { url = "https://files.pythonhosted.org/packages/a0/70/5163fe5359b943f8db9946b62f19be2305de8c3d78a16f629d4165e2f40e/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa", size = 1128948, upload-time = "2025-10-06T20:22:03.814Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/c028aa0babf77315e1cef357d4d768800c5f8a6de04d0eac0f377cb619fa/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be", size = 1151986, upload-time = "2025-10-06T20:22:05.173Z" }, - { url = "https://files.pythonhosted.org/packages/a0/5a/886b108b766aa53e295f7216b509be95eb7d60b166049ce2c58416b25f2a/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a", size = 1194222, upload-time = "2025-10-06T20:22:06.265Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f8/4db272048397636ac7a078d22773dd2795b1becee7bc4922fe6207288d57/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3", size = 1255097, upload-time = "2025-10-06T20:22:07.403Z" }, - { url = "https://files.pythonhosted.org/packages/8e/32/45d02e2e0ea2be3a9ed22afc47d93741247e75018aac967b713b2941f8ea/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697", size = 879117, upload-time = "2025-10-06T20:22:08.418Z" }, - { url = "https://files.pythonhosted.org/packages/ce/76/994fc868f88e016e6d05b0da5ac24582a14c47893f4474c3e9744283f1d5/tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16", size = 1050309, upload-time = "2025-10-06T20:22:10.939Z" }, - { url = "https://files.pythonhosted.org/packages/f6/b8/57ef1456504c43a849821920d582a738a461b76a047f352f18c0b26c6516/tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a", size = 993712, upload-time = "2025-10-06T20:22:12.115Z" }, - { url = "https://files.pythonhosted.org/packages/72/90/13da56f664286ffbae9dbcfadcc625439142675845baa62715e49b87b68b/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27", size = 1128725, upload-time = "2025-10-06T20:22:13.541Z" }, - { url = "https://files.pythonhosted.org/packages/05/df/4f80030d44682235bdaecd7346c90f67ae87ec8f3df4a3442cb53834f7e4/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb", size = 1151875, upload-time = "2025-10-06T20:22:14.559Z" }, - { url = "https://files.pythonhosted.org/packages/22/1f/ae535223a8c4ef4c0c1192e3f9b82da660be9eb66b9279e95c99288e9dab/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e", size = 1194451, upload-time = "2025-10-06T20:22:15.545Z" }, - { url = "https://files.pythonhosted.org/packages/78/a7/f8ead382fce0243cb625c4f266e66c27f65ae65ee9e77f59ea1653b6d730/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25", size = 1253794, upload-time = "2025-10-06T20:22:16.624Z" }, - { url = "https://files.pythonhosted.org/packages/93/e0/6cc82a562bc6365785a3ff0af27a2a092d57c47d7a81d9e2295d8c36f011/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f", size = 878777, upload-time = "2025-10-06T20:22:18.036Z" }, - { url = "https://files.pythonhosted.org/packages/72/05/3abc1db5d2c9aadc4d2c76fa5640134e475e58d9fbb82b5c535dc0de9b01/tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646", size = 1050188, upload-time = "2025-10-06T20:22:19.563Z" }, - { url = "https://files.pythonhosted.org/packages/e3/7b/50c2f060412202d6c95f32b20755c7a6273543b125c0985d6fa9465105af/tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88", size = 993978, upload-time = "2025-10-06T20:22:20.702Z" }, - { url = "https://files.pythonhosted.org/packages/14/27/bf795595a2b897e271771cd31cb847d479073497344c637966bdf2853da1/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff", size = 1129271, upload-time = "2025-10-06T20:22:22.06Z" }, - { url = "https://files.pythonhosted.org/packages/f5/de/9341a6d7a8f1b448573bbf3425fa57669ac58258a667eb48a25dfe916d70/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830", size = 1151216, upload-time = "2025-10-06T20:22:23.085Z" }, - { url = "https://files.pythonhosted.org/packages/75/0d/881866647b8d1be4d67cb24e50d0c26f9f807f994aa1510cb9ba2fe5f612/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b", size = 1194860, upload-time = "2025-10-06T20:22:24.602Z" }, - { url = "https://files.pythonhosted.org/packages/b3/1e/b651ec3059474dab649b8d5b69f5c65cd8fcd8918568c1935bd4136c9392/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b", size = 1254567, upload-time = "2025-10-06T20:22:25.671Z" }, - { url = "https://files.pythonhosted.org/packages/80/57/ce64fd16ac390fafde001268c364d559447ba09b509181b2808622420eec/tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3", size = 921067, upload-time = "2025-10-06T20:22:26.753Z" }, - { url = "https://files.pythonhosted.org/packages/ac/a4/72eed53e8976a099539cdd5eb36f241987212c29629d0a52c305173e0a68/tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365", size = 1050473, upload-time = "2025-10-06T20:22:27.775Z" }, - { url = "https://files.pythonhosted.org/packages/e6/d7/0110b8f54c008466b19672c615f2168896b83706a6611ba6e47313dbc6e9/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e", size = 993855, upload-time = "2025-10-06T20:22:28.799Z" }, - { url = "https://files.pythonhosted.org/packages/5f/77/4f268c41a3957c418b084dd576ea2fad2e95da0d8e1ab705372892c2ca22/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63", size = 1129022, upload-time = "2025-10-06T20:22:29.981Z" }, - { url = "https://files.pythonhosted.org/packages/4e/2b/fc46c90fe5028bd094cd6ee25a7db321cb91d45dc87531e2bdbb26b4867a/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0", size = 1150736, upload-time = "2025-10-06T20:22:30.996Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/3c7a39ff68022ddfd7d93f3337ad90389a342f761c4d71de99a3ccc57857/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a", size = 1194908, upload-time = "2025-10-06T20:22:32.073Z" }, - { url = "https://files.pythonhosted.org/packages/ab/0d/c1ad6f4016a3968c048545f5d9b8ffebf577774b2ede3e2e352553b685fe/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0", size = 1253706, upload-time = "2025-10-06T20:22:33.385Z" }, - { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload-time = "2025-10-06T20:22:34.444Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload_time = "2025-10-06T20:22:45.419Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/61/441588ee21e6b5cdf59d6870f86beb9789e532ee9718c251b391b70c68d6/tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3", size = 1050802, upload_time = "2025-10-06T20:22:00.96Z" }, + { url = "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160", size = 993995, upload_time = "2025-10-06T20:22:02.788Z" }, + { url = "https://files.pythonhosted.org/packages/a0/70/5163fe5359b943f8db9946b62f19be2305de8c3d78a16f629d4165e2f40e/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa", size = 1128948, upload_time = "2025-10-06T20:22:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/c028aa0babf77315e1cef357d4d768800c5f8a6de04d0eac0f377cb619fa/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be", size = 1151986, upload_time = "2025-10-06T20:22:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5a/886b108b766aa53e295f7216b509be95eb7d60b166049ce2c58416b25f2a/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a", size = 1194222, upload_time = "2025-10-06T20:22:06.265Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/4db272048397636ac7a078d22773dd2795b1becee7bc4922fe6207288d57/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3", size = 1255097, upload_time = "2025-10-06T20:22:07.403Z" }, + { url = "https://files.pythonhosted.org/packages/8e/32/45d02e2e0ea2be3a9ed22afc47d93741247e75018aac967b713b2941f8ea/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697", size = 879117, upload_time = "2025-10-06T20:22:08.418Z" }, + { url = "https://files.pythonhosted.org/packages/ce/76/994fc868f88e016e6d05b0da5ac24582a14c47893f4474c3e9744283f1d5/tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16", size = 1050309, upload_time = "2025-10-06T20:22:10.939Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b8/57ef1456504c43a849821920d582a738a461b76a047f352f18c0b26c6516/tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a", size = 993712, upload_time = "2025-10-06T20:22:12.115Z" }, + { url = "https://files.pythonhosted.org/packages/72/90/13da56f664286ffbae9dbcfadcc625439142675845baa62715e49b87b68b/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27", size = 1128725, upload_time = "2025-10-06T20:22:13.541Z" }, + { url = "https://files.pythonhosted.org/packages/05/df/4f80030d44682235bdaecd7346c90f67ae87ec8f3df4a3442cb53834f7e4/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb", size = 1151875, upload_time = "2025-10-06T20:22:14.559Z" }, + { url = "https://files.pythonhosted.org/packages/22/1f/ae535223a8c4ef4c0c1192e3f9b82da660be9eb66b9279e95c99288e9dab/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e", size = 1194451, upload_time = "2025-10-06T20:22:15.545Z" }, + { url = "https://files.pythonhosted.org/packages/78/a7/f8ead382fce0243cb625c4f266e66c27f65ae65ee9e77f59ea1653b6d730/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25", size = 1253794, upload_time = "2025-10-06T20:22:16.624Z" }, + { url = "https://files.pythonhosted.org/packages/93/e0/6cc82a562bc6365785a3ff0af27a2a092d57c47d7a81d9e2295d8c36f011/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f", size = 878777, upload_time = "2025-10-06T20:22:18.036Z" }, + { url = "https://files.pythonhosted.org/packages/72/05/3abc1db5d2c9aadc4d2c76fa5640134e475e58d9fbb82b5c535dc0de9b01/tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646", size = 1050188, upload_time = "2025-10-06T20:22:19.563Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7b/50c2f060412202d6c95f32b20755c7a6273543b125c0985d6fa9465105af/tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88", size = 993978, upload_time = "2025-10-06T20:22:20.702Z" }, + { url = "https://files.pythonhosted.org/packages/14/27/bf795595a2b897e271771cd31cb847d479073497344c637966bdf2853da1/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff", size = 1129271, upload_time = "2025-10-06T20:22:22.06Z" }, + { url = "https://files.pythonhosted.org/packages/f5/de/9341a6d7a8f1b448573bbf3425fa57669ac58258a667eb48a25dfe916d70/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830", size = 1151216, upload_time = "2025-10-06T20:22:23.085Z" }, + { url = "https://files.pythonhosted.org/packages/75/0d/881866647b8d1be4d67cb24e50d0c26f9f807f994aa1510cb9ba2fe5f612/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b", size = 1194860, upload_time = "2025-10-06T20:22:24.602Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1e/b651ec3059474dab649b8d5b69f5c65cd8fcd8918568c1935bd4136c9392/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b", size = 1254567, upload_time = "2025-10-06T20:22:25.671Z" }, + { url = "https://files.pythonhosted.org/packages/80/57/ce64fd16ac390fafde001268c364d559447ba09b509181b2808622420eec/tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3", size = 921067, upload_time = "2025-10-06T20:22:26.753Z" }, + { url = "https://files.pythonhosted.org/packages/ac/a4/72eed53e8976a099539cdd5eb36f241987212c29629d0a52c305173e0a68/tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365", size = 1050473, upload_time = "2025-10-06T20:22:27.775Z" }, + { url = "https://files.pythonhosted.org/packages/e6/d7/0110b8f54c008466b19672c615f2168896b83706a6611ba6e47313dbc6e9/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e", size = 993855, upload_time = "2025-10-06T20:22:28.799Z" }, + { url = "https://files.pythonhosted.org/packages/5f/77/4f268c41a3957c418b084dd576ea2fad2e95da0d8e1ab705372892c2ca22/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63", size = 1129022, upload_time = "2025-10-06T20:22:29.981Z" }, + { url = "https://files.pythonhosted.org/packages/4e/2b/fc46c90fe5028bd094cd6ee25a7db321cb91d45dc87531e2bdbb26b4867a/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0", size = 1150736, upload_time = "2025-10-06T20:22:30.996Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/3c7a39ff68022ddfd7d93f3337ad90389a342f761c4d71de99a3ccc57857/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a", size = 1194908, upload_time = "2025-10-06T20:22:32.073Z" }, + { url = "https://files.pythonhosted.org/packages/ab/0d/c1ad6f4016a3968c048545f5d9b8ffebf577774b2ede3e2e352553b685fe/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0", size = 1253706, upload_time = "2025-10-06T20:22:33.385Z" }, + { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload_time = "2025-10-06T20:22:34.444Z" }, ] [[package]] @@ -2769,23 +2780,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload_time = "2026-01-05T10:45:15.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, - { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, - { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, - { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, - { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, - { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, - { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, - { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, - { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, - { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, - { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, - { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, - { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, - { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload_time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload_time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload_time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload_time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload_time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload_time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload_time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload_time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload_time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload_time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload_time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload_time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload_time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload_time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload_time = "2026-01-05T10:45:17.232Z" }, ] [[package]] @@ -2795,9 +2806,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload_time = "2026-02-03T17:35:53.048Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload_time = "2026-02-03T17:35:50.982Z" }, ] [[package]] @@ -2810,9 +2821,9 @@ dependencies = [ { name = "rich" }, { name = "shellingham" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7e/e6/44e073787aa57cd71c151f44855232feb0f748428fd5242d7366e3c4ae8b/typer-0.23.0.tar.gz", hash = "sha256:d8378833e47ada5d3d093fa20c4c63427cc4e27127f6b349a6c359463087d8cc", size = 120181, upload-time = "2026-02-11T15:22:18.637Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/e6/44e073787aa57cd71c151f44855232feb0f748428fd5242d7366e3c4ae8b/typer-0.23.0.tar.gz", hash = "sha256:d8378833e47ada5d3d093fa20c4c63427cc4e27127f6b349a6c359463087d8cc", size = 120181, upload_time = "2026-02-11T15:22:18.637Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/ed/d6fca788b51d0d4640c4bc82d0e85bad4b49809bca36bf4af01b4dcb66a7/typer-0.23.0-py3-none-any.whl", hash = "sha256:79f4bc262b6c37872091072a3cb7cb6d7d79ee98c0c658b4364bdcde3c42c913", size = 56668, upload-time = "2026-02-11T15:22:21.075Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ed/d6fca788b51d0d4640c4bc82d0e85bad4b49809bca36bf4af01b4dcb66a7/typer-0.23.0-py3-none-any.whl", hash = "sha256:79f4bc262b6c37872091072a3cb7cb6d7d79ee98c0c658b4364bdcde3c42c913", size = 56668, upload_time = "2026-02-11T15:22:21.075Z" }, ] [[package]] @@ -2822,18 +2833,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1f/8a/881cfd399a119db89619dc1b93d36e2fb6720ddb112bceff41203f1abd72/typer_slim-0.23.0.tar.gz", hash = "sha256:be8b60243df27cfee444c6db1b10a85f4f3e54d940574f31a996f78aa35a8254", size = 4773, upload-time = "2026-02-11T15:22:19.106Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/8a/881cfd399a119db89619dc1b93d36e2fb6720ddb112bceff41203f1abd72/typer_slim-0.23.0.tar.gz", hash = "sha256:be8b60243df27cfee444c6db1b10a85f4f3e54d940574f31a996f78aa35a8254", size = 4773, upload_time = "2026-02-11T15:22:19.106Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/3e/ba3a222c80ee070d9497ece3e1fe77253c142925dd4c90f04278aac0a9eb/typer_slim-0.23.0-py3-none-any.whl", hash = "sha256:1d693daf22d998a7b1edab8413cdcb8af07254154ce3956c1664dc11b01e2f8b", size = 3399, upload-time = "2026-02-11T15:22:17.792Z" }, + { url = "https://files.pythonhosted.org/packages/07/3e/ba3a222c80ee070d9497ece3e1fe77253c142925dd4c90f04278aac0a9eb/typer_slim-0.23.0-py3-none-any.whl", hash = "sha256:1d693daf22d998a7b1edab8413cdcb8af07254154ce3956c1664dc11b01e2f8b", size = 3399, upload_time = "2026-02-11T15:22:17.792Z" }, ] [[package]] name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload_time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload_time = "2025-08-25T13:49:24.86Z" }, ] [[package]] @@ -2843,18 +2854,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload_time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload_time = "2025-10-01T02:14:40.154Z" }, ] [[package]] name = "tzdata" version = "2025.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload_time = "2025-12-13T17:45:35.667Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload_time = "2025-12-13T17:45:33.889Z" }, ] [[package]] @@ -2864,27 +2875,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload_time = "2025-03-05T21:17:41.549Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload_time = "2025-03-05T21:17:39.857Z" }, ] [[package]] name = "uritemplate" version = "4.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267, upload-time = "2025-06-02T15:12:06.318Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267, upload_time = "2025-06-02T15:12:06.318Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload-time = "2025-06-02T15:12:03.405Z" }, + { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload_time = "2025-06-02T15:12:03.405Z" }, ] [[package]] name = "urllib3" version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload_time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload_time = "2026-01-07T16:24:42.685Z" }, ] [[package]] @@ -2895,50 +2906,50 @@ dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload_time = "2025-12-21T14:16:22.45Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, + { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload_time = "2025-12-21T14:16:21.041Z" }, ] [[package]] name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload_time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, - { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, - { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload_time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload_time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload_time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload_time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload_time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload_time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload_time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload_time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload_time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload_time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload_time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload_time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload_time = "2024-11-01T14:07:11.845Z" }, ] [[package]] name = "websockets" version = "15.0.1" 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" } +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/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { 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" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload_time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload_time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload_time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload_time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload_time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload_time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload_time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload_time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload_time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload_time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload_time = "2025-03-05T20:02:55.237Z" }, + { 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]] @@ -2950,80 +2961,80 @@ dependencies = [ { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, - { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, - { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, - { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, - { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, - { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, - { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, - { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, - { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, - { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, - { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, - { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, - { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, - { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, - { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, - { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, - { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, - { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, - { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, - { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, - { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, - { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, - { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, - { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, - { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, - { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, - { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, - { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, - { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, - { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, - { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, - { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, - { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, - { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, - { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, - { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, - { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, - { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, - { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, - { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, - { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, - { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, - { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, - { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload_time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload_time = "2025-10-06T14:10:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload_time = "2025-10-06T14:10:16.115Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload_time = "2025-10-06T14:10:17.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload_time = "2025-10-06T14:10:19.44Z" }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload_time = "2025-10-06T14:10:21.124Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload_time = "2025-10-06T14:10:22.902Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload_time = "2025-10-06T14:10:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload_time = "2025-10-06T14:10:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload_time = "2025-10-06T14:10:28.461Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload_time = "2025-10-06T14:10:30.541Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload_time = "2025-10-06T14:10:33.352Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload_time = "2025-10-06T14:10:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload_time = "2025-10-06T14:10:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload_time = "2025-10-06T14:10:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload_time = "2025-10-06T14:10:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload_time = "2025-10-06T14:10:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload_time = "2025-10-06T14:10:44.643Z" }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload_time = "2025-10-06T14:10:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload_time = "2025-10-06T14:10:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload_time = "2025-10-06T14:10:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload_time = "2025-10-06T14:10:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload_time = "2025-10-06T14:10:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload_time = "2025-10-06T14:10:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload_time = "2025-10-06T14:10:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload_time = "2025-10-06T14:10:59.633Z" }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload_time = "2025-10-06T14:11:01.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload_time = "2025-10-06T14:11:03.452Z" }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload_time = "2025-10-06T14:11:05.115Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload_time = "2025-10-06T14:11:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload_time = "2025-10-06T14:11:10.284Z" }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload_time = "2025-10-06T14:11:11.739Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload_time = "2025-10-06T14:11:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload_time = "2025-10-06T14:11:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload_time = "2025-10-06T14:11:17.106Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload_time = "2025-10-06T14:11:19.064Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload_time = "2025-10-06T14:11:20.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload_time = "2025-10-06T14:11:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload_time = "2025-10-06T14:11:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload_time = "2025-10-06T14:11:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload_time = "2025-10-06T14:11:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload_time = "2025-10-06T14:11:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload_time = "2025-10-06T14:11:33.055Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload_time = "2025-10-06T14:11:35.136Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload_time = "2025-10-06T14:11:37.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload_time = "2025-10-06T14:11:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload_time = "2025-10-06T14:11:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload_time = "2025-10-06T14:11:42.578Z" }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload_time = "2025-10-06T14:11:44.863Z" }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload_time = "2025-10-06T14:11:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload_time = "2025-10-06T14:11:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload_time = "2025-10-06T14:11:50.897Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload_time = "2025-10-06T14:11:52.549Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload_time = "2025-10-06T14:11:54.225Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload_time = "2025-10-06T14:11:56.069Z" }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload_time = "2025-10-06T14:11:58.783Z" }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload_time = "2025-10-06T14:12:00.686Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload_time = "2025-10-06T14:12:02.628Z" }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload_time = "2025-10-06T14:12:04.871Z" }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload_time = "2025-10-06T14:12:06.624Z" }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload_time = "2025-10-06T14:12:08.362Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload_time = "2025-10-06T14:12:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload_time = "2025-10-06T14:12:13.317Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload_time = "2025-10-06T14:12:15.398Z" }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload_time = "2025-10-06T14:12:16.935Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload_time = "2025-10-06T14:12:53.872Z" }, ] [[package]] name = "zipp" version = "3.23.0" 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" } +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" }, + { 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" }, ] diff --git a/samples/client/lit/contact/.env.example b/samples/client/lit/contact/.env.example new file mode 100644 index 000000000..cab6d7740 --- /dev/null +++ b/samples/client/lit/contact/.env.example @@ -0,0 +1,18 @@ +# Configuration for MCP Apps Double-Iframe Sandbox in Production +# INSTRUCTION: Copy the contents of this file to a new file named `.env` in this directory to apply these settings. + +# Example: If your main A2UI GenUI app is hosted at https://app.mycompany.com +# VITE_ALLOWED_HOST_ORIGIN=https://app.mycompany.com + +# Example: Then this MUST be hosted on a separate origin to comply with the MCP double-sandbox spec +# VITE_MCP_SANDBOX_URL=https://sandbox.mycompany.com/sandbox.html + +# ----------------------------------------------------------------------------------------- +# Localhost Development +# ----------------------------------------------------------------------------------------- +# For local development without needing a second server, you can leverage the browser's +# definition of origin isolation by using 127.0.0.1 for the sandbox while the host is localhost. +# By default, the code falls back to this behavior if the variables above are commented out. +# +# VITE_ALLOWED_HOST_ORIGIN=http://localhost:5173 +# VITE_MCP_SANDBOX_URL=http://127.0.0.1:5173/sandbox.html diff --git a/samples/client/lit/contact/package.json b/samples/client/lit/contact/package.json index 58da6a441..5205caa09 100644 --- a/samples/client/lit/contact/package.json +++ b/samples/client/lit/contact/package.json @@ -79,6 +79,7 @@ "@a2ui/lit": "file:../../../../renderers/lit", "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.4", + "@modelcontextprotocol/ext-apps": "^1.1.2", "lit": "^3.3.1" } } diff --git a/samples/client/lit/contact/sandbox.html b/samples/client/lit/contact/sandbox.html new file mode 100644 index 000000000..4e144e425 --- /dev/null +++ b/samples/client/lit/contact/sandbox.html @@ -0,0 +1,37 @@ + + + + + + MCP-UI Proxy + + + + + + diff --git a/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts new file mode 100644 index 000000000..0ff3b7e99 --- /dev/null +++ b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts @@ -0,0 +1,208 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { html, css } from "lit"; +import { customElement, property, query, state } from "lit/decorators.js"; +import { Root } from "@a2ui/lit/ui"; +import { v0_8 } from "@a2ui/lit"; +import { AppBridge, PostMessageTransport } from "@modelcontextprotocol/ext-apps/app-bridge"; +import type { McpUiSandboxProxyReadyNotification } from "@modelcontextprotocol/ext-apps/app-bridge"; + +@customElement("a2ui-mcp-apps-component") +export class McpAppsCustomComponent extends Root { + static override styles = [ + ...Root.styles, + css` + :host { + display: block; + width: 100%; + border: 1px solid var(--p-60, #eee); + position: relative; + overflow: hidden; /* For Aspect Ratio / Container */ + border-radius: 8px; + background: #fff; + } + iframe { + width: 100%; + height: 100%; + border: none; + background: #f5f5f5; + transition: height 0.3s ease-out, min-width 0.3s ease-out; + } + `, + ]; + + /* --- Properties (Server Contract) --- */ + + @property({ type: String }) + accessor resourceUri: string = ""; + + @property({ type: String }) + accessor htmlContent: string = ""; + + @property({ type: Number }) + accessor height: number | undefined = undefined; + + @property({ type: Array }) + accessor allowedTools: string[] = []; + + // --- Internal State --- + + @query("iframe") + accessor iframe!: HTMLIFrameElement; + + #bridge?: AppBridge; + + override render() { + // Default to aspect ratio if no height. Use 16:9 or 4:3. + const style = this.height ? `height: ${this.height}px;` : 'aspect-ratio: 4/3;'; + + return html` +
+ +
+ `; + } + + override firstUpdated() { + this.#initializeSandbox(); + } + + override disconnectedCallback() { + if (this.#bridge) { + this.#bridge.close(); + this.#bridge = undefined; + } + super.disconnectedCallback(); + } + + async #initializeSandbox() { + if (!this.iframe || !this.htmlContent) return; + + // Allow configuring the sandbox URL via env var for production deployment + // Fall back to the 127.0.0.1 trick for local development to simulate cross-origin isolation + const meta = import.meta as any; + const configuredSandboxUrl = meta && meta.env ? meta.env.VITE_MCP_SANDBOX_URL : undefined; + const sandboxOrigin = configuredSandboxUrl || `http://127.0.0.1:${window.location.port}/sandbox.html`; + const sandboxUrl = new URL(sandboxOrigin); + + // Set up the bridge. No MCP client needed because A2UI acts as the orchestrator. + this.#bridge = new AppBridge(null, { name: "A2UI Client Host", version: "1.0.0" }, { + serverTools: {}, + updateModelContext: { text: {} }, + }, { + hostContext: { + theme: "light", + platform: "web", + displayMode: "inline", + } + }); + + this.#bridge.onsizechange = ({ width, height }) => { + // Allow the view to dynamically resize the iframe container + const from: Keyframe = {}; + const to: Keyframe = {}; + + if (width !== undefined) { + from.minWidth = `${this.iframe.offsetWidth}px`; + this.iframe.style.minWidth = to.minWidth = `min(${width}px, 100%)`; + } + if (height !== undefined) { + from.height = `${this.iframe.offsetHeight}px`; + this.iframe.style.height = to.height = `${height}px`; + } + this.iframe.animate([from, to], { duration: 300, easing: "ease-out" }); + }; + + // Forward Tool Calls to the A2UI Action Dispatch + this.#bridge.oncalltool = async (params) => { + const actionName = params.name; + const args = params.arguments || {}; + + if (this.allowedTools.includes(actionName)) { + this.#dispatchAgentAction(actionName, args); + return { content: [{ type: "text", text: "Action dispatched to A2UI Agent" }] }; + } else { + console.warn(`[McpAppsCustomComponent] Tool '${actionName}' blocked.`); + throw new Error("Tool not allowed"); + } + }; + + this.#bridge.onloggingmessage = (params) => { + console.log(`[MCP Sandbox ${params.level}]:`, params.data); + }; + + // 1. Listen for the Outer Iframe to declare itself ready. + const readyNotification: McpUiSandboxProxyReadyNotification["method"] = "ui/notifications/sandbox-proxy-ready"; + const proxyReady = new Promise((resolve) => { + const listener = ({ source, data }: MessageEvent) => { + if (source === this.iframe.contentWindow && data?.method === readyNotification) { + window.removeEventListener("message", listener); + resolve(true); + } + }; + window.addEventListener("message", listener); + }); + + // 2. Load the proxy iframe. + this.iframe.src = sandboxUrl.href; + await proxyReady; + + // 3. Connect AppBridge via PostMessage transport. + // We pass iframe.contentWindow to target just the sandbox proxy. + await this.#bridge.connect(new PostMessageTransport(this.iframe.contentWindow!, this.iframe.contentWindow!)); + + // 4. Send the Inner HTML UI resource to the sandbox to spin up the actual app. + await this.#bridge.sendSandboxResourceReady({ + html: this.htmlContent, + sandbox: "allow-scripts allow-forms allow-popups allow-modals allow-same-origin" + }); + } + + #dispatchAgentAction(actionName: string, params: any) { + const context: v0_8.Types.Action["context"] = []; + if (params && typeof params === 'object') { + for (const [key, value] of Object.entries(params)) { + if (typeof value === "string") { + context.push({ key, value: { literalString: value } }); + } else if (typeof value === "number") { + context.push({ key, value: { literalNumber: value } }); + } else if (typeof value === "boolean") { + context.push({ key, value: { literalBoolean: value } }); + } + } + } + + const action: v0_8.Types.Action = { + name: actionName, + context, + }; + + const eventPayload: v0_8.Events.StateEventDetailMap["a2ui.action"] = { + eventType: "a2ui.action", + action, + sourceComponentId: this.id, + dataContextPath: this.dataContextPath, + sourceComponent: this.component as v0_8.Types.AnyComponentNode, + }; + + this.dispatchEvent(new v0_8.Events.StateEvent(eventPayload)); + } +} + diff --git a/samples/client/lit/contact/ui/custom-components/register-components.ts b/samples/client/lit/contact/ui/custom-components/register-components.ts index 047a0438c..94793196a 100644 --- a/samples/client/lit/contact/ui/custom-components/register-components.ts +++ b/samples/client/lit/contact/ui/custom-components/register-components.ts @@ -18,6 +18,7 @@ import { componentRegistry } from "@a2ui/lit/ui"; import { OrgChart } from "./org-chart.js"; import { WebFrame } from "./web-frame.js"; import { PremiumTextField } from "./premium-text-field.js"; +import { McpAppsCustomComponent } from "./mcp-apps-component.js"; export function registerContactComponents() { // Register OrgChart @@ -47,6 +48,20 @@ export function registerContactComponents() { "premium-text-field" ); + // Register McpAppsCustomComponent + componentRegistry.register("McpAppsCustomComponent", McpAppsCustomComponent, "a2ui-mcp-apps-component", { + type: "object", + properties: { + resourceUri: { type: "string" }, + htmlContent: { type: "string" }, + height: { type: "number" }, + allowedTools: { + type: "array", + items: { type: "string" } + } + }, + }); + // Register WebFrame componentRegistry.register("WebFrame", WebFrame, "a2ui-web-frame", { type: "object", diff --git a/samples/client/lit/contact/ui/sandbox.ts b/samples/client/lit/contact/ui/sandbox.ts new file mode 100644 index 000000000..75d0a71a8 --- /dev/null +++ b/samples/client/lit/contact/ui/sandbox.ts @@ -0,0 +1,107 @@ +import type { McpUiSandboxProxyReadyNotification, McpUiSandboxResourceReadyNotification } from "@modelcontextprotocol/ext-apps/app-bridge"; +import { buildAllowAttribute } from "@modelcontextprotocol/ext-apps/app-bridge"; + +// Allow configuring the expected host origin via environment variable for production +const meta = import.meta as any; +const allowedHostOrigin = meta && meta.env ? meta.env.VITE_ALLOWED_HOST_ORIGIN : undefined; +const ALLOWED_REFERRER_PATTERN = allowedHostOrigin + ? new RegExp(`^${allowedHostOrigin.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}`) + : /^http:\/\/(localhost|127\.0\.0\.1)(:|\/|$)/; + +if (window.self === window.top) { + throw new Error("This file is only to be used in an iframe sandbox."); +} + +if (!document.referrer) { + throw new Error("No referrer, cannot validate embedding site."); +} + +if (!document.referrer.match(ALLOWED_REFERRER_PATTERN)) { + throw new Error( + `Embedding domain not allowed in referrer ${document.referrer}. Expected sandbox environment configuration.`, + ); +} + +// Extract the expected host origin from the referrer for origin validation. +// This is the origin we expect all parent messages to come from. +const EXPECTED_HOST_ORIGIN = new URL(document.referrer).origin; +const OWN_ORIGIN = new URL(window.location.href).origin; + +// Security self-test: verify iframe isolation is working correctly. +try { + window.top!.alert("If you see this, the sandbox is not setup securely."); + throw "FAIL"; +} catch (e) { + if (e === "FAIL") { + throw new Error("The sandbox is not setup securely."); + } +} + +// Double-iframe sandbox architecture: THIS file is the outer sandbox proxy +// iframe on a separate origin. It creates an inner iframe for untrusted HTML content. +const inner = document.createElement("iframe"); +inner.style.cssText = "width:100%; height:100%; border:none;"; +inner.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms"); +document.body.appendChild(inner); + +const RESOURCE_READY_NOTIFICATION: McpUiSandboxResourceReadyNotification["method"] = + "ui/notifications/sandbox-resource-ready"; +const PROXY_READY_NOTIFICATION: McpUiSandboxProxyReadyNotification["method"] = + "ui/notifications/sandbox-proxy-ready"; + +window.addEventListener("message", async (event) => { + if (event.source === window.parent) { + if (event.origin !== EXPECTED_HOST_ORIGIN) { + console.error( + "[Sandbox] Rejecting message from unexpected origin:", + event.origin, + "expected:", + EXPECTED_HOST_ORIGIN + ); + return; + } + + if (event.data && event.data.method === RESOURCE_READY_NOTIFICATION) { + const { html, sandbox, permissions } = event.data.params; + if (typeof sandbox === "string") { + inner.setAttribute("sandbox", sandbox); + } + const allowAttribute = buildAllowAttribute(permissions); + if (allowAttribute) { + inner.setAttribute("allow", allowAttribute); + } + if (typeof html === "string") { + const doc = inner.contentDocument || inner.contentWindow?.document; + if (doc) { + doc.open(); + doc.write(html); + doc.close(); + } else { + inner.srcdoc = html; + } + } + } else { + if (inner && inner.contentWindow) { + inner.contentWindow.postMessage(event.data, "*"); + } + } + } else if (event.source === inner.contentWindow) { + if (event.origin !== OWN_ORIGIN) { + console.error( + "[Sandbox] Rejecting message from inner iframe with unexpected origin:", + event.origin, + "expected:", + OWN_ORIGIN + ); + return; + } + window.parent.postMessage(event.data, EXPECTED_HOST_ORIGIN); + } +}); + +// Notify Host +window.parent.postMessage({ + jsonrpc: "2.0", + method: PROXY_READY_NOTIFICATION, + params: {}, +}, EXPECTED_HOST_ORIGIN); diff --git a/samples/client/lit/contact/vite.config.ts b/samples/client/lit/contact/vite.config.ts index ce663a7a2..3467f8f5b 100644 --- a/samples/client/lit/contact/vite.config.ts +++ b/samples/client/lit/contact/vite.config.ts @@ -27,6 +27,7 @@ export default async () => { const entry: Record = { contact: resolve(__dirname, "index.html"), + sandbox: resolve(__dirname, "sandbox.html"), }; return { @@ -41,5 +42,8 @@ export default async () => { resolve: { dedupe: ["lit"], }, + server: { + host: true, // Listen on all network interfaces (0.0.0.0), enabling both localhost and 127.0.0.1 simultaneously + }, } satisfies UserConfig; }; diff --git a/samples/client/lit/package-lock.json b/samples/client/lit/package-lock.json index 94aeccddf..e357fb682 100644 --- a/samples/client/lit/package-lock.json +++ b/samples/client/lit/package-lock.json @@ -45,6 +45,7 @@ "@a2ui/lit": "file:../../../../renderers/lit", "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.4", + "@modelcontextprotocol/ext-apps": "^1.1.2", "lit": "^3.3.1" }, "devDependencies": { @@ -564,6 +565,19 @@ } } }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -694,6 +708,90 @@ "@lit-labs/ssr-dom-shim": "^1.5.0" } }, + "node_modules/@modelcontextprotocol/ext-apps": { + "version": "1.1.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@modelcontextprotocol/ext-apps/-/ext-apps-1.1.2.tgz", + "integrity": "sha512-Gx4TEo3/F8yq1Ix6LdgLwMrKqfZqD7++eakZdbMUewrYtHeeJn3nKpeNhgEfO7nYRwonqWYomOAszWZWJS0IbA==", + "hasInstallScript": true, + "license": "MIT", + "workspaces": [ + "examples/*" + ], + "optionalDependencies": { + "@oven/bun-darwin-aarch64": "^1.2.21", + "@oven/bun-darwin-x64": "^1.2.21", + "@oven/bun-darwin-x64-baseline": "^1.2.21", + "@oven/bun-linux-aarch64": "^1.2.21", + "@oven/bun-linux-aarch64-musl": "^1.2.21", + "@oven/bun-linux-x64": "^1.2.21", + "@oven/bun-linux-x64-baseline": "^1.2.21", + "@oven/bun-linux-x64-musl": "^1.2.21", + "@oven/bun-linux-x64-musl-baseline": "^1.2.21", + "@oven/bun-windows-x64": "^1.2.21", + "@oven/bun-windows-x64-baseline": "^1.2.21", + "@rollup/rollup-darwin-arm64": "^4.53.3", + "@rollup/rollup-darwin-x64": "^4.53.3", + "@rollup/rollup-linux-arm64-gnu": "^4.53.3", + "@rollup/rollup-linux-x64-gnu": "^4.53.3", + "@rollup/rollup-win32-arm64-msvc": "^4.53.3", + "@rollup/rollup-win32-x64-msvc": "^4.53.3" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.24.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.27.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz", + "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -732,6 +830,149 @@ "node": ">= 8" } }, + "node_modules/@oven/bun-darwin-aarch64": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.3.10.tgz", + "integrity": "sha512-PXgg5gqcS/rHwa1hF0JdM1y5TiyejVrMHoBmWY/DjtfYZoFTXie1RCFOkoG0b5diOOmUcuYarMpH7CSNTqwj+w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-darwin-x64/-/bun-darwin-x64-1.3.10.tgz", + "integrity": "sha512-Nhssuh7GBpP5PiDSOl3+qnoIG7PJo+ec2oomDevnl9pRY6x6aD2gRt0JE+uf+A8Om2D6gjeHCxjEdrw5ZHE8mA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64-baseline": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.3.10.tgz", + "integrity": "sha512-w1gaTlqU0IJCmJ1X+PGHkdNU1n8Gemx5YKkjhkJIguvFINXEBB5U1KG82QsT65Tk4KyNMfbLTlmy4giAvUoKfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-linux-aarch64": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.3.10.tgz", + "integrity": "sha512-OUgPHfL6+PM2Q+tFZjcaycN3D7gdQdYlWnwMI31DXZKY1r4HINWk9aEz9t/rNaHg65edwNrt7dsv9TF7xK8xIA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-aarch64-musl": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-aarch64-musl/-/bun-linux-aarch64-musl-1.3.10.tgz", + "integrity": "sha512-Ui5pAgM7JE9MzHokF0VglRMkbak3lTisY4Mf1AZutPACXWgKJC5aGrgnHBfkl7QS6fEeYb0juy1q4eRznRHOsw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64/-/bun-linux-x64-1.3.10.tgz", + "integrity": "sha512-bzUgYj/PIZziB/ZesIP9HUyfvh6Vlf3od+TrbTTyVEuCSMKzDPQVW/yEbRp0tcHO3alwiEXwJDrWrHAguXlgiQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-baseline": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.3.10.tgz", + "integrity": "sha512-oqvMDYpX6dGJO03HgO5bXuccEsH3qbdO3MaAiAlO4CfkBPLUXz3N0DDElg5hz0L6ktdDVKbQVE5lfe+LAUISQg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64-musl/-/bun-linux-x64-musl-1.3.10.tgz", + "integrity": "sha512-poVXvOShekbexHq45b4MH/mRjQKwACAC8lHp3Tz/hEDuz0/20oncqScnmKwzhBPEpqJvydXficXfBYuSim8opw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl-baseline": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64-musl-baseline/-/bun-linux-x64-musl-baseline-1.3.10.tgz", + "integrity": "sha512-/hOZ6S1VsTX6vtbhWVL9aAnOrdpuO54mAGUWpTdMz7dFG5UBZ/VUEiK0pBkq9A1rlBk0GeD/6Y4NBFl8Ha7cRA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-windows-x64": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-windows-x64/-/bun-windows-x64-1.3.10.tgz", + "integrity": "sha512-qaS1In3yfC/Z/IGQriVmF8GWwKuNqiw7feTSJWaQhH5IbL6ENR+4wGNPniZSJFaM/SKUO0e/YCRdoVBvgU4C1g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oven/bun-windows-x64-baseline": { + "version": "1.3.10", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-windows-x64-baseline/-/bun-windows-x64-baseline-1.3.10.tgz", + "integrity": "sha512-gh3UAHbUdDUG6fhLc1Csa4IGdtghue6U8oAIXWnUqawp6lwb3gOCRvp25IUnLF5vUHtgfMxuEUYV7YA2WxVutw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -841,7 +1082,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -855,7 +1095,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -925,7 +1164,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1051,7 +1289,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1107,7 +1344,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1149,7 +1385,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1178,6 +1413,20 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT" }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -1187,6 +1436,41 @@ "node": ">= 14" } }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1286,6 +1570,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -1314,6 +1623,47 @@ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1427,6 +1777,68 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "peer": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1467,6 +1879,16 @@ } } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dotenv": { "version": "17.2.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", @@ -1480,14 +1902,29 @@ "url": "https://dotenvx.com" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", @@ -1495,12 +1932,62 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT", + "peer": true + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -1553,12 +2040,122 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT", + "peer": true + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "peer": true, + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.2.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/express-rate-limit/-/express-rate-limit-8.2.1.tgz", + "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "license": "MIT", + "peer": true, + "dependencies": { + "ip-address": "10.0.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT", + "peer": true + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -1576,6 +2173,23 @@ "node": ">=8.6.0" } }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "peer": true + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -1640,6 +2254,28 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -1668,6 +2304,26 @@ "node": ">=12.20.0" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1683,6 +2339,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gaxios": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz", @@ -1722,6 +2388,45 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "peer": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -1782,6 +2487,19 @@ "node": ">=14" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1812,6 +2530,63 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.12.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/hono/-/hono-4.12.3.tgz", + "integrity": "sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -1825,6 +2600,50 @@ "node": ">= 14" } }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC", + "peer": true + }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1880,6 +2699,13 @@ "node": ">=0.12.0" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT", + "peer": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1901,6 +2727,16 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -1910,6 +2746,20 @@ "bignumber.js": "^9.0.0" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT", + "peer": true + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause", + "peer": true + }, "node_modules/jsonc-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", @@ -1981,6 +2831,39 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2018,6 +2901,33 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -2067,6 +2977,16 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -2115,12 +3035,68 @@ "node": ">=0.10.0" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2146,6 +3122,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2159,7 +3146,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -2167,6 +3153,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -2239,6 +3235,36 @@ "node": ">=12.0.0" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "peer": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2260,6 +3286,32 @@ ], "license": "MIT" }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -2296,6 +3348,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -2377,6 +3439,23 @@ "fsevents": "~2.3.2" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2431,6 +3510,67 @@ ], "license": "MIT" }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT", + "peer": true + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "peer": true, + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC", + "peer": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2465,6 +3605,82 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "peer": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -2493,6 +3709,16 @@ "node": ">=0.10.0" } }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2593,6 +3819,16 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -2610,6 +3846,21 @@ "dev": true, "license": "0BSD" }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "peer": true, + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -2630,6 +3881,16 @@ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/uuid": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", @@ -2644,6 +3905,16 @@ "uuid": "dist-node/bin/uuid" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vite": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", @@ -2826,6 +4097,13 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC", + "peer": true + }, "node_modules/ws": { "version": "8.19.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", @@ -2886,6 +4164,26 @@ "node": ">=12" } }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peer": true, + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, "shell": { "name": "@a2ui/shell", "version": "0.8.1", From 77e96a2cb563f65e40a3114f7dfab194a34dd2b1 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Mon, 2 Mar 2026 15:20:06 -0800 Subject: [PATCH 02/19] chore: address PR review comments from gemini-code-assist --- .../agent/adk/contact_multiple_surfaces/agent.py | 14 ++++++++++++-- .../contact_multiple_surfaces/floor_plan_server.py | 6 +++++- .../ui/custom-components/mcp-apps-component.ts | 2 ++ samples/client/lit/contact/ui/sandbox.ts | 2 +- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/samples/agent/adk/contact_multiple_surfaces/agent.py b/samples/agent/adk/contact_multiple_surfaces/agent.py index 4c755ce84..ec79541cb 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent.py @@ -233,10 +233,13 @@ async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: from mcp import ClientSession from mcp.client.sse import sse_client + import os + + sse_url = os.environ.get("FLOOR_PLAN_SERVER_URL", "http://127.0.0.1:8000/sse") try: # Connect to the persistent Starlette SSE server - async with sse_client("http://127.0.0.1:8000/sse") as (read, write): + async with sse_client(sse_url) as (read, write): async with ClientSession(read, write) as mcp_session: await mcp_session.initialize() @@ -247,11 +250,18 @@ async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: raise ValueError("No content returned from floor plan server") html_content = result.contents[0].text + except ValueError as e: + logger.error(f"Invalid floor plan data: {e}") + yield { + "is_task_complete": True, + "content": f"Failed to load floor plan data: {str(e)}" + } + return except Exception as e: logger.error(f"Failed to fetch floor plan from SSE server: {e}") yield { "is_task_complete": True, - "content": f"Failed to load floor plan: {str(e)}" + "content": f"Failed to connect to floor plan server: {str(e)}" } return diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py index f1d219861..14f3994b2 100644 --- a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py @@ -23,6 +23,9 @@ async def read_resource(uri: str) -> str | bytes: if str(uri) != RESOURCE_URI: raise ValueError(f"Unknown resource: {uri}") + import os + agent_static_url = os.environ.get("AGENT_STATIC_URL", "http://localhost:10004") + html = """ @@ -106,7 +109,7 @@ async def read_resource(uri: str) -> str | bytes:
- Office Floor Plan + Office Floor Plan
@@ -265,6 +268,7 @@ async def read_resource(uri: str) -> str | bytes: """ + html = html.replace("__AGENT_STATIC_URL__", agent_static_url) return html import uvicorn diff --git a/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts index 0ff3b7e99..85d139167 100644 --- a/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts +++ b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts @@ -185,6 +185,8 @@ export class McpAppsCustomComponent extends Root { context.push({ key, value: { literalNumber: value } }); } else if (typeof value === "boolean") { context.push({ key, value: { literalBoolean: value } }); + } else if (value !== null && typeof value === 'object') { + context.push({ key, value: { literalString: JSON.stringify(value) } }); } } } diff --git a/samples/client/lit/contact/ui/sandbox.ts b/samples/client/lit/contact/ui/sandbox.ts index 75d0a71a8..2fe43e4f8 100644 --- a/samples/client/lit/contact/ui/sandbox.ts +++ b/samples/client/lit/contact/ui/sandbox.ts @@ -82,7 +82,7 @@ window.addEventListener("message", async (event) => { } } else { if (inner && inner.contentWindow) { - inner.contentWindow.postMessage(event.data, "*"); + inner.contentWindow.postMessage(event.data, OWN_ORIGIN); } } } else if (event.source === inner.contentWindow) { From 24cbc89872c9a3ff108b4278638431df791f8e47 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Mon, 2 Mar 2026 15:26:36 -0800 Subject: [PATCH 03/19] fix: Secure postMessage by capturing trusted host origin statefully --- .../contact_multiple_surfaces/floor_plan_server.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py index 14f3994b2..194b55f18 100644 --- a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py @@ -135,6 +135,7 @@ async def read_resource(uri: str) -> str | bytes: let pointY = 0; let startX = 0; let startY = 0; + let hostOrigin = '*'; window.onload = () => { updateTransform(); }; @@ -224,7 +225,7 @@ async def read_resource(uri: str) -> str | bytes: source: 'modal' } } - }, '*'); + }, hostOrigin); }; } else { el.style.borderColor = 'rgba(0,0,0,0.1)'; @@ -246,8 +247,13 @@ async def read_resource(uri: str) -> str | bytes: } window.addEventListener('message', (event) => { + // Capture the trusted host origin from the first incoming message + if (hostOrigin === '*' && event.source === window.parent) { + hostOrigin = event.origin; + } + const data = event.data; - if (data.type === 'zoom') { + if (data && data.type === 'zoom') { zoom(data.payload.factor); } }); @@ -264,7 +270,7 @@ async def read_resource(uri: str) -> str | bytes: clientInfo: { name: "Floor Plan App", version: "1.0.0" }, protocolVersion: "2026-01-26" } - }, '*'); + }, hostOrigin); """ From ab56d1715faefd910e4e75c769628ab3c5334244 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:57:52 -0800 Subject: [PATCH 04/19] fix: fully secure MCP iframe initialization handshake with sandbox-init payload --- pr_748_replies.md | 80 +++++++++++++++++++ .../floor_plan_server.py | 24 +++--- .../tasks-do-not-submit.md | 7 ++ samples/client/lit/contact/ui/sandbox.ts | 9 +++ 4 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 pr_748_replies.md create mode 100644 samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md diff --git a/pr_748_replies.md b/pr_748_replies.md new file mode 100644 index 000000000..7344a9ce5 --- /dev/null +++ b/pr_748_replies.md @@ -0,0 +1,80 @@ +# PR #748 Review Responses + +Here are proposed first-person responses you can paste into each of the review comment threads on GitHub! I've included the reviewer's exact quotes so you can easily match them up. + +### 1. General PR Summary Comment (Security & Tests) +**Reviewer via gemini-code-assist:** +> ![medium] +> +> This pull request integrates MCP Apps into A2UI by adding a new `McpAppsCustomComponent`, a double-iframe sandbox for security, and a persistent SSE backend... I've identified critical security issues related to `postMessage` usage that should be addressed. Additionally, there are opportunities to improve maintainability by removing hardcoded URLs... The repository's style guide requires tests for new code... Please consider adding tests... + +**Reply:** +> Thanks for the thorough review! I've gone ahead and secured all the `postMessage` boundaries across the stack. Specifically, the client sandbox proxy now strictly enforces `EXPECTED_HOST_ORIGIN` validating against the `document.referrer`, and the inner `floor_plan_server` uses a stateful approach to capture and lock to the exact `hostOrigin` from the frontend handshake rather than blindly broadcasting to `*`. I've also parameterized all hardcoded URLs. +> +> As for the tests, we currently do not use an automated UI testing framework for the Python ADK backend samples, but I've manually verified the edge cases and failure modes end-to-end to ensure the connection robustly handles errors and rejected tool calls. + +--- + +### 2. `sandbox.ts` Line (null) - Target Origin +**Reviewer via gemini-code-assist:** +> ![high] +> +> When forwarding messages to the inner iframe, you are using a wildcard `*` as the target origin. While the inner iframe is same-origin in this setup, it is a security best practice to always specify the exact target origin. You should use `OWN_ORIGIN` here to ensure the message is only delivered if the inner iframe's origin matches. + +**Reply:** +> Addressed in the latest commit. I realized this was leaking through the proxy, so I swapped the forwarder destination from `*` to `OWN_ORIGIN`. + +--- + +### 3. `floor_plan_server.py` Line (null) - Target Origin Vulnerability +**Reviewer via gemini-code-assist:** +> ![critical] +> +> The `postMessage` calls on lines 224 and 264 use a wildcard `*` for the target origin, which is a significant security vulnerability. This allows any website to embed this content and intercept the messages. You should restrict the target origin to the specific, expected parent origin. For example, the parent frame could send its origin in an initial message, which this script could then store and use for all subsequent `postMessage` calls. + +**Reply:** +> Great point. I implemented exactly what you suggested: The inner iframe logic now defaults `hostOrigin` to `*` only until it receives a `sandbox-init` message from the parent proxy. It captures the `event.origin`, permanently saves it as the `hostOrigin`, and strictly uses that for all subsequent outbound MCP tool calls and the initial `ui/initialize` handshake! + +--- + +### 4. `agent.py` Line (null) - Hardcoded SSE URL +**Reviewer via gemini-code-assist:** +> ![medium] +> +> The SSE server URL `http://127.0.0.1:8000/sse` is hardcoded. This makes the agent less flexible and harder to configure for different environments (e.g., development, staging, production). It's recommended to extract this into a configurable variable, for instance, loaded from an environment variable. + +**Reply:** +> Good catch! I updated the connection logic to grab `FLOOR_PLAN_SERVER_URL` entirely from the `os.environ`. It defaults securely to the local `http://127.0.0.1:8000/sse` for the out-of-the-box demo experience, but can now easily run in deployed or CI environments without code changes. + +--- + +### 5. `agent.py` Line 260 - Broad Exception Handler +**Reviewer via gemini-code-assist:** +> ![medium] +> +> Catching a broad `Exception` can hide unexpected errors and make debugging more difficult. It's better to catch more specific exceptions that you expect from the network request (e.g., connection errors) and from the logic within the `try` block (like the `ValueError` you're raising). This allows for more granular error handling and logging. + +**Reply:** +> Done. I've added a specific catch block for `ValueError` alongside the other connection handlers. If the floor plan server responds with invalid or empty data (like a 404), the agent will now catch it explicitly and gracefully yield a UI error message indicating the failure to load the floor plan, rather than swallowing a broader bug. + +--- + +### 6. `floor_plan_server.py` Line (null) - Hardcoded Static URL +**Reviewer via gemini-code-assist:** +> ![medium] +> +> The image URL `http://localhost:10004/static/floorplan.png` is hardcoded within the HTML string. This will cause issues when deploying to environments other than local development. This URL should be made configurable, for example by passing it into the HTML template from the Python server, which could in turn read it from an environment variable or configuration file. + +**Reply:** +> Fixed. I refactored the floor plan HTML payload injection to dynamically inject an `AGENT_STATIC_URL` variable read from the environment. It replaces `__AGENT_STATIC_URL__` in the template strings, entirely decoupling the static asset delivery from the strict local port mapping. + +--- + +### 7. `mcp-apps-component.ts` Line 190 - Complex Action Arguments +**Reviewer via gemini-code-assist:** +> ![medium] +> +> The `#dispatchAgentAction` method currently only handles primitive types (`string`, `number`, `boolean`) for action parameters. If an action parameter is a complex object or an array, it will be skipped without an error. To make this more robust, you should consider handling these cases, for example by serializing complex values to a JSON string. + +**Reply:** +> This is a great edge case to protect against. I've updated the dispatcher's type checking logic as you suggested. It now gracefully detects complex objects or arrays and stringifies them into a generic `literalString` payload using `JSON.stringify()`. This ensures the backend `context` resolver can still extract those arguments dynamically without the frontend silently dropping them. diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py index 194b55f18..2aeebf8fa 100644 --- a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py @@ -250,6 +250,18 @@ async def read_resource(uri: str) -> str | bytes: // Capture the trusted host origin from the first incoming message if (hostOrigin === '*' && event.source === window.parent) { hostOrigin = event.origin; + + // MCP Handshake AFTER getting the origin securely + window.parent.postMessage({ + jsonrpc: "2.0", + id: Date.now(), + method: "ui/initialize", + params: { + appCapabilities: {}, + clientInfo: { name: "Floor Plan App", version: "1.0.0" }, + protocolVersion: "2026-01-26" + } + }, hostOrigin); } const data = event.data; @@ -259,18 +271,6 @@ async def read_resource(uri: str) -> str | bytes: }); createHotspots(); - - // MCP Handshake - window.parent.postMessage({ - jsonrpc: "2.0", - id: Date.now(), - method: "ui/initialize", - params: { - appCapabilities: {}, - clientInfo: { name: "Floor Plan App", version: "1.0.0" }, - protocolVersion: "2026-01-26" - } - }, hostOrigin); """ diff --git a/samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md b/samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md new file mode 100644 index 000000000..2ce14a6d6 --- /dev/null +++ b/samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md @@ -0,0 +1,7 @@ +Check out the contact_multiple_surfaces sample for a2ui. Here, we are using a single agent to handle multiple a2ui surfaces. One is a genUI surface (JSON coming down and rendered using standard catalog components). The second is a custom component surface (where we are using a custom component to render the UI). The third one (for showing office location) is an iframe custom component. + +We want to create a new MCP-APPs SDK based custom component that can be used similar to the iframe component (be fully interactive and update combined state of all surfaces through piped action events). Make ultra sure that you are strictly referring to the official MCP-Apps docs and use the official MCP apps sdk for this custom MCPAppsCustomComponent. It is at https://github.com/modelcontextprotocol/ext-apps + +For this, I assume you will need to create a new MCP server that will host this custom component. This MCP server will be called by the agent to render the custom component. We need to make sure that it is still within A2UI. (The ui:// resource is encapsulated with a2ui). + +Goal of this new custom component is to be able to easily integrate with already built MCP servers that support MCP apps. Make sure that the sample functionality (including shared state across all a2ui surfaces) and looks are maintained. You can just replace the iframe component with this new MCPAppsCustomComponent. Then the surface will be an MCP apps custom component surface. diff --git a/samples/client/lit/contact/ui/sandbox.ts b/samples/client/lit/contact/ui/sandbox.ts index 2fe43e4f8..7c39446ce 100644 --- a/samples/client/lit/contact/ui/sandbox.ts +++ b/samples/client/lit/contact/ui/sandbox.ts @@ -71,11 +71,20 @@ window.addEventListener("message", async (event) => { inner.setAttribute("allow", allowAttribute); } if (typeof html === "string") { + const sendInit = () => { + if (inner.contentWindow) { + inner.contentWindow.postMessage({ type: "sandbox-init" }, OWN_ORIGIN); + } + }; + inner.onload = sendInit; + const doc = inner.contentDocument || inner.contentWindow?.document; if (doc) { doc.open(); doc.write(html); doc.close(); + // doc.write doesn't always trigger iframe onload reliably. + Promise.resolve().then(sendInit); } else { inner.srcdoc = html; } From e22bed75789307699c8d5b2db6fc300c8d5b93d8 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:11:20 -0800 Subject: [PATCH 05/19] style: run pyink auto-formatter to fix CI build --- .../adk/contact_multiple_surfaces/agent.py | 202 ++++++++---------- .../floor_plan_server.py | 56 ++--- 2 files changed, 120 insertions(+), 138 deletions(-) diff --git a/samples/agent/adk/contact_multiple_surfaces/agent.py b/samples/agent/adk/contact_multiple_surfaces/agent.py index 172c10dc6..66bb8b5f0 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent.py @@ -248,114 +248,102 @@ async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: sse_url = os.environ.get("FLOOR_PLAN_SERVER_URL", "http://127.0.0.1:8000/sse") try: - # Connect to the persistent Starlette SSE server - async with sse_client(sse_url) as (read, write): - async with ClientSession(read, write) as mcp_session: - await mcp_session.initialize() - - logger.info("--- ContactAgent: Fetching ui://floor-plan-server/map from persistent SSE server ---") - result = await mcp_session.read_resource("ui://floor-plan-server/map") - - if not result.contents or len(result.contents) == 0: - raise ValueError("No content returned from floor plan server") - - html_content = result.contents[0].text + # Connect to the persistent Starlette SSE server + async with sse_client(sse_url) as (read, write): + async with ClientSession(read, write) as mcp_session: + await mcp_session.initialize() + + logger.info( + "--- ContactAgent: Fetching ui://floor-plan-server/map from" + " persistent SSE server ---" + ) + result = await mcp_session.read_resource("ui://floor-plan-server/map") + + if not result.contents or len(result.contents) == 0: + raise ValueError("No content returned from floor plan server") + + html_content = result.contents[0].text except ValueError as e: - logger.error(f"Invalid floor plan data: {e}") - yield { - "is_task_complete": True, - "content": f"Failed to load floor plan data: {str(e)}" - } - return + logger.error(f"Invalid floor plan data: {e}") + yield { + "is_task_complete": True, + "content": f"Failed to load floor plan data: {str(e)}", + } + return except Exception as e: - logger.error(f"Failed to fetch floor plan from SSE server: {e}") - yield { - "is_task_complete": True, - "content": f"Failed to connect to floor plan server: {str(e)}" - } - return + logger.error(f"Failed to fetch floor plan from SSE server: {e}") + yield { + "is_task_complete": True, + "content": f"Failed to connect to floor plan server: {str(e)}", + } + return json_content = [ - { - "beginRendering": { - "surfaceId": "location-surface", - "root": "floor-plan-card" - } - }, - { - "surfaceUpdate": { - "surfaceId": "location-surface", - "components": [ - { - "id": "floor-plan-card", - "component": { - "Card": { - "child": "floor-plan-col" - } - } - }, - { - "id": "floor-plan-col", - "component": { - "Column": { - "children": { - "explicitList": [ - "floor-plan-title", - "floor-plan-comp", - "dismiss-fp" - ] - } - } - } - }, - { - "id": "floor-plan-title", - "component": { - "Text": { - "usageHint": "h2", - "text": { - "literalString": "Office Floor Plan" - } - } - } - }, - { - "id": "floor-plan-comp", - "component": { - "McpAppsCustomComponent": { - "htmlContent": html_content, - "height": 400, - "allowedTools": [ - "chart_node_click" - ] - } - } - }, - { - "id": "dismiss-fp-text", - "component": { - "Text": { - "text": { - "literalString": "Close Map" - } - } - } - }, - { - "id": "dismiss-fp", - "component": { - "Button": { - "child": "dismiss-fp-text", - "action": { - "name": "close_modal", - "context": [] - } - } - } + { + "beginRendering": { + "surfaceId": "location-surface", + "root": "floor-plan-card", } - ] - } - } + }, + { + "surfaceUpdate": { + "surfaceId": "location-surface", + "components": [ + { + "id": "floor-plan-card", + "component": {"Card": {"child": "floor-plan-col"}}, + }, + { + "id": "floor-plan-col", + "component": { + "Column": { + "children": { + "explicitList": [ + "floor-plan-title", + "floor-plan-comp", + "dismiss-fp", + ] + } + } + }, + }, + { + "id": "floor-plan-title", + "component": { + "Text": { + "usageHint": "h2", + "text": {"literalString": "Office Floor Plan"}, + } + }, + }, + { + "id": "floor-plan-comp", + "component": { + "McpAppsCustomComponent": { + "htmlContent": html_content, + "height": 400, + "allowedTools": ["chart_node_click"], + } + }, + }, + { + "id": "dismiss-fp-text", + "component": { + "Text": {"text": {"literalString": "Close Map"}} + }, + }, + { + "id": "dismiss-fp", + "component": { + "Button": { + "child": "dismiss-fp-text", + "action": {"name": "close_modal", "context": []}, + } + }, + }, + ], + } + }, ] logger.info(f"--- ContactAgent.stream: Sending Floor Plan ---") @@ -367,13 +355,7 @@ async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: if query.startswith("ACTION:") and "close_modal" in query: logger.info("--- ContactAgent.stream: Handling close_modal ACTION ---") - json_content = [ - { - "deleteSurface": { - "surfaceId": "location-surface" - } - } - ] + json_content = [{"deleteSurface": {"surfaceId": "location-surface"}}] final_response_content = ( f"Modal closed.\n---a2ui_JSON---\n{json.dumps(json_content)}" ) diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py index 2aeebf8fa..a6687f6e3 100644 --- a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py @@ -7,26 +7,29 @@ RESOURCE_URI = "ui://floor-plan-server/map" MIME_TYPE = "text/html;profile=mcp-app" + @app.list_resources() async def list_resources() -> list[Resource]: - return [ - Resource( - uri=RESOURCE_URI, - name="Interactive Floor Plan", - mimeType=MIME_TYPE, - description="A visual floor plan showing desk assignments." - ) - ] + return [ + Resource( + uri=RESOURCE_URI, + name="Interactive Floor Plan", + mimeType=MIME_TYPE, + description="A visual floor plan showing desk assignments.", + ) + ] + @app.read_resource() async def read_resource(uri: str) -> str | bytes: - if str(uri) != RESOURCE_URI: - raise ValueError(f"Unknown resource: {uri}") - - import os - agent_static_url = os.environ.get("AGENT_STATIC_URL", "http://localhost:10004") - - html = """ + if str(uri) != RESOURCE_URI: + raise ValueError(f"Unknown resource: {uri}") + + import os + + agent_static_url = os.environ.get("AGENT_STATIC_URL", "http://localhost:10004") + + html = """ @@ -274,8 +277,9 @@ async def read_resource(uri: str) -> str | bytes: """ - html = html.replace("__AGENT_STATIC_URL__", agent_static_url) - return html + html = html.replace("__AGENT_STATIC_URL__", agent_static_url) + return html + import uvicorn from starlette.applications import Starlette @@ -286,17 +290,13 @@ async def read_resource(uri: str) -> str | bytes: sse = SseServerTransport("/messages/") + async def handle_sse(request: Request): - """Handle the initial SSE connection from the A2UI agent.""" - async with sse.connect_sse( - request.scope, request.receive, request._send - ) as streams: - await app.run( - streams[0], - streams[1], - app.create_initialization_options() - ) - return Response() + """Handle the initial SSE connection from the A2UI agent.""" + async with sse.connect_sse(request.scope, request.receive, request._send) as streams: + await app.run(streams[0], streams[1], app.create_initialization_options()) + return Response() + starlette_app = Starlette( routes=[ @@ -306,4 +306,4 @@ async def handle_sse(request: Request): ) if __name__ == "__main__": - uvicorn.run(starlette_app, host="127.0.0.1", port=8000) + uvicorn.run(starlette_app, host="127.0.0.1", port=8000) From f5b2f41434ed54982128c1fb85d736816d033147 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:12:39 -0700 Subject: [PATCH 06/19] fix(markdown-it): add missing package main and exports to resolve downstream import errors --- renderers/markdown/markdown-it/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/renderers/markdown/markdown-it/package.json b/renderers/markdown/markdown-it/package.json index 69de3d150..a83f938c7 100644 --- a/renderers/markdown/markdown-it/package.json +++ b/renderers/markdown/markdown-it/package.json @@ -15,9 +15,12 @@ "license": "Apache-2.0", "author": "Google", "type": "module", + "main": "dist/src/markdown.js", "exports": { ".": { "types": "./dist/src/markdown.d.ts", + "import": "./dist/src/markdown.js", + "require": "./dist/src/markdown.js", "default": "./dist/src/markdown.js" } }, From 22859bfc0b6c37b5442d6ff3a8c8af5c04a94e4c Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:12:45 -0700 Subject: [PATCH 07/19] fix(contact): resolve MCP iframe security issues and location double-click bug --- pr_748_replies.md | 80 ------------------- .../adk/contact_multiple_surfaces/README.md | 6 ++ .../adk/contact_multiple_surfaces/agent.py | 7 ++ .../tasks-do-not-submit.md | 7 -- samples/client/lit/contact/README.md | 3 +- samples/client/lit/contact/contact.ts | 8 +- samples/client/lit/contact/sandbox.html | 2 + samples/client/lit/contact/test_browser.js | 15 ++++ samples/client/lit/contact/test_browser.py | 49 ++++++++++++ .../client/lit/contact/test_browser_cdp.js | 23 ++++++ .../client/lit/contact/test_browser_static.js | 18 +++++ .../custom-components/mcp-apps-component.ts | 12 ++- samples/client/lit/contact/vite.config.ts | 7 +- 13 files changed, 143 insertions(+), 94 deletions(-) delete mode 100644 pr_748_replies.md delete mode 100644 samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md create mode 100644 samples/client/lit/contact/test_browser.js create mode 100644 samples/client/lit/contact/test_browser.py create mode 100644 samples/client/lit/contact/test_browser_cdp.js create mode 100644 samples/client/lit/contact/test_browser_static.js diff --git a/pr_748_replies.md b/pr_748_replies.md deleted file mode 100644 index 7344a9ce5..000000000 --- a/pr_748_replies.md +++ /dev/null @@ -1,80 +0,0 @@ -# PR #748 Review Responses - -Here are proposed first-person responses you can paste into each of the review comment threads on GitHub! I've included the reviewer's exact quotes so you can easily match them up. - -### 1. General PR Summary Comment (Security & Tests) -**Reviewer via gemini-code-assist:** -> ![medium] -> -> This pull request integrates MCP Apps into A2UI by adding a new `McpAppsCustomComponent`, a double-iframe sandbox for security, and a persistent SSE backend... I've identified critical security issues related to `postMessage` usage that should be addressed. Additionally, there are opportunities to improve maintainability by removing hardcoded URLs... The repository's style guide requires tests for new code... Please consider adding tests... - -**Reply:** -> Thanks for the thorough review! I've gone ahead and secured all the `postMessage` boundaries across the stack. Specifically, the client sandbox proxy now strictly enforces `EXPECTED_HOST_ORIGIN` validating against the `document.referrer`, and the inner `floor_plan_server` uses a stateful approach to capture and lock to the exact `hostOrigin` from the frontend handshake rather than blindly broadcasting to `*`. I've also parameterized all hardcoded URLs. -> -> As for the tests, we currently do not use an automated UI testing framework for the Python ADK backend samples, but I've manually verified the edge cases and failure modes end-to-end to ensure the connection robustly handles errors and rejected tool calls. - ---- - -### 2. `sandbox.ts` Line (null) - Target Origin -**Reviewer via gemini-code-assist:** -> ![high] -> -> When forwarding messages to the inner iframe, you are using a wildcard `*` as the target origin. While the inner iframe is same-origin in this setup, it is a security best practice to always specify the exact target origin. You should use `OWN_ORIGIN` here to ensure the message is only delivered if the inner iframe's origin matches. - -**Reply:** -> Addressed in the latest commit. I realized this was leaking through the proxy, so I swapped the forwarder destination from `*` to `OWN_ORIGIN`. - ---- - -### 3. `floor_plan_server.py` Line (null) - Target Origin Vulnerability -**Reviewer via gemini-code-assist:** -> ![critical] -> -> The `postMessage` calls on lines 224 and 264 use a wildcard `*` for the target origin, which is a significant security vulnerability. This allows any website to embed this content and intercept the messages. You should restrict the target origin to the specific, expected parent origin. For example, the parent frame could send its origin in an initial message, which this script could then store and use for all subsequent `postMessage` calls. - -**Reply:** -> Great point. I implemented exactly what you suggested: The inner iframe logic now defaults `hostOrigin` to `*` only until it receives a `sandbox-init` message from the parent proxy. It captures the `event.origin`, permanently saves it as the `hostOrigin`, and strictly uses that for all subsequent outbound MCP tool calls and the initial `ui/initialize` handshake! - ---- - -### 4. `agent.py` Line (null) - Hardcoded SSE URL -**Reviewer via gemini-code-assist:** -> ![medium] -> -> The SSE server URL `http://127.0.0.1:8000/sse` is hardcoded. This makes the agent less flexible and harder to configure for different environments (e.g., development, staging, production). It's recommended to extract this into a configurable variable, for instance, loaded from an environment variable. - -**Reply:** -> Good catch! I updated the connection logic to grab `FLOOR_PLAN_SERVER_URL` entirely from the `os.environ`. It defaults securely to the local `http://127.0.0.1:8000/sse` for the out-of-the-box demo experience, but can now easily run in deployed or CI environments without code changes. - ---- - -### 5. `agent.py` Line 260 - Broad Exception Handler -**Reviewer via gemini-code-assist:** -> ![medium] -> -> Catching a broad `Exception` can hide unexpected errors and make debugging more difficult. It's better to catch more specific exceptions that you expect from the network request (e.g., connection errors) and from the logic within the `try` block (like the `ValueError` you're raising). This allows for more granular error handling and logging. - -**Reply:** -> Done. I've added a specific catch block for `ValueError` alongside the other connection handlers. If the floor plan server responds with invalid or empty data (like a 404), the agent will now catch it explicitly and gracefully yield a UI error message indicating the failure to load the floor plan, rather than swallowing a broader bug. - ---- - -### 6. `floor_plan_server.py` Line (null) - Hardcoded Static URL -**Reviewer via gemini-code-assist:** -> ![medium] -> -> The image URL `http://localhost:10004/static/floorplan.png` is hardcoded within the HTML string. This will cause issues when deploying to environments other than local development. This URL should be made configurable, for example by passing it into the HTML template from the Python server, which could in turn read it from an environment variable or configuration file. - -**Reply:** -> Fixed. I refactored the floor plan HTML payload injection to dynamically inject an `AGENT_STATIC_URL` variable read from the environment. It replaces `__AGENT_STATIC_URL__` in the template strings, entirely decoupling the static asset delivery from the strict local port mapping. - ---- - -### 7. `mcp-apps-component.ts` Line 190 - Complex Action Arguments -**Reviewer via gemini-code-assist:** -> ![medium] -> -> The `#dispatchAgentAction` method currently only handles primitive types (`string`, `number`, `boolean`) for action parameters. If an action parameter is a complex object or an array, it will be skipped without an error. To make this more robust, you should consider handling these cases, for example by serializing complex values to a JSON string. - -**Reply:** -> This is a great edge case to protect against. I've updated the dispatcher's type checking logic as you suggested. It now gracefully detects complex objects or arrays and stringifies them into a generic `literalString` payload using `JSON.stringify()`. This ensures the backend `context` resolver can still extract those arguments dynamically without the frontend silently dropping them. diff --git a/samples/agent/adk/contact_multiple_surfaces/README.md b/samples/agent/adk/contact_multiple_surfaces/README.md index 3c11ebb13..f561a2c9e 100644 --- a/samples/agent/adk/contact_multiple_surfaces/README.md +++ b/samples/agent/adk/contact_multiple_surfaces/README.md @@ -28,6 +28,12 @@ This sample uses the Agent Development Kit (ADK) along with the A2A protocol to uv run . ``` +4. (Optional) Run the server with standard `WebFrame` instead of the custom `McpAppsCustomComponent`: + + ```bash + USE_MCP_SANDBOX=false uv run . + ``` + ## Disclaimer diff --git a/samples/agent/adk/contact_multiple_surfaces/agent.py b/samples/agent/adk/contact_multiple_surfaces/agent.py index 66bb8b5f0..c71b4af59 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent.py @@ -324,6 +324,13 @@ async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: "height": 400, "allowedTools": ["chart_node_click"], } + } if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true" else { + "WebFrame": { + "html": html_content, + "height": 400, + "interactionMode": "interactive", + "allowedEvents": ["chart_node_click"], + } }, }, { diff --git a/samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md b/samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md deleted file mode 100644 index 2ce14a6d6..000000000 --- a/samples/agent/adk/contact_multiple_surfaces/tasks-do-not-submit.md +++ /dev/null @@ -1,7 +0,0 @@ -Check out the contact_multiple_surfaces sample for a2ui. Here, we are using a single agent to handle multiple a2ui surfaces. One is a genUI surface (JSON coming down and rendered using standard catalog components). The second is a custom component surface (where we are using a custom component to render the UI). The third one (for showing office location) is an iframe custom component. - -We want to create a new MCP-APPs SDK based custom component that can be used similar to the iframe component (be fully interactive and update combined state of all surfaces through piped action events). Make ultra sure that you are strictly referring to the official MCP-Apps docs and use the official MCP apps sdk for this custom MCPAppsCustomComponent. It is at https://github.com/modelcontextprotocol/ext-apps - -For this, I assume you will need to create a new MCP server that will host this custom component. This MCP server will be called by the agent to render the custom component. We need to make sure that it is still within A2UI. (The ui:// resource is encapsulated with a2ui). - -Goal of this new custom component is to be able to easily integrate with already built MCP servers that support MCP apps. Make sure that the sample functionality (including shared state across all a2ui surfaces) and looks are maintained. You can just replace the iframe component with this new MCPAppsCustomComponent. Then the surface will be an MCP apps custom component surface. diff --git a/samples/client/lit/contact/README.md b/samples/client/lit/contact/README.md index 9cea3880b..a3fd92234 100644 --- a/samples/client/lit/contact/README.md +++ b/samples/client/lit/contact/README.md @@ -24,7 +24,8 @@ This sample depends on the Lit renderer. Before running this sample, you need to ``` 3. **Run the servers:** - - Run the [A2A server](../../../agent/adk/contact_lookup/) + - Run the [A2A server](../../../agent/adk/contact_multiple_surfaces/) + - Optionally run the server using `USE_MCP_SANDBOX=false uv run .` to bypass the custom `McpAppsCustomComponent` and use the standard `WebFrame` element. - Run the dev server: `npm run dev` After starting the dev server, you can open http://localhost:5173/ to view the sample. \ No newline at end of file diff --git a/samples/client/lit/contact/contact.ts b/samples/client/lit/contact/contact.ts index 8300abe16..c04f5821d 100644 --- a/samples/client/lit/contact/contact.ts +++ b/samples/client/lit/contact/contact.ts @@ -41,6 +41,9 @@ import * as UI from "@a2ui/lit/ui"; // Demo elements. import "./ui/ui.js"; import { registerContactComponents } from "./ui/custom-components/register-components.js"; +import { Context } from "@a2ui/lit/ui"; +// @ts-ignore +import { renderMarkdown } from "@a2ui/markdown-it"; // Register custom components for the contact app registerContactComponents(); @@ -54,6 +57,9 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { @provide({ context: UI.Context.themeContext }) accessor theme: v0_8.Types.Theme = uiTheme; + @provide({ context: UI.Context.markdown }) + accessor markdownRenderer: v0_8.Types.MarkdownRenderer = renderMarkdown; + @state() accessor #requesting = false; @@ -345,7 +351,7 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { const message: v0_8.Types.A2UIClientEventMessage = { userAction: { surfaceId: surfaceId, - name: evt.detail.action.name, + name: "ACTION: " + evt.detail.action.name, sourceComponentId: target.id, timestamp: new Date().toISOString(), context, diff --git a/samples/client/lit/contact/sandbox.html b/samples/client/lit/contact/sandbox.html index 4e144e425..2a9960c1d 100644 --- a/samples/client/lit/contact/sandbox.html +++ b/samples/client/lit/contact/sandbox.html @@ -3,6 +3,8 @@ + MCP-UI Proxy - - - -
-
- Office Floor Plan -
-
-
- - - -""" + from pathlib import Path + template_path = Path(__file__).parent / "floor_plan_template.html" + html = template_path.read_text(encoding="utf-8") html = html.replace("__AGENT_STATIC_URL__", agent_static_url) return html diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_template.html b/samples/agent/adk/contact_multiple_surfaces/floor_plan_template.html new file mode 100644 index 000000000..475dad459 --- /dev/null +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_template.html @@ -0,0 +1,248 @@ + + + + + + + Floor Plan + + + + +
+
+ Office Floor Plan +
+
+
+ + + + diff --git a/samples/client/lit/contact/README.md b/samples/client/lit/contact/README.md index a3fd92234..433712b33 100644 --- a/samples/client/lit/contact/README.md +++ b/samples/client/lit/contact/README.md @@ -25,7 +25,9 @@ This sample depends on the Lit renderer. Before running this sample, you need to 3. **Run the servers:** - Run the [A2A server](../../../agent/adk/contact_multiple_surfaces/) - - Optionally run the server using `USE_MCP_SANDBOX=false uv run .` to bypass the custom `McpAppsCustomComponent` and use the standard `WebFrame` element. + - By default, the server uses the `McpAppsCustomComponent` which wraps MCP Apps in a secure, isolated double-iframe sandbox (`sandbox.html`) communicating strictly via JSON-RPC. + - Optionally run the server using `USE_MCP_SANDBOX=false uv run .` to bypass this security and use the standard `WebFrame` element. + - **Observing the difference**: Search for "Alex Jordan" in the UI and click the Location button to open the floor plan. If you inspect the DOM using your browser's Developer Tools, you will see that `McpAppsCustomComponent` securely points the iframe `src` to the local proxy (`/sandbox.html`). In contrast, `WebFrame` directly injects the untrusted HTML via a data blob/srcdoc, lacking defense-in-depth origin isolation. - Run the dev server: `npm run dev` After starting the dev server, you can open http://localhost:5173/ to view the sample. \ No newline at end of file diff --git a/samples/client/lit/contact/vite.config.ts b/samples/client/lit/contact/vite.config.ts index 0125d3745..c8101061c 100644 --- a/samples/client/lit/contact/vite.config.ts +++ b/samples/client/lit/contact/vite.config.ts @@ -41,6 +41,9 @@ export default async () => { define: {}, resolve: { dedupe: ["lit"], + alias: { + "@a2ui/markdown-it": resolve(__dirname, "../../../../renderers/markdown/markdown-it/dist/src/markdown.js") + } }, optimizeDeps: { esbuildOptions: { From c1b84a1d992140efb1122b1a7492e6be85ecb3ac Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Wed, 11 Mar 2026 08:58:03 -0700 Subject: [PATCH 10/19] fix(lit): resolve compiler type errors and review comments --- .../lit/src/0.8/ui/directives/markdown.ts | 15 +++++++--- renderers/lit/src/0.8/ui/root.ts | 4 +-- renderers/lit/src/0.8/ui/text-field.ts | 2 +- samples/client/lit/contact/contact.ts | 2 +- .../custom-components/mcp-apps-component.ts | 30 +++++++++---------- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/renderers/lit/src/0.8/ui/directives/markdown.ts b/renderers/lit/src/0.8/ui/directives/markdown.ts index d909ac823..4102290bc 100644 --- a/renderers/lit/src/0.8/ui/directives/markdown.ts +++ b/renderers/lit/src/0.8/ui/directives/markdown.ts @@ -50,15 +50,22 @@ class MarkdownDirective extends Directive { */ render(value: string, markdownRenderer?: Types.MarkdownRenderer, markdownOptions?: Types.MarkdownRendererOptions) { if (markdownRenderer) { - const rendered = markdownRenderer(value, markdownOptions).then((value) => { + const result = markdownRenderer(value, markdownOptions) as any; + if (typeof result === 'string') { + return unsafeHTML(result); + } + const rendered = result.then((val: string) => { // `value` is a plain string, which we need to convert to a template // with the `unsafeHTML` directive. // It is the responsibility of the markdown renderer to sanitize the HTML. - return unsafeHTML(value); - }) + return unsafeHTML(val); + }); // The until directive lets us render a placeholder *until* the rendered // content resolves. - return until(rendered, html`${value}`); + return until( + rendered, + html`${value}` + ); } if (!MarkdownDirective.defaultMarkdownWarningLogged) { diff --git a/renderers/lit/src/0.8/ui/root.ts b/renderers/lit/src/0.8/ui/root.ts index de5f357e9..563858b3d 100644 --- a/renderers/lit/src/0.8/ui/root.ts +++ b/renderers/lit/src/0.8/ui/root.ts @@ -299,7 +299,7 @@ export class Root extends SignalWatcher(LitElement) { .dataContextPath=${node.dataContextPath ?? ""} .action=${node.properties.action} .childComponents=${[node.properties.child]} - .primary=${node.properties.primary} + .primary=${(node.properties as any).primary} .enableCustomElements=${this.enableCustomElements} >`; } @@ -422,7 +422,7 @@ export class Root extends SignalWatcher(LitElement) { .dataContextPath=${node.dataContextPath} .label=${node.properties.label} .text=${node.properties.text} - .textFieldType=${node.properties.textFieldType} + .textFieldType=${(node.properties as any).textFieldType} .validationRegexp=${node.properties.validationRegexp} .enableCustomElements=${this.enableCustomElements} >`; diff --git a/renderers/lit/src/0.8/ui/text-field.ts b/renderers/lit/src/0.8/ui/text-field.ts index 90caf76be..d9fa06d60 100644 --- a/renderers/lit/src/0.8/ui/text-field.ts +++ b/renderers/lit/src/0.8/ui/text-field.ts @@ -35,7 +35,7 @@ export class TextField extends Root { accessor label: Primitives.StringValue | null = null; @property() - accessor textFieldType: Types.ResolvedTextField["textFieldType"] | null = null; + accessor textFieldType: string | null = null; @property() accessor validationRegexp: string | null = null; diff --git a/samples/client/lit/contact/contact.ts b/samples/client/lit/contact/contact.ts index f0e8cab0a..61fc0cbdb 100644 --- a/samples/client/lit/contact/contact.ts +++ b/samples/client/lit/contact/contact.ts @@ -58,7 +58,7 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { accessor theme: v0_8.Types.Theme = uiTheme; @provide({ context: UI.Context.markdown }) - accessor markdownRenderer: v0_8.Types.MarkdownRenderer = renderMarkdown; + accessor markdownRenderer: v0_8.Types.MarkdownRenderer = renderMarkdown as any; @state() accessor #requesting = false; diff --git a/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts index 11158e8e9..6c8d16342 100644 --- a/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts +++ b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts @@ -64,7 +64,7 @@ export class McpAppsCustomComponent extends Root { @query("iframe") accessor iframe!: HTMLIFrameElement; - #bridge?: AppBridge; + private bridge?: AppBridge; override render() { // Default to aspect ratio if no height. Use 16:9 or 4:3. @@ -83,20 +83,20 @@ export class McpAppsCustomComponent extends Root { override updated(changedProperties: Map) { super.updated(changedProperties); - if (!this.#bridge && this.htmlContent && this.iframe) { - this.#initializeSandbox(); + if (!this.bridge && this.htmlContent && this.iframe) { + this.initializeSandbox(); } } override disconnectedCallback() { - if (this.#bridge) { - this.#bridge.close(); - this.#bridge = undefined; + if (this.bridge) { + this.bridge.close(); + this.bridge = undefined; } super.disconnectedCallback(); } - async #initializeSandbox() { + private async initializeSandbox() { if (!this.iframe || !this.htmlContent) return; // Allow configuring the sandbox URL via env var for production deployment @@ -107,7 +107,7 @@ export class McpAppsCustomComponent extends Root { const sandboxUrl = new URL(sandboxOrigin); // Set up the bridge. No MCP client needed because A2UI acts as the orchestrator. - this.#bridge = new AppBridge(null, { name: "A2UI Client Host", version: "1.0.0" }, { + this.bridge = new AppBridge(null, { name: "A2UI Client Host", version: "1.0.0" }, { serverTools: {}, updateModelContext: { text: {} }, }, { @@ -118,7 +118,7 @@ export class McpAppsCustomComponent extends Root { } }); - this.#bridge.onsizechange = ({ width, height }) => { + this.bridge.onsizechange = ({ width, height }) => { // Allow the view to dynamically resize the iframe container const from: Keyframe = {}; const to: Keyframe = {}; @@ -135,12 +135,12 @@ export class McpAppsCustomComponent extends Root { }; // Forward Tool Calls to the A2UI Action Dispatch - this.#bridge.oncalltool = async (params) => { + this.bridge.oncalltool = async (params) => { const actionName = params.name; const args = params.arguments || {}; if (this.allowedTools.includes(actionName)) { - this.#dispatchAgentAction(actionName, args); + this.dispatchAgentAction(actionName, args); return { content: [{ type: "text", text: "Action dispatched to A2UI Agent" }] }; } else { console.warn(`[McpAppsCustomComponent] Tool '${actionName}' blocked.`); @@ -148,7 +148,7 @@ export class McpAppsCustomComponent extends Root { } }; - this.#bridge.onloggingmessage = (params) => { + this.bridge.onloggingmessage = (params) => { console.log(`[MCP Sandbox ${params.level}]:`, params.data); }; @@ -170,16 +170,16 @@ export class McpAppsCustomComponent extends Root { // 3. Connect AppBridge via PostMessage transport. // We pass iframe.contentWindow to target just the sandbox proxy. - await this.#bridge.connect(new PostMessageTransport(this.iframe.contentWindow!, this.iframe.contentWindow!)); + await this.bridge.connect(new PostMessageTransport(this.iframe.contentWindow!, this.iframe.contentWindow!)); // 4. Send the Inner HTML UI resource to the sandbox to spin up the actual app. - await this.#bridge.sendSandboxResourceReady({ + await this.bridge.sendSandboxResourceReady({ html: this.htmlContent, sandbox: "allow-scripts allow-forms allow-popups allow-modals allow-same-origin" }); } - #dispatchAgentAction(actionName: string, params: any) { + private dispatchAgentAction(actionName: string, params: any) { const context: v0_8.Types.Action["context"] = []; if (params && typeof params === 'object') { for (const [key, value] of Object.entries(params)) { From 62bfcd39d1c720a01d2aa4edbfc582a85114f256 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Wed, 11 Mar 2026 09:25:36 -0700 Subject: [PATCH 11/19] chore: remove internal Google3 configs and properly align renderer schemas --- renderers/angular/.npmrc | 2 -- renderers/lit/.npmrc | 2 -- renderers/lit/src/0.8/ui/directives/markdown.ts | 10 +++------- renderers/lit/src/0.8/ui/root.ts | 4 ++-- renderers/lit/src/0.8/ui/text-field.ts | 2 +- renderers/markdown/markdown-it/.npmrc | 2 -- samples/client/lit/contact/contact.ts | 4 +++- 7 files changed, 9 insertions(+), 17 deletions(-) delete mode 100644 renderers/angular/.npmrc delete mode 100644 renderers/lit/.npmrc delete mode 100644 renderers/markdown/markdown-it/.npmrc diff --git a/renderers/angular/.npmrc b/renderers/angular/.npmrc deleted file mode 100644 index 06b0eef7e..000000000 --- a/renderers/angular/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ -//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/renderers/lit/.npmrc b/renderers/lit/.npmrc deleted file mode 100644 index 06b0eef7e..000000000 --- a/renderers/lit/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ -//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/renderers/lit/src/0.8/ui/directives/markdown.ts b/renderers/lit/src/0.8/ui/directives/markdown.ts index 4102290bc..9a3b20330 100644 --- a/renderers/lit/src/0.8/ui/directives/markdown.ts +++ b/renderers/lit/src/0.8/ui/directives/markdown.ts @@ -50,16 +50,12 @@ class MarkdownDirective extends Directive { */ render(value: string, markdownRenderer?: Types.MarkdownRenderer, markdownOptions?: Types.MarkdownRendererOptions) { if (markdownRenderer) { - const result = markdownRenderer(value, markdownOptions) as any; - if (typeof result === 'string') { - return unsafeHTML(result); - } - const rendered = result.then((val: string) => { + const rendered = markdownRenderer(value, markdownOptions).then((value) => { // `value` is a plain string, which we need to convert to a template // with the `unsafeHTML` directive. // It is the responsibility of the markdown renderer to sanitize the HTML. - return unsafeHTML(val); - }); + return unsafeHTML(value); + }) // The until directive lets us render a placeholder *until* the rendered // content resolves. return until( diff --git a/renderers/lit/src/0.8/ui/root.ts b/renderers/lit/src/0.8/ui/root.ts index 563858b3d..de5f357e9 100644 --- a/renderers/lit/src/0.8/ui/root.ts +++ b/renderers/lit/src/0.8/ui/root.ts @@ -299,7 +299,7 @@ export class Root extends SignalWatcher(LitElement) { .dataContextPath=${node.dataContextPath ?? ""} .action=${node.properties.action} .childComponents=${[node.properties.child]} - .primary=${(node.properties as any).primary} + .primary=${node.properties.primary} .enableCustomElements=${this.enableCustomElements} >`; } @@ -422,7 +422,7 @@ export class Root extends SignalWatcher(LitElement) { .dataContextPath=${node.dataContextPath} .label=${node.properties.label} .text=${node.properties.text} - .textFieldType=${(node.properties as any).textFieldType} + .textFieldType=${node.properties.textFieldType} .validationRegexp=${node.properties.validationRegexp} .enableCustomElements=${this.enableCustomElements} >`; diff --git a/renderers/lit/src/0.8/ui/text-field.ts b/renderers/lit/src/0.8/ui/text-field.ts index d9fa06d60..90caf76be 100644 --- a/renderers/lit/src/0.8/ui/text-field.ts +++ b/renderers/lit/src/0.8/ui/text-field.ts @@ -35,7 +35,7 @@ export class TextField extends Root { accessor label: Primitives.StringValue | null = null; @property() - accessor textFieldType: string | null = null; + accessor textFieldType: Types.ResolvedTextField["textFieldType"] | null = null; @property() accessor validationRegexp: string | null = null; diff --git a/renderers/markdown/markdown-it/.npmrc b/renderers/markdown/markdown-it/.npmrc deleted file mode 100644 index 06b0eef7e..000000000 --- a/renderers/markdown/markdown-it/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ -//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/samples/client/lit/contact/contact.ts b/samples/client/lit/contact/contact.ts index 61fc0cbdb..895cd1913 100644 --- a/samples/client/lit/contact/contact.ts +++ b/samples/client/lit/contact/contact.ts @@ -58,7 +58,9 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { accessor theme: v0_8.Types.Theme = uiTheme; @provide({ context: UI.Context.markdown }) - accessor markdownRenderer: v0_8.Types.MarkdownRenderer = renderMarkdown as any; + accessor markdownRenderer: v0_8.Types.MarkdownRenderer = async (text, options) => { + return renderMarkdown(text, options); + }; @state() accessor #requesting = false; From 22cfcecc7aa50d7d22e6d1728a82218a570d4590 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Thu, 12 Mar 2026 10:06:14 -0700 Subject: [PATCH 12/19] Fix A2UI schema validator for incremental updates and update sample iframe titles --- .../python/src/a2ui/core/schema/manager.py | 9 ++- .../python/src/a2ui/core/schema/utils.py | 11 ++++ .../python/src/a2ui/core/schema/validator.py | 60 +++++++++++-------- .../adk/contact_multiple_surfaces/agent.py | 8 +-- .../agent_executor.py | 23 +++---- .../examples/contact_card.json | 4 ++ .../examples/multi_surface.json | 4 ++ .../prompt_builder.py | 13 +++- samples/client/lit/contact/contact.ts | 3 +- .../custom-components/register-components.ts | 47 ++++++++++++--- 10 files changed, 131 insertions(+), 51 deletions(-) diff --git a/agent_sdks/python/src/a2ui/core/schema/manager.py b/agent_sdks/python/src/a2ui/core/schema/manager.py index 5a92c8787..1a012f3b4 100644 --- a/agent_sdks/python/src/a2ui/core/schema/manager.py +++ b/agent_sdks/python/src/a2ui/core/schema/manager.py @@ -19,7 +19,7 @@ import importlib.resources from typing import List, Dict, Any, Optional, Callable from dataclasses import dataclass, field -from .utils import load_from_bundled_resource +from .utils import load_from_bundled_resource, deep_update from ..inference_strategy import InferenceStrategy from .constants import * from .catalog import CatalogConfig, A2uiCatalog @@ -146,10 +146,15 @@ def _select_catalog( # Load the first inline catalog schema. inline_catalog_schema = inline_catalogs[0] inline_catalog_schema = self._apply_modifiers(inline_catalog_schema) + + # Deep merge the standard catalog properties with the inline catalog + merged_schema = copy.deepcopy(self._supported_catalogs[0].catalog_schema) + deep_update(merged_schema, inline_catalog_schema) + return A2uiCatalog( version=self._version, name=INLINE_CATALOG_NAME, - catalog_schema=inline_catalog_schema, + catalog_schema=merged_schema, s2c_schema=self._server_to_client_schema, common_types_schema=self._common_types_schema, ) diff --git a/agent_sdks/python/src/a2ui/core/schema/utils.py b/agent_sdks/python/src/a2ui/core/schema/utils.py index f68ce85b7..1f35015d9 100644 --- a/agent_sdks/python/src/a2ui/core/schema/utils.py +++ b/agent_sdks/python/src/a2ui/core/schema/utils.py @@ -117,3 +117,14 @@ def wrap_as_json_array(a2ui_schema: dict[str, Any]) -> dict[str, Any]: if not a2ui_schema: raise ValueError("A2UI schema is empty") return {"type": "array", "items": a2ui_schema} + + +def deep_update(d: dict, u: dict) -> dict: + """Recursively update a dict with another dict.""" + for k, v in u.items(): + if isinstance(v, dict): + d[k] = deep_update(d.get(k, {}), v) + else: + d[k] = v + return d + diff --git a/agent_sdks/python/src/a2ui/core/schema/validator.py b/agent_sdks/python/src/a2ui/core/schema/validator.py index 07c1b968a..54696859c 100644 --- a/agent_sdks/python/src/a2ui/core/schema/validator.py +++ b/agent_sdks/python/src/a2ui/core/schema/validator.py @@ -274,31 +274,33 @@ def validate(self, a2ui_json: Union[Dict[str, Any], List[Any]]) -> None: msg += f"\n - {sub_error.message}" raise ValueError(msg) - root_id = _find_root_id(messages) - for message in messages: if not isinstance(message, dict): continue components = None + surface_id = None if "surfaceUpdate" in message: # v0.8 components = message["surfaceUpdate"].get(COMPONENTS) + surface_id = message["surfaceUpdate"].get("surfaceId") elif "updateComponents" in message and isinstance( message["updateComponents"], dict ): # v0.9 components = message["updateComponents"].get(COMPONENTS) + surface_id = message["updateComponents"].get("surfaceId") if components: ref_map = _extract_component_ref_fields(self._catalog) + root_id = _find_root_id(messages, surface_id) _validate_component_integrity(root_id, components, ref_map) _validate_topology(root_id, components, ref_map) _validate_recursion_and_paths(message) -def _find_root_id(messages: List[Dict[str, Any]]) -> str: +def _find_root_id(messages: List[Dict[str, Any]], surface_id: Optional[str] = None) -> Optional[str]: """ - Finds the root id from a list of A2UI messages. + Finds the root id from a list of A2UI messages for a given surface. - For v0.8, the root id is in the beginRendering message. - For v0.9+, the root id is 'root'. """ @@ -306,12 +308,14 @@ def _find_root_id(messages: List[Dict[str, Any]]) -> str: if not isinstance(message, dict): continue if "beginRendering" in message: + if surface_id and message["beginRendering"].get("surfaceId") != surface_id: + continue return message["beginRendering"].get(ROOT, ROOT) - return ROOT + return None def _validate_component_integrity( - root_id: str, + root_id: Optional[str], components: List[Dict[str, Any]], ref_fields_map: Dict[str, tuple[Set[str], Set[str]]], ) -> None: @@ -334,21 +338,23 @@ def _validate_component_integrity( ids.add(comp_id) # 2. Check for root component - if root_id not in ids: + if root_id is not None and root_id not in ids: raise ValueError(f"Missing root component: No component has id='{root_id}'") # 3. Check for dangling references using helper - for comp in components: - for ref_id, field_name in _get_component_references(comp, ref_fields_map): - if ref_id not in ids: - raise ValueError( - f"Component '{comp.get(ID)}' references non-existent component '{ref_id}'" - f" in field '{field_name}'" - ) + # In an incremental update (root_id is None), components may reference IDs already on the client. + if root_id is not None: + for comp in components: + for ref_id, field_name in _get_component_references(comp, ref_fields_map): + if ref_id not in ids: + raise ValueError( + f"Component '{comp.get(ID)}' references non-existent component '{ref_id}'" + f" in field '{field_name}'" + ) def _validate_topology( - root_id: str, + root_id: Optional[str], components: List[Dict[str, Any]], ref_fields_map: Dict[str, tuple[Set[str], Set[str]]], ) -> None: @@ -401,16 +407,22 @@ def dfs(node_id: str, depth: int): recursion_stack.remove(node_id) - if root_id in all_ids: - dfs(root_id, 0) + if root_id is not None: + if root_id in all_ids: + dfs(root_id, 0) - # Check for Orphans - orphans = all_ids - visited - if orphans: - sorted_orphans = sorted(list(orphans)) - raise ValueError( - f"Component '{sorted_orphans[0]}' is not reachable from '{root_id}'" - ) + # Check for Orphans + orphans = all_ids - visited + if orphans: + sorted_orphans = sorted(list(orphans)) + raise ValueError( + f"Component '{sorted_orphans[0]}' is not reachable from '{root_id}'" + ) + else: + # Partial update: we cannot check root reachability, but we still check for cycles + for node_id in all_ids: + if node_id not in visited: + dfs(node_id, 0) def _extract_component_ref_fields( diff --git a/samples/agent/adk/contact_multiple_surfaces/agent.py b/samples/agent/adk/contact_multiple_surfaces/agent.py index 87cd7a4ee..270506c39 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent.py @@ -40,7 +40,7 @@ get_text_prompt, ROLE_DESCRIPTION, WORKFLOW_DESCRIPTION, - UI_DESCRIPTION, + get_ui_description, ) from tools import get_contact_info from a2ui.core.schema.constants import VERSION_0_8, A2UI_OPEN_TAG, A2UI_CLOSE_TAG @@ -128,7 +128,7 @@ def _build_agent(self, use_ui: bool) -> LlmAgent: self.schema_manager.generate_system_prompt( role_description=ROLE_DESCRIPTION, workflow_description=WORKFLOW_DESCRIPTION, - ui_description=UI_DESCRIPTION, + ui_description=get_ui_description(), include_examples=True, include_schema=True, validate_examples=False, # Missing inline_catalogs for OrgChart and WebFrame validation @@ -145,7 +145,7 @@ def _build_agent(self, use_ui: bool) -> LlmAgent: tools=[get_contact_info], ) - async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: + async def stream(self, query, session_id, client_ui_capabilities: dict[str, Any] | None = None) -> AsyncIterable[dict[str, Any]]: session_state = {"base_url": self.base_url} session = await self._runner.session_service.get_session( @@ -169,7 +169,7 @@ async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: current_query_text = query # Ensure schema was loaded - selected_catalog = self.schema_manager.get_selected_catalog() + selected_catalog = self.schema_manager.get_selected_catalog(client_ui_capabilities) if self.use_ui and not selected_catalog.catalog_schema: logger.error( "--- ContactAgent.stream: A2UI_SCHEMA is not loaded. " diff --git a/samples/agent/adk/contact_multiple_surfaces/agent_executor.py b/samples/agent/adk/contact_multiple_surfaces/agent_executor.py index c56d488c4..72effe18b 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent_executor.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent_executor.py @@ -53,6 +53,7 @@ async def execute( query = "" ui_event_part = None action = None + client_ui_capabilities = None logger.info(f"--- Client requested extensions: {context.requested_extensions} ---") use_ui = try_activate_a2ui_extension(context) @@ -91,15 +92,6 @@ async def execute( client_ui_capabilities = part.root.data["metadata"][ "a2uiClientCapabilities" ] - catalog = agent.schema_manager.get_selected_catalog( - client_ui_capabilities=client_ui_capabilities - ) - catalog_schema_str = catalog.render_as_llm_instructions() - # Append to query so the agent sees it (simple injection) - query += ( - "\n\n[SYSTEM: The client supports the following custom components:" - f" {catalog_schema_str}]" - ) else: logger.info(f" Part {i}: DataPart (data: {part.root.data})") elif isinstance(part.root, TextPart): @@ -155,6 +147,17 @@ async def execute( logger.info("No a2ui UI event part found. Falling back to text input.") query = context.get_user_input() + # Inject client UI capabilities into the query if found + if client_ui_capabilities is not None and "query" in locals() and query: + catalog = agent.schema_manager.get_selected_catalog( + client_ui_capabilities=client_ui_capabilities + ) + catalog_schema_str = catalog.render_as_llm_instructions() + query += ( + "\n\n[SYSTEM: The client supports the following custom components:" + f" {catalog_schema_str}]" + ) + logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") task = context.current_task @@ -164,7 +167,7 @@ async def execute( await event_queue.enqueue_event(task) updater = TaskUpdater(event_queue, task.id, task.context_id) - async for item in agent.stream(query, task.context_id): + async for item in agent.stream(query, task.context_id, client_ui_capabilities): is_task_complete = item["is_task_complete"] if not is_task_complete: await updater.update_status( diff --git a/samples/agent/adk/contact_multiple_surfaces/examples/contact_card.json b/samples/agent/adk/contact_multiple_surfaces/examples/contact_card.json index 12f77e644..979515425 100644 --- a/samples/agent/adk/contact_multiple_surfaces/examples/contact_card.json +++ b/samples/agent/adk/contact_multiple_surfaces/examples/contact_card.json @@ -441,6 +441,10 @@ "surfaceId": "contact-card", "path": "/", "contents": [ + { + "key": "id", + "valueString": "1" + }, { "key": "name", "valueString": "" diff --git a/samples/agent/adk/contact_multiple_surfaces/examples/multi_surface.json b/samples/agent/adk/contact_multiple_surfaces/examples/multi_surface.json index ffa723cc6..638d58334 100644 --- a/samples/agent/adk/contact_multiple_surfaces/examples/multi_surface.json +++ b/samples/agent/adk/contact_multiple_surfaces/examples/multi_surface.json @@ -480,6 +480,10 @@ "surfaceId": "contact-card", "path": "/", "contents": [ + { + "key": "id", + "valueString": "2" + }, { "key": "name", "valueString": "Casey Smith" diff --git a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py index 8bc8cbeb0..ddd383b07 100644 --- a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py +++ b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py @@ -28,12 +28,18 @@ Buttons that represent the main action on a card or view (e.g., 'Follow', 'Email', 'Search') SHOULD include the `"primary": true` attribute. """ -UI_DESCRIPTION = f""" +def get_ui_description() -> str: + import os + title_suffix = "(iFrame)" + if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true": + title_suffix = "(MCP Apps)" + + return f""" - **For finding contacts (e.g., "Who is Alex Jordan?"):** a. You MUST call the `get_contact_info` tool. b. If the tool returns a **single contact**, you MUST use the `MULTI_SURFACE_EXAMPLE` template. Provide BOTH the Contact Card and the Org Chart in a single response. c. If the tool returns **multiple contacts**, you MUST use the `CONTACT_LIST_EXAMPLE` template. Populate the `dataModelUpdate.contents` with the list of contacts for the "contacts" key. - d. If the tool returns an **empty list**, respond with text only and an empty JSON list: "I couldn't find anyone by that name.{A2UI_OPEN_TAG}[]{A2UI_CLOSE_TAG}" + d. If the tool returns an **empty list**, respond with text only and an empty JSON list: "I couldn't find anyone by that name.{{A2UI_OPEN_TAG}}[]{{A2UI_CLOSE_TAG}}" - **For handling a profile view (e.g., "WHO_IS: Alex Jordan..."):** a. You MUST call the `get_contact_info` tool with the specific name. @@ -42,6 +48,9 @@ - **For handling actions (e.g., "USER_WANTS_TO_EMAIL: ..."):** a. You MUST use the `ACTION_CONFIRMATION_EXAMPLE` template. b. Populate the `dataModelUpdate.contents` with a confirmation title and message (e.g., title: "Email Drafted", message: "Drafting an email to Alex Jordan..."). + +- **For generating the Org Chart (`org-chart-view` dataModelUpdate or title Text):** + a. You MUST set any title referring to the Organizational Chart to exactly "Organizational Chart {title_suffix}". """ diff --git a/samples/client/lit/contact/contact.ts b/samples/client/lit/contact/contact.ts index 895cd1913..18f50be86 100644 --- a/samples/client/lit/contact/contact.ts +++ b/samples/client/lit/contact/contact.ts @@ -276,7 +276,7 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { `; } - const surfacesMap = this.#processor.getSurfaces(); + const surfacesMap = new Map(this.#processor.getSurfaces()); const surfaces = Array.from(surfacesMap.entries()).sort(([a], [b]) => { // "org-chart-view" comes first (left), "contact-card" second (right) if (a === 'org-chart-view') return -1; @@ -384,6 +384,7 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { // this.#processor.clearSurfaces(); // Removed to allow partial updates this.#processor.processMessages(messages); this.renderVersion++; // Force re-render of surfaces + this.requestUpdate(); const cardSurface = this.#processor.getSurfaces().get('contact-card'); if (cardSurface) { diff --git a/samples/client/lit/contact/ui/custom-components/register-components.ts b/samples/client/lit/contact/ui/custom-components/register-components.ts index fa0cefcf2..f8c11da89 100644 --- a/samples/client/lit/contact/ui/custom-components/register-components.ts +++ b/samples/client/lit/contact/ui/custom-components/register-components.ts @@ -26,17 +26,48 @@ export function registerContactComponents() { type: "object", properties: { chain: { - type: "array", - items: { - type: "object", - properties: { - title: { type: "string" }, - name: { type: "string" }, + type: "object", + properties: { + path: { type: "string" }, + literalArray: { + type: "array", + items: { + type: "object", + properties: { + title: { type: "string" }, + name: { type: "string" }, + }, + required: ["title", "name"], + }, + }, + }, + }, + action: { + type: "object", + properties: { + name: { type: "string" }, + context: { + type: "array", + items: { + type: "object", + properties: { + key: { type: "string" }, + value: { + type: "object", + properties: { + path: { type: "string" }, + literalString: { type: "string" }, + literalNumber: { type: "number" }, + literalBoolean: { type: "boolean" }, + }, + }, + }, + required: ["key", "value"], + }, }, - required: ["title", "name"], }, + required: ["name"], }, - action: { $ref: "#/definitions/Action" }, }, required: ["chain"], }); From 6c53d2021f04a10f20ca0d83739a750e31a7a66f Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Thu, 12 Mar 2026 10:50:55 -0700 Subject: [PATCH 13/19] Fix f-string curly brace escaping in prompt_builder.py --- samples/agent/adk/contact_multiple_surfaces/prompt_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py index ddd383b07..7064760eb 100644 --- a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py +++ b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py @@ -39,7 +39,7 @@ def get_ui_description() -> str: a. You MUST call the `get_contact_info` tool. b. If the tool returns a **single contact**, you MUST use the `MULTI_SURFACE_EXAMPLE` template. Provide BOTH the Contact Card and the Org Chart in a single response. c. If the tool returns **multiple contacts**, you MUST use the `CONTACT_LIST_EXAMPLE` template. Populate the `dataModelUpdate.contents` with the list of contacts for the "contacts" key. - d. If the tool returns an **empty list**, respond with text only and an empty JSON list: "I couldn't find anyone by that name.{{A2UI_OPEN_TAG}}[]{{A2UI_CLOSE_TAG}}" + d. If the tool returns an **empty list**, respond with text only and an empty JSON list: "I couldn't find anyone by that name.{A2UI_OPEN_TAG}[]{A2UI_CLOSE_TAG}" - **For handling a profile view (e.g., "WHO_IS: Alex Jordan..."):** a. You MUST call the `get_contact_info` tool with the specific name. From 776fa4d3582b21a0707e7e41af5ada54c0cceb79 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:06:56 -0700 Subject: [PATCH 14/19] Fix LLM prompt for chart_node_click missing context to extract name --- .../agent/adk/contact_multiple_surfaces/prompt_builder.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py index 7064760eb..2f0c81921 100644 --- a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py +++ b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py @@ -51,6 +51,11 @@ def get_ui_description() -> str: - **For generating the Org Chart (`org-chart-view` dataModelUpdate or title Text):** a. You MUST set any title referring to the Organizational Chart to exactly "Organizational Chart {title_suffix}". + +- **For handling a chart node click (e.g., "ACTION: chart_node_click..." with context):** + a. Extract the `clickedNodeName` from the context JSON. + b. You MUST call the `get_contact_info` tool with that name. + c. Use the `MULTI_SURFACE_EXAMPLE` template or `CHART_NODE_CLICK_EXAMPLE` to update the UI with the newly selected contact's details. """ From 6bf48688e525c81788d1771933f3a96f6b8f602c Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Thu, 12 Mar 2026 19:41:37 -0700 Subject: [PATCH 15/19] Address remaining PR #748 comments - Extract location action logic in ContactAgent.stream into _handle_action - Provide code comments clarifying action intent for UI surfaces - Extract location-surface into LOCATION_SURFACE_ID constant - Rename McpAppsCustomComponent to McpApp --- .../a2ui_examples.py | 12 +- .../adk/contact_multiple_surfaces/agent.py | 165 +++++++++--------- .../prompt_builder.py | 16 +- .../custom-components/mcp-apps-component.ts | 4 +- .../custom-components/register-components.ts | 6 +- 5 files changed, 100 insertions(+), 103 deletions(-) diff --git a/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py b/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py index 9ca824f57..4b0bd11e6 100644 --- a/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py +++ b/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py @@ -32,21 +32,23 @@ } FLOOR_PLAN_FILE = "floor_plan.json" +LOCATION_SURFACE_ID = "location-surface" def load_floor_plan_example(html_content: str = "") -> list[dict]: """Constructs the JSON for the location surface displaying the floor plan.""" import os + title_suffix = "(MCP Apps)" if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true" else "(iFrame)" return [ { "beginRendering": { - "surfaceId": "location-surface", + "surfaceId": LOCATION_SURFACE_ID, "root": "floor-plan-card", } }, { "surfaceUpdate": { - "surfaceId": "location-surface", + "surfaceId": LOCATION_SURFACE_ID, "components": [ { "id": "floor-plan-card", @@ -71,14 +73,14 @@ def load_floor_plan_example(html_content: str = "") -> list[dict]: "component": { "Text": { "usageHint": "h2", - "text": {"literalString": "Office Floor Plan"}, + "text": {"literalString": f"Office Floor Plan {title_suffix}"}, } }, }, { "id": "floor-plan-comp", "component": { - "McpAppsCustomComponent": { + "McpApp": { "htmlContent": html_content, "height": 400, "allowedTools": ["chart_node_click"], @@ -115,7 +117,7 @@ def load_floor_plan_example(html_content: str = "") -> list[dict]: def load_close_modal_example() -> list[dict]: """Constructs the JSON for closing the floor plan modal.""" - return [{"deleteSurface": {"surfaceId": "location-surface"}}] + return [{"deleteSurface": {"surfaceId": LOCATION_SURFACE_ID}}] def load_send_message_example(contact_name: str) -> str: """Constructs the JSON string for the send message confirmation.""" diff --git a/samples/agent/adk/contact_multiple_surfaces/agent.py b/samples/agent/adk/contact_multiple_surfaces/agent.py index 270506c39..36376d8cd 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent.py @@ -40,7 +40,7 @@ get_text_prompt, ROLE_DESCRIPTION, WORKFLOW_DESCRIPTION, - get_ui_description, + UI_DESCRIPTION, ) from tools import get_contact_info from a2ui.core.schema.constants import VERSION_0_8, A2UI_OPEN_TAG, A2UI_CLOSE_TAG @@ -128,7 +128,7 @@ def _build_agent(self, use_ui: bool) -> LlmAgent: self.schema_manager.generate_system_prompt( role_description=ROLE_DESCRIPTION, workflow_description=WORKFLOW_DESCRIPTION, - ui_description=get_ui_description(), + ui_description=UI_DESCRIPTION, include_examples=True, include_schema=True, validate_examples=False, # Missing inline_catalogs for OrgChart and WebFrame validation @@ -145,6 +145,87 @@ def _build_agent(self, use_ui: bool) -> LlmAgent: tools=[get_contact_info], ) + async def _handle_action(self, query: str) -> dict[str, Any] | None: + """Handles simulated UI actions like close_modal or view_location.""" + if not query.startswith("ACTION:"): + return None + + from a2ui_examples import load_floor_plan_example, load_close_modal_example, load_send_message_example + + if "send_message" in query: + logger.info("--- ContactAgent.stream: Detected send_message ACTION ---") + contact_name = "Unknown" + if "(contact:" in query: + try: + contact_name = query.split("(contact:")[1].split(")")[0].strip() + except Exception: + pass + json_content = load_send_message_example(contact_name) + final_response_content = ( + f"Message sent to {contact_name}\n" + f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" + ) + + return { + "is_task_complete": True, + "parts": parse_response_to_parts(final_response_content), + } + + elif "view_location" in query: + logger.info("--- ContactAgent.stream: Detected view_location ACTION ---") + # Action maps to opening the FloorPlan overlay to view the contact's location + from mcp import ClientSession + from mcp.client.sse import sse_client + import os + + sse_url = os.environ.get("FLOOR_PLAN_SERVER_URL", "http://127.0.0.1:8000/sse") + try: + async with sse_client(sse_url) as (read, write): + async with ClientSession(read, write) as mcp_session: + await mcp_session.initialize() + logger.info("--- ContactAgent: Fetching ui://floor-plan-server/map from persistent SSE server ---") + result = await mcp_session.read_resource("ui://floor-plan-server/map") + + if not result.contents or len(result.contents) == 0: + raise ValueError("No content returned from floor plan server") + html_content = result.contents[0].text + except Exception as e: + logger.error(f"Failed to fetch floor plan: {e}") + return { + "is_task_complete": True, + "parts": parse_response_to_parts(f"Failed to load floor plan data: {str(e)}") + } + + json_content = json.dumps(load_floor_plan_example(html_content)) + logger.info(f"--- ContactAgent.stream: Sending Floor Plan ---") + + final_response_content = ( + "Here is the floor plan.\n" + f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" + ) + + return { + "is_task_complete": True, + "parts": parse_response_to_parts(final_response_content) + } + + elif "close_modal" in query: + logger.info("--- ContactAgent.stream: Handling close_modal ACTION ---") + # Action maps to closing the FloorPlan overlay + json_content = json.dumps(load_close_modal_example()) + + final_response_content = ( + "Modal closed.\n" + f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" + ) + + return { + "is_task_complete": True, + "parts": parse_response_to_parts(final_response_content) + } + + return None + async def stream(self, query, session_id, client_ui_capabilities: dict[str, Any] | None = None) -> AsyncIterable[dict[str, Any]]: session_state = {"base_url": self.base_url} @@ -193,82 +274,10 @@ async def stream(self, query, session_id, client_ui_capabilities: dict[str, Any] logger.info(f"--- ContactAgent.stream: Received query: '{query}' ---") # --- Check for User Action --- - # If the query looks like an action (starts with "ACTION:"), parsing it to see which action - if query.startswith("ACTION:"): - from a2ui_examples import load_floor_plan_example, load_close_modal_example, load_send_message_example - - if "send_message" in query: - logger.info("--- ContactAgent.stream: Detected send_message ACTION ---") - contact_name = "Unknown" - if "(contact:" in query: - try: - contact_name = query.split("(contact:")[1].split(")")[0].strip() - except Exception: - pass - json_content = load_send_message_example(contact_name) - final_response_content = ( - f"Message sent to {contact_name}\n" - f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" - ) - - final_parts = parse_response_to_parts(final_response_content) - - yield { - "is_task_complete": True, - "parts": final_parts, - } - return - - elif "view_location" in query: - logger.info("--- ContactAgent.stream: Detected view_location ACTION ---") - # Action maps to opening the FloorPlan overlay to view the contact's location - from mcp import ClientSession - from mcp.client.sse import sse_client - import os - - sse_url = os.environ.get("FLOOR_PLAN_SERVER_URL", "http://127.0.0.1:8000/sse") - try: - async with sse_client(sse_url) as (read, write): - async with ClientSession(read, write) as mcp_session: - await mcp_session.initialize() - logger.info("--- ContactAgent: Fetching ui://floor-plan-server/map from persistent SSE server ---") - result = await mcp_session.read_resource("ui://floor-plan-server/map") - - if not result.contents or len(result.contents) == 0: - raise ValueError("No content returned from floor plan server") - html_content = result.contents[0].text - except Exception as e: - logger.error(f"Failed to fetch floor plan: {e}") - yield {"is_task_complete": True, "parts": parse_response_to_parts(f"Failed to load floor plan data: {str(e)}")} - return - - json_content = json.dumps(load_floor_plan_example(html_content)) - logger.info(f"--- ContactAgent.stream: Sending Floor Plan ---") - - final_response_content = ( - "Here is the floor plan.\n" - f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" - ) - - final_parts = parse_response_to_parts(final_response_content) - - yield {"is_task_complete": True, "parts": final_parts} - return - - elif "close_modal" in query: - logger.info("--- ContactAgent.stream: Handling close_modal ACTION ---") - # Action maps to closing the FloorPlan overlay - json_content = json.dumps(load_close_modal_example()) - - final_response_content = ( - "Modal closed.\n" - f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" - ) - - final_parts = parse_response_to_parts(final_response_content) - - yield {"is_task_complete": True, "parts": final_parts} - return + action_response = await self._handle_action(query) + if action_response: + yield action_response + return current_message = types.Content( role="user", parts=[types.Part.from_text(text=current_query_text)] diff --git a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py index 2f0c81921..8bc8cbeb0 100644 --- a/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py +++ b/samples/agent/adk/contact_multiple_surfaces/prompt_builder.py @@ -28,13 +28,7 @@ Buttons that represent the main action on a card or view (e.g., 'Follow', 'Email', 'Search') SHOULD include the `"primary": true` attribute. """ -def get_ui_description() -> str: - import os - title_suffix = "(iFrame)" - if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true": - title_suffix = "(MCP Apps)" - - return f""" +UI_DESCRIPTION = f""" - **For finding contacts (e.g., "Who is Alex Jordan?"):** a. You MUST call the `get_contact_info` tool. b. If the tool returns a **single contact**, you MUST use the `MULTI_SURFACE_EXAMPLE` template. Provide BOTH the Contact Card and the Org Chart in a single response. @@ -48,14 +42,6 @@ def get_ui_description() -> str: - **For handling actions (e.g., "USER_WANTS_TO_EMAIL: ..."):** a. You MUST use the `ACTION_CONFIRMATION_EXAMPLE` template. b. Populate the `dataModelUpdate.contents` with a confirmation title and message (e.g., title: "Email Drafted", message: "Drafting an email to Alex Jordan..."). - -- **For generating the Org Chart (`org-chart-view` dataModelUpdate or title Text):** - a. You MUST set any title referring to the Organizational Chart to exactly "Organizational Chart {title_suffix}". - -- **For handling a chart node click (e.g., "ACTION: chart_node_click..." with context):** - a. Extract the `clickedNodeName` from the context JSON. - b. You MUST call the `get_contact_info` tool with that name. - c. Use the `MULTI_SURFACE_EXAMPLE` template or `CHART_NODE_CLICK_EXAMPLE` to update the UI with the newly selected contact's details. """ diff --git a/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts index 6c8d16342..db9e6d488 100644 --- a/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts +++ b/samples/client/lit/contact/ui/custom-components/mcp-apps-component.ts @@ -22,7 +22,7 @@ import { AppBridge, PostMessageTransport } from "@modelcontextprotocol/ext-apps/ import type { McpUiSandboxProxyReadyNotification } from "@modelcontextprotocol/ext-apps/app-bridge"; @customElement("a2ui-mcp-apps-component") -export class McpAppsCustomComponent extends Root { +export class McpApp extends Root { static override styles = [ ...Root.styles, css` @@ -143,7 +143,7 @@ export class McpAppsCustomComponent extends Root { this.dispatchAgentAction(actionName, args); return { content: [{ type: "text", text: "Action dispatched to A2UI Agent" }] }; } else { - console.warn(`[McpAppsCustomComponent] Tool '${actionName}' blocked.`); + console.warn(`[McpApp] Tool '${actionName}' blocked.`); throw new Error("Tool not allowed"); } }; diff --git a/samples/client/lit/contact/ui/custom-components/register-components.ts b/samples/client/lit/contact/ui/custom-components/register-components.ts index f8c11da89..71ffe4da0 100644 --- a/samples/client/lit/contact/ui/custom-components/register-components.ts +++ b/samples/client/lit/contact/ui/custom-components/register-components.ts @@ -18,7 +18,7 @@ import { componentRegistry } from "@a2ui/lit/ui"; import { OrgChart } from "./org-chart.js"; import { WebFrame } from "./web-frame.js"; import { PremiumTextField } from "./premium-text-field.js"; -import { McpAppsCustomComponent } from "./mcp-apps-component.js"; +import { McpApp } from "./mcp-apps-component.js"; export function registerContactComponents() { // Register OrgChart @@ -79,8 +79,8 @@ export function registerContactComponents() { "premium-text-field" ); - // Register McpAppsCustomComponent - componentRegistry.register("McpAppsCustomComponent", McpAppsCustomComponent, "a2ui-mcp-apps-component", { + // Register McpApp + componentRegistry.register("McpApp", McpApp, "a2ui-mcp-apps-component", { type: "object", properties: { resourceUri: { type: "string" }, From 441f2821d7891bc2c786b5523b2e96e84383b46e Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:49:58 -0700 Subject: [PATCH 16/19] Auto-format python code and add missing Apache license headers --- .../src/a2ui/core/schema/common_modifiers.py | 6 +- .../python/src/a2ui/core/schema/manager.py | 2 +- .../python/src/a2ui/core/schema/utils.py | 1 - .../python/src/a2ui/core/schema/validator.py | 4 +- .../tests/core/schema/test_validator.py | 30 +- .../tests/integration/verify_load_real.py | 744 +++++----- docs/scripts/convert_docs.py | 51 +- docs/scripts/test_convert_docs.py | 50 +- .../agent/adk/component_gallery/__main__.py | 126 +- samples/agent/adk/component_gallery/agent.py | 136 +- .../adk/component_gallery/agent_executor.py | 70 +- .../adk/component_gallery/gallery_examples.py | 964 ++++++------ samples/agent/adk/contact_lookup/__main__.py | 80 +- samples/agent/adk/contact_lookup/agent.py | 562 +++---- .../adk/contact_lookup/agent_executor.py | 250 ++-- .../adk/contact_lookup/prompt_builder.py | 42 +- samples/agent/adk/contact_lookup/tools.py | 72 +- .../a2ui_examples.py | 48 +- .../adk/contact_multiple_surfaces/agent.py | 44 +- .../floor_plan_server.py | 15 + .../floor_plan_template.html | 15 + samples/agent/adk/orchestrator/__main__.py | 82 +- samples/agent/adk/orchestrator/agent.py | 385 ++--- .../agent/adk/orchestrator/agent_executor.py | 218 +-- .../agent/adk/orchestrator/part_converters.py | 52 +- .../orchestrator/subagent_route_manager.py | 82 +- .../agent/adk/restaurant_finder/__main__.py | 76 +- samples/agent/adk/restaurant_finder/agent.py | 526 +++---- .../adk/restaurant_finder/agent_executor.py | 252 ++-- .../adk/restaurant_finder/prompt_builder.py | 52 +- samples/agent/adk/restaurant_finder/tools.py | 66 +- samples/agent/adk/rizzcharts/__main__.py | 158 +- samples/agent/adk/rizzcharts/agent.py | 241 +-- .../agent/adk/rizzcharts/agent_executor.py | 156 +- samples/agent/adk/rizzcharts/tools.py | 154 +- samples/agent/mcp/server.py | 254 ++-- samples/client/lit/contact/sandbox.html | 15 + samples/client/lit/contact/ui/sandbox.ts | 16 + samples/personalized_learning/agent/agent.py | 24 +- .../agent/download_openstax.py | 8 +- .../agent/openstax_chapters.py | 171 ++- .../agent/openstax_content.py | 67 +- .../agent/openstax_modules.py | 1302 +++++++++++++---- samples/personalized_learning/deploy.py | 630 ++++++-- .../personalized_learning/deploy_hosting.py | 312 ++-- specification/scripts/validate.py | 100 +- specification/v0_10/test/run_tests.py | 56 +- specification/v0_9/test/run_tests.py | 57 +- tools/build_catalog/build_catalog.py | 94 +- .../build_catalog/tests/test_build_catalog.py | 132 +- 50 files changed, 5377 insertions(+), 3673 deletions(-) diff --git a/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py b/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py index 36a5a3a33..1f29c2366 100644 --- a/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py +++ b/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py @@ -17,10 +17,10 @@ def remove_strict_validation(schema): if isinstance(schema, dict): new_schema = {k: remove_strict_validation(v) for k, v in schema.items()} if ( - 'additionalProperties' in new_schema - and new_schema['additionalProperties'] is False + "additionalProperties" in new_schema + and new_schema["additionalProperties"] is False ): - del new_schema['additionalProperties'] + del new_schema["additionalProperties"] return new_schema elif isinstance(schema, list): return [remove_strict_validation(item) for item in schema] diff --git a/agent_sdks/python/src/a2ui/core/schema/manager.py b/agent_sdks/python/src/a2ui/core/schema/manager.py index 1a012f3b4..97e9eefd4 100644 --- a/agent_sdks/python/src/a2ui/core/schema/manager.py +++ b/agent_sdks/python/src/a2ui/core/schema/manager.py @@ -146,7 +146,7 @@ def _select_catalog( # Load the first inline catalog schema. inline_catalog_schema = inline_catalogs[0] inline_catalog_schema = self._apply_modifiers(inline_catalog_schema) - + # Deep merge the standard catalog properties with the inline catalog merged_schema = copy.deepcopy(self._supported_catalogs[0].catalog_schema) deep_update(merged_schema, inline_catalog_schema) diff --git a/agent_sdks/python/src/a2ui/core/schema/utils.py b/agent_sdks/python/src/a2ui/core/schema/utils.py index 1f35015d9..193a289c0 100644 --- a/agent_sdks/python/src/a2ui/core/schema/utils.py +++ b/agent_sdks/python/src/a2ui/core/schema/utils.py @@ -127,4 +127,3 @@ def deep_update(d: dict, u: dict) -> dict: else: d[k] = v return d - diff --git a/agent_sdks/python/src/a2ui/core/schema/validator.py b/agent_sdks/python/src/a2ui/core/schema/validator.py index 54696859c..f06b89da2 100644 --- a/agent_sdks/python/src/a2ui/core/schema/validator.py +++ b/agent_sdks/python/src/a2ui/core/schema/validator.py @@ -298,7 +298,9 @@ def validate(self, a2ui_json: Union[Dict[str, Any], List[Any]]) -> None: _validate_recursion_and_paths(message) -def _find_root_id(messages: List[Dict[str, Any]], surface_id: Optional[str] = None) -> Optional[str]: +def _find_root_id( + messages: List[Dict[str, Any]], surface_id: Optional[str] = None +) -> Optional[str]: """ Finds the root id from a list of A2UI messages for a given surface. - For v0.8, the root id is in the beginRendering message. diff --git a/agent_sdks/python/tests/core/schema/test_validator.py b/agent_sdks/python/tests/core/schema/test_validator.py index d46d093fa..9a05668cb 100644 --- a/agent_sdks/python/tests/core/schema/test_validator.py +++ b/agent_sdks/python/tests/core/schema/test_validator.py @@ -48,7 +48,10 @@ def catalog_0_9(self): "catalogId": { "type": "string", }, - "theme": {"type": "object", "additionalProperties": True}, + "theme": { + "type": "object", + "additionalProperties": True, + }, }, "required": ["surfaceId", "catalogId"], "additionalProperties": False, @@ -495,7 +498,10 @@ def test_custom_catalog_0_8(self, catalog_0_8): "children": { "type": "object", "properties": { - "explicitList": {"type": "array", "items": {"type": "string"}} + "explicitList": { + "type": "array", + "items": {"type": "string"}, + } }, "required": ["explicitList"], } @@ -724,23 +730,35 @@ def make_payload(self, catalog, components=None, data_model=None): if catalog.version == VERSION_0_8: payload = { - "surfaceUpdate": {"surfaceId": "test-surface", "components": processed} + "surfaceUpdate": { + "surfaceId": "test-surface", + "components": processed, + } } else: payload = { "version": "v0.9", - "updateComponents": {"surfaceId": "test-surface", "components": processed}, + "updateComponents": { + "surfaceId": "test-surface", + "components": processed, + }, } elif data_model: if catalog.version == VERSION_0_8: payload = { - "dataModelUpdate": {"surfaceId": "test-surface", "contents": data_model} + "dataModelUpdate": { + "surfaceId": "test-surface", + "contents": data_model, + } } else: payload = { "version": "v0.9", - "updateDataModel": {"surfaceId": "test-surface", "value": data_model}, + "updateDataModel": { + "surfaceId": "test-surface", + "value": data_model, + }, } if payload is None: diff --git a/agent_sdks/python/tests/integration/verify_load_real.py b/agent_sdks/python/tests/integration/verify_load_real.py index f4dcdb95a..18a9e33b3 100644 --- a/agent_sdks/python/tests/integration/verify_load_real.py +++ b/agent_sdks/python/tests/integration/verify_load_real.py @@ -21,7 +21,7 @@ def verify(): - print('Verifying A2uiSchemaManager...') + print("Verifying A2uiSchemaManager...") try: manager = A2uiSchemaManager( version=VERSION_0_8, @@ -30,351 +30,363 @@ def verify(): ) catalog = manager.get_selected_catalog() catalog_components = catalog.catalog_schema[CATALOG_COMPONENTS_KEY] - print(f'Successfully loaded {VERSION_0_8}: {len(catalog_components)} components') - print(f'Components found: {list(catalog_components.keys())[:5]}...') + print(f"Successfully loaded {VERSION_0_8}: {len(catalog_components)} components") + print(f"Components found: {list(catalog_components.keys())[:5]}...") a2ui_message = [ - {'beginRendering': {'surfaceId': 'contact-card', 'root': 'main_card'}}, + {"beginRendering": {"surfaceId": "contact-card", "root": "main_card"}}, { - 'surfaceUpdate': { - 'surfaceId': 'contact-card', - 'components': [ - { - 'id': 'profile_image', - 'component': { - 'Image': { - 'url': {'path': '/imageUrl'}, - 'usageHint': 'avatar', - 'fit': 'cover', + "surfaceUpdate": { + "surfaceId": "contact-card", + "components": [ + { + "id": "profile_image", + "component": { + "Image": { + "url": {"path": "/imageUrl"}, + "usageHint": "avatar", + "fit": "cover", } }, }, { - 'id': 'user_heading', - 'weight': 1, - 'component': { - 'Text': {'text': {'path': '/name'}, 'usageHint': 'h2'} + "id": "user_heading", + "weight": 1, + "component": { + "Text": {"text": {"path": "/name"}, "usageHint": "h2"} }, }, { - 'id': 'description_text_1', - 'component': {'Text': {'text': {'path': '/title'}}}, + "id": "description_text_1", + "component": {"Text": {"text": {"path": "/title"}}}, }, { - 'id': 'description_text_2', - 'component': {'Text': {'text': {'path': '/team'}}}, + "id": "description_text_2", + "component": {"Text": {"text": {"path": "/team"}}}, }, { - 'id': 'description_column', - 'component': { - 'Column': { - 'children': { - 'explicitList': [ - 'user_heading', - 'description_text_1', - 'description_text_2', + "id": "description_column", + "component": { + "Column": { + "children": { + "explicitList": [ + "user_heading", + "description_text_1", + "description_text_2", ] }, - 'alignment': 'center', + "alignment": "center", } }, }, { - 'id': 'calendar_icon', - 'component': { - 'Icon': {'name': {'literalString': 'calendarToday'}} + "id": "calendar_icon", + "component": { + "Icon": {"name": {"literalString": "calendarToday"}} }, }, { - 'id': 'calendar_primary_text', - 'component': { - 'Text': {'usageHint': 'h5', 'text': {'path': '/calendar'}} + "id": "calendar_primary_text", + "component": { + "Text": { + "usageHint": "h5", + "text": {"path": "/calendar"}, + } }, }, { - 'id': 'calendar_secondary_text', - 'component': {'Text': {'text': {'literalString': 'Calendar'}}}, + "id": "calendar_secondary_text", + "component": {"Text": {"text": {"literalString": "Calendar"}}}, }, { - 'id': 'calendar_text_column', - 'component': { - 'Column': { - 'children': { - 'explicitList': [ - 'calendar_primary_text', - 'calendar_secondary_text', + "id": "calendar_text_column", + "component": { + "Column": { + "children": { + "explicitList": [ + "calendar_primary_text", + "calendar_secondary_text", ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, { - 'id': 'info_row_1', - 'component': { - 'Row': { - 'children': { - 'explicitList': [ - 'calendar_icon', - 'calendar_text_column', + "id": "info_row_1", + "component": { + "Row": { + "children": { + "explicitList": [ + "calendar_icon", + "calendar_text_column", ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, { - 'id': 'location_icon', - 'component': { - 'Icon': {'name': {'literalString': 'locationOn'}} + "id": "location_icon", + "component": { + "Icon": {"name": {"literalString": "locationOn"}} }, }, { - 'id': 'location_primary_text', - 'component': { - 'Text': {'usageHint': 'h5', 'text': {'path': '/location'}} + "id": "location_primary_text", + "component": { + "Text": { + "usageHint": "h5", + "text": {"path": "/location"}, + } }, }, { - 'id': 'location_secondary_text', - 'component': {'Text': {'text': {'literalString': 'Location'}}}, + "id": "location_secondary_text", + "component": {"Text": {"text": {"literalString": "Location"}}}, }, { - 'id': 'location_text_column', - 'component': { - 'Column': { - 'children': { - 'explicitList': [ - 'location_primary_text', - 'location_secondary_text', + "id": "location_text_column", + "component": { + "Column": { + "children": { + "explicitList": [ + "location_primary_text", + "location_secondary_text", ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, { - 'id': 'info_row_2', - 'component': { - 'Row': { - 'children': { - 'explicitList': [ - 'location_icon', - 'location_text_column', + "id": "info_row_2", + "component": { + "Row": { + "children": { + "explicitList": [ + "location_icon", + "location_text_column", ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, { - 'id': 'mail_icon', - 'component': {'Icon': {'name': {'literalString': 'mail'}}}, + "id": "mail_icon", + "component": {"Icon": {"name": {"literalString": "mail"}}}, }, { - 'id': 'mail_primary_text', - 'component': { - 'Text': {'usageHint': 'h5', 'text': {'path': '/email'}} + "id": "mail_primary_text", + "component": { + "Text": {"usageHint": "h5", "text": {"path": "/email"}} }, }, { - 'id': 'mail_secondary_text', - 'component': {'Text': {'text': {'literalString': 'Email'}}}, + "id": "mail_secondary_text", + "component": {"Text": {"text": {"literalString": "Email"}}}, }, { - 'id': 'mail_text_column', - 'component': { - 'Column': { - 'children': { - 'explicitList': [ - 'mail_primary_text', - 'mail_secondary_text', + "id": "mail_text_column", + "component": { + "Column": { + "children": { + "explicitList": [ + "mail_primary_text", + "mail_secondary_text", ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, { - 'id': 'info_row_3', - 'component': { - 'Row': { - 'children': { - 'explicitList': ['mail_icon', 'mail_text_column'] + "id": "info_row_3", + "component": { + "Row": { + "children": { + "explicitList": [ + "mail_icon", + "mail_text_column", + ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, - {'id': 'div', 'component': {'Divider': {}}}, + {"id": "div", "component": {"Divider": {}}}, { - 'id': 'call_icon', - 'component': {'Icon': {'name': {'literalString': 'call'}}}, + "id": "call_icon", + "component": {"Icon": {"name": {"literalString": "call"}}}, }, { - 'id': 'call_primary_text', - 'component': { - 'Text': {'usageHint': 'h5', 'text': {'path': '/mobile'}} + "id": "call_primary_text", + "component": { + "Text": {"usageHint": "h5", "text": {"path": "/mobile"}} }, }, { - 'id': 'call_secondary_text', - 'component': {'Text': {'text': {'literalString': 'Mobile'}}}, + "id": "call_secondary_text", + "component": {"Text": {"text": {"literalString": "Mobile"}}}, }, { - 'id': 'call_text_column', - 'component': { - 'Column': { - 'children': { - 'explicitList': [ - 'call_primary_text', - 'call_secondary_text', + "id": "call_text_column", + "component": { + "Column": { + "children": { + "explicitList": [ + "call_primary_text", + "call_secondary_text", ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, { - 'id': 'info_row_4', - 'component': { - 'Row': { - 'children': { - 'explicitList': ['call_icon', 'call_text_column'] + "id": "info_row_4", + "component": { + "Row": { + "children": { + "explicitList": [ + "call_icon", + "call_text_column", + ] }, - 'distribution': 'start', - 'alignment': 'start', + "distribution": "start", + "alignment": "start", } }, }, { - 'id': 'info_rows_column', - 'weight': 1, - 'component': { - 'Column': { - 'children': { - 'explicitList': [ - 'info_row_1', - 'info_row_2', - 'info_row_3', - 'info_row_4', + "id": "info_rows_column", + "weight": 1, + "component": { + "Column": { + "children": { + "explicitList": [ + "info_row_1", + "info_row_2", + "info_row_3", + "info_row_4", ] }, - 'alignment': 'stretch', + "alignment": "stretch", } }, }, { - 'id': 'button_1_text', - 'component': {'Text': {'text': {'literalString': 'Follow'}}}, + "id": "button_1_text", + "component": {"Text": {"text": {"literalString": "Follow"}}}, }, { - 'id': 'button_1', - 'component': { - 'Button': { - 'child': 'button_1_text', - 'primary': True, - 'action': {'name': 'follow_contact'}, + "id": "button_1", + "component": { + "Button": { + "child": "button_1_text", + "primary": True, + "action": {"name": "follow_contact"}, } }, }, { - 'id': 'button_2_text', - 'component': {'Text': {'text': {'literalString': 'Message'}}}, + "id": "button_2_text", + "component": {"Text": {"text": {"literalString": "Message"}}}, }, { - 'id': 'button_2', - 'component': { - 'Button': { - 'child': 'button_2_text', - 'primary': False, - 'action': {'name': 'send_message'}, + "id": "button_2", + "component": { + "Button": { + "child": "button_2_text", + "primary": False, + "action": {"name": "send_message"}, } }, }, { - 'id': 'action_buttons_row', - 'component': { - 'Row': { - 'children': {'explicitList': ['button_1', 'button_2']}, - 'distribution': 'center', - 'alignment': 'center', + "id": "action_buttons_row", + "component": { + "Row": { + "children": {"explicitList": ["button_1", "button_2"]}, + "distribution": "center", + "alignment": "center", } }, }, { - 'id': 'link_text', - 'component': { - 'Text': { - 'text': { - 'literalString': '[View Full Profile](/profile)' + "id": "link_text", + "component": { + "Text": { + "text": { + "literalString": "[View Full Profile](/profile)" } } }, }, { - 'id': 'link_text_wrapper', - 'component': { - 'Row': { - 'children': {'explicitList': ['link_text']}, - 'distribution': 'center', - 'alignment': 'center', + "id": "link_text_wrapper", + "component": { + "Row": { + "children": {"explicitList": ["link_text"]}, + "distribution": "center", + "alignment": "center", } }, }, { - 'id': 'main_column', - 'component': { - 'Column': { - 'children': { - 'explicitList': [ - 'profile_image', - 'description_column', - 'div', - 'info_rows_column', - 'action_buttons_row', - 'link_text_wrapper', + "id": "main_column", + "component": { + "Column": { + "children": { + "explicitList": [ + "profile_image", + "description_column", + "div", + "info_rows_column", + "action_buttons_row", + "link_text_wrapper", ] }, - 'alignment': 'stretch', + "alignment": "stretch", } }, }, { - 'id': 'main_card', - 'component': {'Card': {'child': 'main_column'}}, + "id": "main_card", + "component": {"Card": {"child": "main_column"}}, }, ], } }, { - 'dataModelUpdate': { - 'surfaceId': 'contact-card', - 'path': '/', - 'contents': [ - {'key': 'name', 'valueString': 'Casey Smith'}, - {'key': 'title', 'valueString': 'Digital Marketing Specialist'}, - {'key': 'team', 'valueString': 'Growth Team'}, - {'key': 'location', 'valueString': 'New York'}, - {'key': 'email', 'valueString': 'casey.smith@example.com'}, - {'key': 'mobile', 'valueString': '+1 (415) 222-3333'}, - {'key': 'calendar', 'valueString': 'In a meeting'}, - { - 'key': 'imageUrl', - 'valueString': 'http://localhost:10003/static/profile2.png', - }, - { - 'key': 'contacts', - 'valueMap': [{ - 'key': 'contact1', - 'valueMap': [{'key': 'name', 'valueString': 'Casey Smith'}], + "dataModelUpdate": { + "surfaceId": "contact-card", + "path": "/", + "contents": [ + {"key": "name", "valueString": "Casey Smith"}, + {"key": "title", "valueString": "Digital Marketing Specialist"}, + {"key": "team", "valueString": "Growth Team"}, + {"key": "location", "valueString": "New York"}, + {"key": "email", "valueString": "casey.smith@example.com"}, + {"key": "mobile", "valueString": "+1 (415) 222-3333"}, + {"key": "calendar", "valueString": "In a meeting"}, + { + "key": "imageUrl", + "valueString": "http://localhost:10003/static/profile2.png", + }, + { + "key": "contacts", + "valueMap": [{ + "key": "contact1", + "valueMap": [{"key": "name", "valueString": "Casey Smith"}], }], }, ], @@ -382,9 +394,9 @@ def verify(): }, ] catalog.validator.validate(a2ui_message) - print('Validation successful') + print("Validation successful") except Exception as e: - print(f'Failed to load {VERSION_0_8}: {e}') + print(f"Failed to load {VERSION_0_8}: {e}") sys.exit(1) try: @@ -395,205 +407,209 @@ def verify(): ) catalog = manager.get_selected_catalog() catalog_components = catalog.catalog_schema[CATALOG_COMPONENTS_KEY] - print(f'Successfully loaded {VERSION_0_9}: {len(catalog_components)} components') - print(f'Components found: {list(catalog_components.keys())}...') + print(f"Successfully loaded {VERSION_0_9}: {len(catalog_components)} components") + print(f"Components found: {list(catalog_components.keys())}...") a2ui_message = [ { - 'version': 'v0.9', - 'createSurface': { - 'surfaceId': 'contact_form_1', - 'catalogId': 'https://a2ui.dev/specification/v0_9/basic_catalog.json', - 'fakeProperty': 'should be allowed', + "version": "v0.9", + "createSurface": { + "surfaceId": "contact_form_1", + "catalogId": "https://a2ui.dev/specification/v0_9/basic_catalog.json", + "fakeProperty": "should be allowed", }, }, { - 'version': 'v0.9', - 'updateComponents': { - 'surfaceId': 'contact_form_1', - 'components': [ - {'id': 'root', 'component': 'Card', 'child': 'form_container'}, - { - 'id': 'form_container', - 'component': 'Column', - 'children': [ - 'header_row', - 'name_row', - 'email_group', - 'phone_group', - 'pref_group', - 'divider_1', - 'newsletter_checkbox', - 'submit_button', + "version": "v0.9", + "updateComponents": { + "surfaceId": "contact_form_1", + "components": [ + {"id": "root", "component": "Card", "child": "form_container"}, + { + "id": "form_container", + "component": "Column", + "children": [ + "header_row", + "name_row", + "email_group", + "phone_group", + "pref_group", + "divider_1", + "newsletter_checkbox", + "submit_button", ], - 'justify': 'start', - 'align': 'stretch', + "justify": "start", + "align": "stretch", }, { - 'id': 'header_row', - 'component': 'Row', - 'children': ['header_icon', 'header_text'], - 'align': 'center', + "id": "header_row", + "component": "Row", + "children": ["header_icon", "header_text"], + "align": "center", }, - {'id': 'header_icon', 'component': 'Icon', 'name': 'mail'}, + {"id": "header_icon", "component": "Icon", "name": "mail"}, { - 'id': 'header_text', - 'component': 'Text', - 'text': '# Contact Us', - 'variant': 'h2', + "id": "header_text", + "component": "Text", + "text": "# Contact Us", + "variant": "h2", }, { - 'id': 'name_row', - 'component': 'Row', - 'children': ['first_name_group', 'last_name_group'], - 'justify': 'spaceBetween', + "id": "name_row", + "component": "Row", + "children": ["first_name_group", "last_name_group"], + "justify": "spaceBetween", }, { - 'id': 'first_name_group', - 'component': 'Column', - 'children': ['first_name_label', 'first_name_field'], - 'weight': 1, + "id": "first_name_group", + "component": "Column", + "children": ["first_name_label", "first_name_field"], + "weight": 1, }, { - 'id': 'first_name_label', - 'component': 'Text', - 'text': 'First Name', - 'variant': 'caption', + "id": "first_name_label", + "component": "Text", + "text": "First Name", + "variant": "caption", }, { - 'id': 'first_name_field', - 'component': 'TextField', - 'label': 'First Name', - 'value': {'path': '/contact/firstName'}, - 'variant': 'shortText', + "id": "first_name_field", + "component": "TextField", + "label": "First Name", + "value": {"path": "/contact/firstName"}, + "variant": "shortText", }, { - 'id': 'last_name_group', - 'component': 'Column', - 'children': ['last_name_label', 'last_name_field'], - 'weight': 1, + "id": "last_name_group", + "component": "Column", + "children": ["last_name_label", "last_name_field"], + "weight": 1, }, { - 'id': 'last_name_label', - 'component': 'Text', - 'text': 'Last Name', - 'variant': 'caption', + "id": "last_name_label", + "component": "Text", + "text": "Last Name", + "variant": "caption", }, { - 'id': 'last_name_field', - 'component': 'TextField', - 'label': 'Last Name', - 'value': {'path': '/contact/lastName'}, - 'variant': 'shortText', + "id": "last_name_field", + "component": "TextField", + "label": "Last Name", + "value": {"path": "/contact/lastName"}, + "variant": "shortText", }, { - 'id': 'email_group', - 'component': 'Column', - 'children': ['email_label', 'email_field'], + "id": "email_group", + "component": "Column", + "children": ["email_label", "email_field"], }, { - 'id': 'email_label', - 'component': 'Text', - 'text': 'Email Address', - 'variant': 'caption', + "id": "email_label", + "component": "Text", + "text": "Email Address", + "variant": "caption", }, { - 'id': 'email_field', - 'component': 'TextField', - 'label': 'Email', - 'value': {'path': '/contact/email'}, - 'variant': 'shortText', - 'checks': [ + "id": "email_field", + "component": "TextField", + "label": "Email", + "value": {"path": "/contact/email"}, + "variant": "shortText", + "checks": [ { - 'condition': { - 'call': 'required', - 'args': {'value': {'path': '/contact/email'}}, + "condition": { + "call": "required", + "args": {"value": {"path": "/contact/email"}}, }, - 'message': 'Email is required.', + "message": "Email is required.", }, { - 'condition': { - 'call': 'email', - 'args': {'value': {'path': '/contact/email'}}, + "condition": { + "call": "email", + "args": {"value": {"path": "/contact/email"}}, }, - 'message': 'Please enter a valid email address.', + "message": "Please enter a valid email address.", }, ], }, { - 'id': 'phone_group', - 'component': 'Column', - 'children': ['phone_label', 'phone_field'], + "id": "phone_group", + "component": "Column", + "children": ["phone_label", "phone_field"], }, { - 'id': 'phone_label', - 'component': 'Text', - 'text': 'Phone Number', - 'variant': 'caption', + "id": "phone_label", + "component": "Text", + "text": "Phone Number", + "variant": "caption", }, { - 'id': 'phone_field', - 'component': 'TextField', - 'label': 'Phone', - 'value': {'path': '/contact/phone'}, - 'variant': 'shortText', - 'checks': [{ - 'condition': { - 'call': 'regex', - 'args': { - 'value': {'path': '/contact/phone'}, - 'pattern': '^\\d{10}$', + "id": "phone_field", + "component": "TextField", + "label": "Phone", + "value": {"path": "/contact/phone"}, + "variant": "shortText", + "checks": [{ + "condition": { + "call": "regex", + "args": { + "value": {"path": "/contact/phone"}, + "pattern": "^\\d{10}$", }, }, - 'message': 'Phone number must be 10 digits.', + "message": "Phone number must be 10 digits.", }], }, { - 'id': 'pref_group', - 'component': 'Column', - 'children': ['pref_label', 'pref_picker'], + "id": "pref_group", + "component": "Column", + "children": ["pref_label", "pref_picker"], }, { - 'id': 'pref_label', - 'component': 'Text', - 'text': 'Preferred Contact Method', - 'variant': 'caption', + "id": "pref_label", + "component": "Text", + "text": "Preferred Contact Method", + "variant": "caption", }, { - 'id': 'pref_picker', - 'component': 'ChoicePicker', - 'variant': 'mutuallyExclusive', - 'options': [ - {'label': 'Email', 'value': 'email'}, - {'label': 'Phone', 'value': 'phone'}, - {'label': 'SMS', 'value': 'sms'}, + "id": "pref_picker", + "component": "ChoicePicker", + "variant": "mutuallyExclusive", + "options": [ + {"label": "Email", "value": "email"}, + {"label": "Phone", "value": "phone"}, + {"label": "SMS", "value": "sms"}, ], - 'value': {'path': '/contact/preference'}, + "value": {"path": "/contact/preference"}, + }, + { + "id": "divider_1", + "component": "Divider", + "axis": "horizontal", }, - {'id': 'divider_1', 'component': 'Divider', 'axis': 'horizontal'}, { - 'id': 'newsletter_checkbox', - 'component': 'CheckBox', - 'label': 'Subscribe to our newsletter', - 'value': {'path': '/contact/subscribe'}, + "id": "newsletter_checkbox", + "component": "CheckBox", + "label": "Subscribe to our newsletter", + "value": {"path": "/contact/subscribe"}, }, { - 'id': 'submit_button_label', - 'component': 'Text', - 'text': 'Send Message', + "id": "submit_button_label", + "component": "Text", + "text": "Send Message", }, { - 'id': 'submit_button', - 'component': 'Button', - 'child': 'submit_button_label', - 'variant': 'primary', - 'action': { - 'event': { - 'name': 'submitContactForm', - 'context': { - 'formId': 'contact_form_1', - 'isNewsletterSubscribed': { - 'path': '/contact/subscribe' + "id": "submit_button", + "component": "Button", + "child": "submit_button_label", + "variant": "primary", + "action": { + "event": { + "name": "submitContactForm", + "context": { + "formId": "contact_form_1", + "isNewsletterSubscribed": { + "path": "/contact/subscribe" }, }, } @@ -603,28 +619,28 @@ def verify(): }, }, { - 'version': 'v0.9', - 'updateDataModel': { - 'surfaceId': 'contact_form_1', - 'path': '/contact', - 'value': { - 'firstName': 'John', - 'lastName': 'Doe', - 'email': 'john.doe@example.com', - 'phone': '1234567890', - 'preference': ['email'], - 'subscribe': True, + "version": "v0.9", + "updateDataModel": { + "surfaceId": "contact_form_1", + "path": "/contact", + "value": { + "firstName": "John", + "lastName": "Doe", + "email": "john.doe@example.com", + "phone": "1234567890", + "preference": ["email"], + "subscribe": True, }, }, }, - {'version': 'v0.9', 'deleteSurface': {'surfaceId': 'contact_form_1'}}, + {"version": "v0.9", "deleteSurface": {"surfaceId": "contact_form_1"}}, ] catalog.validator.validate(a2ui_message) - print('Validation successful') + print("Validation successful") except Exception as e: - print(f'Failed to load {VERSION_0_9}: {e}') + print(f"Failed to load {VERSION_0_9}: {e}") sys.exit(1) -if __name__ == '__main__': +if __name__ == "__main__": verify() diff --git a/docs/scripts/convert_docs.py b/docs/scripts/convert_docs.py index a82b72ac0..ffdaed7f5 100644 --- a/docs/scripts/convert_docs.py +++ b/docs/scripts/convert_docs.py @@ -17,9 +17,9 @@ import argparse # Registry for bidirectional format conversion: -# +# # Key: The MkDocs admonition type (the target for '!!! type' syntax). -# Value: +# Value: # - emoji: Used for mapping GitHub-style emoji quotes (> ⚠️) to MkDocs. # - tag: Reserved for mapping official GitHub Alert syntax (> [!WARNING]). MAPPING = { @@ -28,17 +28,19 @@ "info": {"emoji": "ℹ️", "tag": "NOTE"}, "success": {"emoji": "✅", "tag": "SUCCESS"}, "danger": {"emoji": "🚫", "tag": "CAUTION"}, - "note": {"emoji": "📝", "tag": "NOTE"} + "note": {"emoji": "📝", "tag": "NOTE"}, } # Reverse lookup: mapping emojis back to their respective MkDocs types EMOJI_TO_TYPE = {v["emoji"]: k for k, v in MAPPING.items()} # Emoji Pattern: Handles optional bold titles and standard emojis -EMOJI_PATTERN = r'>\s*(⚠️|💡|ℹ️|✅|🚫|📝)(?:\s*\*\*(.*?)\*\*)?\s*\n((?:>\s*.*\n?)*)' +EMOJI_PATTERN = r">\s*(⚠️|💡|ℹ️|✅|🚫|📝)(?:\s*\*\*(.*?)\*\*)?\s*\n((?:>\s*.*\n?)*)" # GitHub Alert Pattern [!TYPE] -GITHUB_ALERT_PATTERN = r'>\s*\[\!(WARNING|TIP|NOTE|IMPORTANT|CAUTION)\]\s*\n((?:>\s*.*\n?)*)' +GITHUB_ALERT_PATTERN = ( + r">\s*\[\!(WARNING|TIP|NOTE|IMPORTANT|CAUTION)\]\s*\n((?:>\s*.*\n?)*)" +) # MkDocs Pattern: Captures '!!! type "Title"' blocks MKDOCS_PATTERN = r'!!!\s+(\w+)\s+"(.*?)"\n((?:\s{4}.*\n?)*)' @@ -53,28 +55,29 @@ def clean_body_for_mkdocs(body_text): 4. Preserves internal paragraph breaks. """ # Remove leading '>' and trailing whitespace from each line - raw_lines = [re.sub(r'^>\s?', '', line).rstrip() for line in body_text.split('\n')] - + raw_lines = [re.sub(r"^>\s?", "", line).rstrip() for line in body_text.split("\n")] + # Find the first line with actual text (to strip leading blank lines) start_idx = -1 for i, line in enumerate(raw_lines): if line.strip(): start_idx = i break - + if start_idx == -1: return "" - + # Slice from the first content line content_lines = raw_lines[start_idx:] - + # Join lines and rstrip the entire block to remove trailing blank lines body = "\n".join([f" {l}".rstrip() for l in content_lines]).rstrip() return body + def to_mkdocs(content): """Converts GitHub style to MkDocs style.""" - + def emoji_replacer(match): emoji_char, title, raw_body = match.groups() adm_type = EMOJI_TO_TYPE.get(emoji_char, "note") @@ -83,18 +86,17 @@ def emoji_replacer(match): # Return block with exactly one newline at the end return f'!!! {adm_type} "{title_val}"\n{body}\n' - def alert_replacer(match): alert_type = match.group(1).lower() type_map = {"important": "info", "caution": "danger"} mkdocs_type = type_map.get(alert_type, alert_type) raw_body = match.group(2) - - first_line_match = re.search(r'^>\s*\*\*(.*?)\*\*\s*\n', raw_body) + + first_line_match = re.search(r"^>\s*\*\*(.*?)\*\*\s*\n", raw_body) title = first_line_match.group(1) if first_line_match else "" if first_line_match: - raw_body = raw_body[first_line_match.end():] - + raw_body = raw_body[first_line_match.end() :] + body = clean_body_for_mkdocs(raw_body) return f'!!! {mkdocs_type} "{title}"\n{body}\n' @@ -102,24 +104,29 @@ def alert_replacer(match): content = re.sub(GITHUB_ALERT_PATTERN, alert_replacer, content, flags=re.MULTILINE) return content + def process_file(path): - with open(path, 'r', encoding='utf-8') as f: + with open(path, "r", encoding="utf-8") as f: content = f.read() new_content = to_mkdocs(content) if new_content != content: - with open(path, 'w', encoding='utf-8') as f: + with open(path, "w", encoding="utf-8") as f: f.write(new_content) print(f"[CONVERTED] {path}") + def run_conversion(): - for root, dirs, files in os.walk('docs'): - if any(x in root for x in ['scripts', 'assets', '__pycache__']): + for root, dirs, files in os.walk("docs"): + if any(x in root for x in ["scripts", "assets", "__pycache__"]): continue for file in files: - if file.endswith('.md'): + if file.endswith(".md"): process_file(os.path.join(root, file)) + if __name__ == "__main__": - parser = argparse.ArgumentParser(description="GitHub to MkDocs Markdown Admonition Converter") + parser = argparse.ArgumentParser( + description="GitHub to MkDocs Markdown Admonition Converter" + ) args = parser.parse_args() run_conversion() diff --git a/docs/scripts/test_convert_docs.py b/docs/scripts/test_convert_docs.py index 03bae2d3e..6ab9114ae 100644 --- a/docs/scripts/test_convert_docs.py +++ b/docs/scripts/test_convert_docs.py @@ -18,21 +18,26 @@ # --- 1. A2UI Specific Header Cases --- ADMONITION_CASES = [ ('!!! info "Coming soon..."', "Coming soon...", "ℹ️"), - ('!!! warning "Status: Early Stage Public Preview"', "Status: Early Stage Public Preview", "⚠️"), + ( + '!!! warning "Status: Early Stage Public Preview"', + "Status: Early Stage Public Preview", + "⚠️", + ), ('!!! success "Stable Release"', "Stable Release", "✅"), ('!!! note "Version Compatibility"', "Version Compatibility", "📝"), ('!!! warning "Attention"', "Attention", "⚠️"), ('!!! tip "It\'s Just JSON"', "It's Just JSON", "💡"), ] + @pytest.mark.parametrize("expected_header, title, emoji", ADMONITION_CASES) def test_standard_a2ui_conversion(expected_header, title, emoji): """Verifies that GitHub style converts to expected A2UI headers.""" body = " Line 1\n Line 2" github_input = f"> {emoji} **{title}**\n>\n> Line 1\n> Line 2\n" - + expected = f"{expected_header}\n{body}\n" - + # GitHub -> MkDocs result = to_mkdocs(github_input) assert result.strip() == expected.strip() @@ -45,7 +50,7 @@ def test_empty_title_case(): """ github_input = "> 💡\n>\n> Content.\n" expected = '!!! tip ""\n Content.\n' - + result = to_mkdocs(github_input) assert result == expected @@ -60,22 +65,17 @@ def test_paragraph_spacing_and_trailing_lines(): """ source_github = ( "> ✅ **Stable Release**\n" - ">\n" # Spacer line + ">\n" # Spacer line "> Line 1\n" - ">\n" # Internal break + ">\n" # Internal break "> Line 2\n" - ">\n" # Trailing line 1 - ">\n" # Trailing line 2 + ">\n" # Trailing line 1 + ">\n" # Trailing line 2 ) - + result = to_mkdocs(source_github) - - expected = ( - '!!! success "Stable Release"\n' - ' Line 1\n' - '\n' - ' Line 2\n' - ) + + expected = '!!! success "Stable Release"\n' " Line 1\n" "\n" " Line 2\n" assert result == expected @@ -83,21 +83,17 @@ def test_paragraph_spacing_and_trailing_lines(): def test_multiple_blocks_in_one_file(): """Ensures multiple blocks are processed without bleeding into each other.""" github_input = ( - '> ✅ **Block 1**\n' - '> Content 1\n' - '\n' - '> ℹ️ **Block 2**\n' - '> Content 2\n' + "> ✅ **Block 1**\n" "> Content 1\n" "\n" "> ℹ️ **Block 2**\n" "> Content 2\n" ) - + expected = ( '!!! success "Block 1"\n' - ' Content 1\n' - '\n' + " Content 1\n" + "\n" '!!! info "Block 2"\n' - ' Content 2\n' + " Content 2\n" ) - + result = to_mkdocs(github_input) assert result == expected @@ -114,5 +110,5 @@ def test_github_alert_to_mkdocs(): """Verifies official [!TYPE] syntax conversion.""" source = "> [!WARNING]\n> **Security Notice**\n> Do not share keys." expected = '!!! warning "Security Notice"\n Do not share keys.\n' - + assert to_mkdocs(source) == expected diff --git a/samples/agent/adk/component_gallery/__main__.py b/samples/agent/adk/component_gallery/__main__.py index 050c53446..234c1e0a1 100644 --- a/samples/agent/adk/component_gallery/__main__.py +++ b/samples/agent/adk/component_gallery/__main__.py @@ -48,69 +48,69 @@ @click.option("--host", default="localhost") @click.option("--port", default=10005) def main(host, port): - try: - capabilities = AgentCapabilities( - streaming=True, - extensions=[get_a2ui_agent_extension()], - ) - - # Skill definition - skill = AgentSkill( - id="component_gallery", - name="Component Gallery", - description="Demonstrates A2UI components.", - tags=["gallery", "demo"], - examples=["Show me the gallery"], - ) - - base_url = f"http://{host}:{port}" - - agent_card = AgentCard( - name="Component Gallery Agent", - description="A2UI Component Gallery", - url=base_url, - version="0.0.1", - default_input_modes=["text"], - default_output_modes=["text"], - capabilities=capabilities, - skills=[skill], - ) - - agent_executor = ComponentGalleryExecutor(base_url=base_url) - - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - - server = A2AStarletteApplication( - agent_card=agent_card, http_handler=request_handler - ) - - app = server.build() - - app.add_middleware( - CORSMiddleware, - allow_origins=["http://localhost:5173"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) - - # Mount assets directory - assets_dir = os.path.join(os.path.dirname(__file__), "assets") - if os.path.exists(assets_dir): - app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") - else: - logger.warning(f"Assets directory not found at {assets_dir}") - - print(f"Starting Component Gallery Agent on port {port}...") - uvicorn.run(app, host=host, port=port) - - except Exception as e: - logger.error(f"An error occurred during server startup: {e}") - exit(1) + try: + capabilities = AgentCapabilities( + streaming=True, + extensions=[get_a2ui_agent_extension()], + ) + + # Skill definition + skill = AgentSkill( + id="component_gallery", + name="Component Gallery", + description="Demonstrates A2UI components.", + tags=["gallery", "demo"], + examples=["Show me the gallery"], + ) + + base_url = f"http://{host}:{port}" + + agent_card = AgentCard( + name="Component Gallery Agent", + description="A2UI Component Gallery", + url=base_url, + version="0.0.1", + default_input_modes=["text"], + default_output_modes=["text"], + capabilities=capabilities, + skills=[skill], + ) + + agent_executor = ComponentGalleryExecutor(base_url=base_url) + + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + + server = A2AStarletteApplication( + agent_card=agent_card, http_handler=request_handler + ) + + app = server.build() + + app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:5173"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + # Mount assets directory + assets_dir = os.path.join(os.path.dirname(__file__), "assets") + if os.path.exists(assets_dir): + app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") + else: + logger.warning(f"Assets directory not found at {assets_dir}") + + print(f"Starting Component Gallery Agent on port {port}...") + uvicorn.run(app, host=host, port=port) + + except Exception as e: + logger.error(f"An error occurred during server startup: {e}") + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/component_gallery/agent.py b/samples/agent/adk/component_gallery/agent.py index 855d4d935..4e0d48f51 100644 --- a/samples/agent/adk/component_gallery/agent.py +++ b/samples/agent/adk/component_gallery/agent.py @@ -32,68 +32,74 @@ class ComponentGalleryAgent: - """An agent that displays a component gallery.""" - - def __init__(self, base_url: str): - self.base_url = base_url - - async def stream(self, query: str, session_id: str) -> AsyncIterable[dict[str, Any]]: - """Streams the gallery or responses to actions.""" - - logger.info(f"Stream called with query: {query}") - - # Initial Load or Reset - if "WHO_ARE_YOU" in query or "START" in query: # Simple trigger for initial load - gallery_json = get_gallery_json() - yield { - "is_task_complete": True, - "parts": parse_response_to_parts( - "Here is the component" - f" gallery.\n{A2UI_OPEN_TAG}\n{gallery_json}\n{A2UI_CLOSE_TAG}" - ), - } - return - - # Handle Actions - if query.startswith("ACTION:"): - action_name = query - # Create a response update for the second surface - - # Simulate network/processing delay - await asyncio.sleep(0.5) - - timestamp = datetime.datetime.now().strftime("%H:%M:%S") - - response_update = { - "surfaceUpdate": { - "surfaceId": "response-surface", - "components": [{ - "id": "response-text", - "component": { - "Text": { - "text": { - "literalString": ( - f"Agent Processed Action: {action_name} at" - f" {timestamp}" - ) - } - } - }, - }], - } - } - - yield { - "is_task_complete": True, - "parts": [ - Part(root=TextPart(text="Action processed.")), - create_a2ui_part(response_update), - ], - } - return - - # Fallback for text - yield { - "is_task_complete": True, - "parts": [Part(root=TextPart(text="I am the Component Gallery Agent."))], - } + """An agent that displays a component gallery.""" + + def __init__(self, base_url: str): + self.base_url = base_url + + async def stream( + self, query: str, session_id: str + ) -> AsyncIterable[dict[str, Any]]: + """Streams the gallery or responses to actions.""" + + logger.info(f"Stream called with query: {query}") + + # Initial Load or Reset + if ( + "WHO_ARE_YOU" in query or "START" in query + ): # Simple trigger for initial load + gallery_json = get_gallery_json() + yield { + "is_task_complete": True, + "parts": parse_response_to_parts( + "Here is the component" + f" gallery.\n{A2UI_OPEN_TAG}\n{gallery_json}\n{A2UI_CLOSE_TAG}" + ), + } + return + + # Handle Actions + if query.startswith("ACTION:"): + action_name = query + # Create a response update for the second surface + + # Simulate network/processing delay + await asyncio.sleep(0.5) + + timestamp = datetime.datetime.now().strftime("%H:%M:%S") + + response_update = { + "surfaceUpdate": { + "surfaceId": "response-surface", + "components": [ + { + "id": "response-text", + "component": { + "Text": { + "text": { + "literalString": ( + f"Agent Processed Action: {action_name} at" + f" {timestamp}" + ) + } + } + }, + } + ], + } + } + + yield { + "is_task_complete": True, + "parts": [ + Part(root=TextPart(text="Action processed.")), + create_a2ui_part(response_update), + ], + } + return + + # Fallback for text + yield { + "is_task_complete": True, + "parts": [Part(root=TextPart(text="I am the Component Gallery Agent."))], + } diff --git a/samples/agent/adk/component_gallery/agent_executor.py b/samples/agent/adk/component_gallery/agent_executor.py index d0bed73c7..29a3ec66b 100644 --- a/samples/agent/adk/component_gallery/agent_executor.py +++ b/samples/agent/adk/component_gallery/agent_executor.py @@ -29,47 +29,47 @@ class ComponentGalleryExecutor(AgentExecutor): - def __init__(self, base_url: str): - self.agent = ComponentGalleryAgent(base_url=base_url) + def __init__(self, base_url: str): + self.agent = ComponentGalleryAgent(base_url=base_url) - async def execute(self, context: RequestContext, event_queue: EventQueue) -> None: - query = "START" # Default start - ui_event_part = None + async def execute(self, context: RequestContext, event_queue: EventQueue) -> None: + query = "START" # Default start + ui_event_part = None - try_activate_a2ui_extension(context) + try_activate_a2ui_extension(context) - if context.message and context.message.parts: - for part in context.message.parts: - if isinstance(part.root, DataPart): - if "userAction" in part.root.data: - ui_event_part = part.root.data["userAction"] - elif "request" in part.root.data: - query = part.root.data["request"] - elif isinstance(part.root, TextPart): - # If user says something, might want to handle it, but for now defaults to START usually for initial connection - if part.root.text: - query = part.root.text + if context.message and context.message.parts: + for part in context.message.parts: + if isinstance(part.root, DataPart): + if "userAction" in part.root.data: + ui_event_part = part.root.data["userAction"] + elif "request" in part.root.data: + query = part.root.data["request"] + elif isinstance(part.root, TextPart): + # If user says something, might want to handle it, but for now defaults to START usually for initial connection + if part.root.text: + query = part.root.text - if ui_event_part: - action = ui_event_part.get("name") - ctx = ui_event_part.get("context", {}) - query = f"ACTION: {action} with {ctx}" + if ui_event_part: + action = ui_event_part.get("name") + ctx = ui_event_part.get("context", {}) + query = f"ACTION: {action} with {ctx}" - task = context.current_task - if not task: - task = new_task(context.message) - await event_queue.enqueue_event(task) + task = context.current_task + if not task: + task = new_task(context.message) + await event_queue.enqueue_event(task) - updater = TaskUpdater(event_queue, task.id, task.context_id) + updater = TaskUpdater(event_queue, task.id, task.context_id) - async for item in self.agent.stream(query, task.context_id): - final_parts = item["parts"] + async for item in self.agent.stream(query, task.context_id): + final_parts = item["parts"] - await updater.update_status( - TaskState.completed, - new_agent_parts_message(final_parts, task.context_id, task.id), - final=True, - ) + await updater.update_status( + TaskState.completed, + new_agent_parts_message(final_parts, task.context_id, task.id), + final=True, + ) - async def cancel(self, request, event_queue): - pass + async def cancel(self, request, event_queue): + pass diff --git a/samples/agent/adk/component_gallery/gallery_examples.py b/samples/agent/adk/component_gallery/gallery_examples.py index f241ea320..389bcfecb 100644 --- a/samples/agent/adk/component_gallery/gallery_examples.py +++ b/samples/agent/adk/component_gallery/gallery_examples.py @@ -18,464 +18,512 @@ def get_gallery_json() -> str: - """Returns the JSON structure for the Component Gallery surfaces.""" - - messages = [] - - # Common Data Model - # We use a single global data model for simplicity across all demo surfaces. - # Common Data Model Content - # We define the content here and inject it into EACH surface so they all share the same initial state. - gallery_data_content = { - "key": "galleryData", - "valueMap": [ - {"key": "textField", "valueString": "Hello World"}, - {"key": "checkbox", "valueBoolean": False}, - {"key": "checkboxChecked", "valueBoolean": True}, - {"key": "slider", "valueNumber": 30}, - {"key": "date", "valueString": "2025-10-26"}, - {"key": "favorites", "valueMap": [{"key": "0", "valueString": "A"}]}, - {"key": "favoritesChips", "valueMap": []}, - {"key": "favoritesFilter", "valueMap": []}, - ], - } - - # Helper to create a surface for a single component - def add_demo_surface(surface_id, component_def): - root_id = f"{surface_id}-root" - - components = [] - components.append({"id": root_id, "component": component_def}) - - messages.append({"beginRendering": {"surfaceId": surface_id, "root": root_id}}) + """Returns the JSON structure for the Component Gallery surfaces.""" + + messages = [] + + # Common Data Model + # We use a single global data model for simplicity across all demo surfaces. + # Common Data Model Content + # We define the content here and inject it into EACH surface so they all share the same initial state. + gallery_data_content = { + "key": "galleryData", + "valueMap": [ + {"key": "textField", "valueString": "Hello World"}, + {"key": "checkbox", "valueBoolean": False}, + {"key": "checkboxChecked", "valueBoolean": True}, + {"key": "slider", "valueNumber": 30}, + {"key": "date", "valueString": "2025-10-26"}, + {"key": "favorites", "valueMap": [{"key": "0", "valueString": "A"}]}, + {"key": "favoritesChips", "valueMap": []}, + {"key": "favoritesFilter", "valueMap": []}, + ], + } + + # Helper to create a surface for a single component + def add_demo_surface(surface_id, component_def): + root_id = f"{surface_id}-root" + + components = [] + components.append({"id": root_id, "component": component_def}) + + messages.append({"beginRendering": {"surfaceId": surface_id, "root": root_id}}) + messages.append( + {"surfaceUpdate": {"surfaceId": surface_id, "components": components}} + ) + + # Inject data model for this surface + messages.append( + { + "dataModelUpdate": { + "surfaceId": surface_id, + "contents": [gallery_data_content], + } + } + ) + + # 1. TextField + add_demo_surface( + "demo-text", + { + "TextField": { + "label": {"literalString": "Enter some text"}, + "text": {"path": "galleryData/textField"}, + } + }, + ) + + # 1b. TextField (Regex) + add_demo_surface( + "demo-text-regex", + { + "TextField": { + "label": {"literalString": "Enter exactly 5 digits"}, + "text": {"path": "galleryData/textFieldRegex"}, + "validationRegexp": "^\\d{5}$", + } + }, + ) + + # 2. CheckBox + add_demo_surface( + "demo-checkbox", + { + "CheckBox": { + "label": {"literalString": "Toggle me"}, + "value": {"path": "galleryData/checkbox"}, + } + }, + ) + + # 3. Slider + add_demo_surface( + "demo-slider", + { + "Slider": { + "value": {"path": "galleryData/slider"}, + "minValue": 0, + "maxValue": 100, + } + }, + ) + + # 4. DateTimeInput + add_demo_surface( + "demo-date", + {"DateTimeInput": {"value": {"path": "galleryData/date"}, "enableDate": True}}, + ) + + # 5. MultipleChoice (Default) + add_demo_surface( + "demo-multichoice", + { + "MultipleChoice": { + "selections": {"path": "galleryData/favorites"}, + "options": [ + {"label": {"literalString": "Apple"}, "value": "A"}, + {"label": {"literalString": "Banana"}, "value": "B"}, + {"label": {"literalString": "Cherry"}, "value": "C"}, + ], + } + }, + ) + + # 5b. MultipleChoice (Chips) + add_demo_surface( + "demo-multichoice-chips", + { + "MultipleChoice": { + "selections": {"path": "galleryData/favoritesChips"}, + "description": "Select tags (Chips)", + "variant": "chips", + "options": [ + {"label": {"literalString": "Work"}, "value": "work"}, + {"label": {"literalString": "Home"}, "value": "home"}, + {"label": {"literalString": "Urgent"}, "value": "urgent"}, + {"label": {"literalString": "Later"}, "value": "later"}, + ], + } + }, + ) + + # 5c. MultipleChoice (Filterable) + add_demo_surface( + "demo-multichoice-filter", + { + "MultipleChoice": { + "selections": {"path": "galleryData/favoritesFilter"}, + "description": "Select countries (Filterable)", + "filterable": True, + "options": [ + {"label": {"literalString": "United States"}, "value": "US"}, + {"label": {"literalString": "Canada"}, "value": "CA"}, + {"label": {"literalString": "United Kingdom"}, "value": "UK"}, + {"label": {"literalString": "Australia"}, "value": "AU"}, + {"label": {"literalString": "Germany"}, "value": "DE"}, + {"label": {"literalString": "France"}, "value": "FR"}, + {"label": {"literalString": "Japan"}, "value": "JP"}, + ], + } + }, + ) + + # 6. Image + add_demo_surface( + "demo-image", + { + "Image": { + "url": {"literalString": "http://localhost:10005/assets/a2ui.png"}, + "usageHint": "mediumFeature", + } + }, + ) + + # 7. Button + # Button needs a child Text component. + button_surface_id = "demo-button" + btn_root_id = "demo-button-root" + btn_text_id = "demo-button-text" + + messages.append( + {"beginRendering": {"surfaceId": button_surface_id, "root": btn_root_id}} + ) + messages.append( + { + "surfaceUpdate": { + "surfaceId": button_surface_id, + "components": [ + { + "id": btn_text_id, + "component": { + "Text": {"text": {"literalString": "Trigger Action"}} + }, + }, + { + "id": btn_root_id, + "component": { + "Button": { + "child": btn_text_id, + "primary": True, + "action": { + "name": "custom_action", + "context": [ + { + "key": "info", + "value": { + "literalString": "Custom Button Clicked" + }, + } + ], + }, + } + }, + }, + ], + } + } + ) + + # 8. Tabs + tabs_surface_id = "demo-tabs" + tabs_root_id = "demo-tabs-root" + tab1_id = "tab-1-content" + tab2_id = "tab-2-content" + + messages.append( + {"beginRendering": {"surfaceId": tabs_surface_id, "root": tabs_root_id}} + ) + messages.append( + { + "surfaceUpdate": { + "surfaceId": tabs_surface_id, + "components": [ + { + "id": tab1_id, + "component": { + "Text": {"text": {"literalString": "First Tab Content"}} + }, + }, + { + "id": tab2_id, + "component": { + "Text": {"text": {"literalString": "Second Tab Content"}} + }, + }, + { + "id": tabs_root_id, + "component": { + "Tabs": { + "tabItems": [ + { + "title": {"literalString": "View One"}, + "child": tab1_id, + }, + { + "title": {"literalString": "View Two"}, + "child": tab2_id, + }, + ] + } + }, + }, + ], + } + } + ) + + # 9. Icon + icon_surface_id = "demo-icon" + messages.append( + {"beginRendering": {"surfaceId": icon_surface_id, "root": "icon-root"}} + ) + messages.append( + { + "surfaceUpdate": { + "surfaceId": icon_surface_id, + "components": [ + { + "id": "icon-root", + "component": { + "Row": { + "children": { + "explicitList": ["icon-1", "icon-2", "icon-3"] + }, + "distribution": "spaceEvenly", + "alignment": "center", + } + }, + }, + { + "id": "icon-1", + "component": {"Icon": {"name": {"literalString": "star"}}}, + }, + { + "id": "icon-2", + "component": {"Icon": {"name": {"literalString": "home"}}}, + }, + { + "id": "icon-3", + "component": {"Icon": {"name": {"literalString": "settings"}}}, + }, + ], + } + } + ) + + # 10. Divider + div_surface_id = "demo-divider" + messages.append( + {"beginRendering": {"surfaceId": div_surface_id, "root": "div-root"}} + ) + messages.append( + { + "surfaceUpdate": { + "surfaceId": div_surface_id, + "components": [ + { + "id": "div-root", + "component": { + "Column": { + "children": { + "explicitList": [ + "div-text-1", + "div-horiz", + "div-text-2", + ] + }, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + { + "id": "div-text-1", + "component": { + "Text": {"text": {"literalString": "Above Divider"}} + }, + }, + { + "id": "div-horiz", + "component": {"Divider": {"axis": "horizontal"}}, + }, + { + "id": "div-text-2", + "component": { + "Text": {"text": {"literalString": "Below Divider"}} + }, + }, + ], + } + } + ) + + # 11. Card + card_surface_id = "demo-card" + messages.append( + {"beginRendering": {"surfaceId": card_surface_id, "root": "card-root"}} + ) + messages.append( + { + "surfaceUpdate": { + "surfaceId": card_surface_id, + "components": [ + {"id": "card-root", "component": {"Card": {"child": "card-text"}}}, + { + "id": "card-text", + "component": { + "Text": {"text": {"literalString": "I am inside a Card"}} + }, + }, + ], + } + } + ) + + # 12. Video + add_demo_surface( + "demo-video", + { + "Video": { + # Still external as user only provided audio and image + "url": { + "literalString": ( + "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" + ) + } + } + }, + ) + + # 13. Modal + # Modal needs an entry point (Button) and content. + modal_surface_id = "demo-modal" + messages.append( + {"beginRendering": {"surfaceId": modal_surface_id, "root": "modal-root"}} + ) + messages.append( + { + "surfaceUpdate": { + "surfaceId": modal_surface_id, + "components": [ + { + "id": "modal-root", + "component": { + "Modal": { + "entryPointChild": "modal-btn", + "contentChild": "modal-content", + } + }, + }, + { + "id": "modal-btn", + "component": { + "Button": { + "child": "modal-btn-text", + "primary": False, + "action": {"name": "noop"}, + } + }, + }, + { + "id": "modal-btn-text", + "component": { + "Text": {"text": {"literalString": "Open Modal"}} + }, + }, + { + "id": "modal-content", + "component": { + "Text": { + "text": {"literalString": "This is the modal content!"} + } + }, + }, + ], + } + } + ) + + # 14. List + list_surface_id = "demo-list" + messages.append( + {"beginRendering": {"surfaceId": list_surface_id, "root": "list-root"}} + ) + messages.append( + { + "surfaceUpdate": { + "surfaceId": list_surface_id, + "components": [ + { + "id": "list-root", + "component": { + "List": { + "children": { + "explicitList": [ + "list-item-1", + "list-item-2", + "list-item-3", + ] + }, + "direction": "vertical", + "alignment": "stretch", + } + }, + }, + { + "id": "list-item-1", + "component": {"Text": {"text": {"literalString": "Item 1"}}}, + }, + { + "id": "list-item-2", + "component": {"Text": {"text": {"literalString": "Item 2"}}}, + }, + { + "id": "list-item-3", + "component": {"Text": {"text": {"literalString": "Item 3"}}}, + }, + ], + } + } + ) + + # 15. AudioPlayer + add_demo_surface( + "demo-audio", + { + "AudioPlayer": { + "url": {"literalString": "http://localhost:10005/assets/audio.mp3"}, + "description": {"literalString": "Local Audio Sample"}, + } + }, + ) + + # Response Surface + messages.append( + {"beginRendering": {"surfaceId": "response-surface", "root": "response-text"}} + ) messages.append( - {"surfaceUpdate": {"surfaceId": surface_id, "components": components}} + { + "surfaceUpdate": { + "surfaceId": "response-surface", + "components": [ + { + "id": "response-text", + "component": { + "Text": { + "text": { + "literalString": ( + "Interact with the gallery to see responses. This view is" + " updated by the agent by relaying the raw action" + " commands it received from the client" + ) + } + } + }, + } + ], + } + } ) - # Inject data model for this surface - messages.append({ - "dataModelUpdate": {"surfaceId": surface_id, "contents": [gallery_data_content]} - }) - - # 1. TextField - add_demo_surface( - "demo-text", - { - "TextField": { - "label": {"literalString": "Enter some text"}, - "text": {"path": "galleryData/textField"}, - } - }, - ) - - # 1b. TextField (Regex) - add_demo_surface( - "demo-text-regex", - { - "TextField": { - "label": {"literalString": "Enter exactly 5 digits"}, - "text": {"path": "galleryData/textFieldRegex"}, - "validationRegexp": "^\\d{5}$", - } - }, - ) - - # 2. CheckBox - add_demo_surface( - "demo-checkbox", - { - "CheckBox": { - "label": {"literalString": "Toggle me"}, - "value": {"path": "galleryData/checkbox"}, - } - }, - ) - - # 3. Slider - add_demo_surface( - "demo-slider", - { - "Slider": { - "value": {"path": "galleryData/slider"}, - "minValue": 0, - "maxValue": 100, - } - }, - ) - - # 4. DateTimeInput - add_demo_surface( - "demo-date", - {"DateTimeInput": {"value": {"path": "galleryData/date"}, "enableDate": True}}, - ) - - # 5. MultipleChoice (Default) - add_demo_surface( - "demo-multichoice", - { - "MultipleChoice": { - "selections": {"path": "galleryData/favorites"}, - "options": [ - {"label": {"literalString": "Apple"}, "value": "A"}, - {"label": {"literalString": "Banana"}, "value": "B"}, - {"label": {"literalString": "Cherry"}, "value": "C"}, - ], - } - }, - ) - - # 5b. MultipleChoice (Chips) - add_demo_surface( - "demo-multichoice-chips", - { - "MultipleChoice": { - "selections": {"path": "galleryData/favoritesChips"}, - "description": "Select tags (Chips)", - "variant": "chips", - "options": [ - {"label": {"literalString": "Work"}, "value": "work"}, - {"label": {"literalString": "Home"}, "value": "home"}, - {"label": {"literalString": "Urgent"}, "value": "urgent"}, - {"label": {"literalString": "Later"}, "value": "later"}, - ], - } - }, - ) - - # 5c. MultipleChoice (Filterable) - add_demo_surface( - "demo-multichoice-filter", - { - "MultipleChoice": { - "selections": {"path": "galleryData/favoritesFilter"}, - "description": "Select countries (Filterable)", - "filterable": True, - "options": [ - {"label": {"literalString": "United States"}, "value": "US"}, - {"label": {"literalString": "Canada"}, "value": "CA"}, - {"label": {"literalString": "United Kingdom"}, "value": "UK"}, - {"label": {"literalString": "Australia"}, "value": "AU"}, - {"label": {"literalString": "Germany"}, "value": "DE"}, - {"label": {"literalString": "France"}, "value": "FR"}, - {"label": {"literalString": "Japan"}, "value": "JP"}, - ], - } - }, - ) - - # 6. Image - add_demo_surface( - "demo-image", - { - "Image": { - "url": {"literalString": "http://localhost:10005/assets/a2ui.png"}, - "usageHint": "mediumFeature", - } - }, - ) - - # 7. Button - # Button needs a child Text component. - button_surface_id = "demo-button" - btn_root_id = "demo-button-root" - btn_text_id = "demo-button-text" - - messages.append( - {"beginRendering": {"surfaceId": button_surface_id, "root": btn_root_id}} - ) - messages.append({ - "surfaceUpdate": { - "surfaceId": button_surface_id, - "components": [ - { - "id": btn_text_id, - "component": {"Text": {"text": {"literalString": "Trigger Action"}}}, - }, - { - "id": btn_root_id, - "component": { - "Button": { - "child": btn_text_id, - "primary": True, - "action": { - "name": "custom_action", - "context": [{ - "key": "info", - "value": {"literalString": "Custom Button Clicked"}, - }], - }, - } - }, - }, - ], - } - }) - - # 8. Tabs - tabs_surface_id = "demo-tabs" - tabs_root_id = "demo-tabs-root" - tab1_id = "tab-1-content" - tab2_id = "tab-2-content" - - messages.append( - {"beginRendering": {"surfaceId": tabs_surface_id, "root": tabs_root_id}} - ) - messages.append({ - "surfaceUpdate": { - "surfaceId": tabs_surface_id, - "components": [ - { - "id": tab1_id, - "component": { - "Text": {"text": {"literalString": "First Tab Content"}} - }, - }, - { - "id": tab2_id, - "component": { - "Text": {"text": {"literalString": "Second Tab Content"}} - }, - }, - { - "id": tabs_root_id, - "component": { - "Tabs": { - "tabItems": [ - { - "title": {"literalString": "View One"}, - "child": tab1_id, - }, - { - "title": {"literalString": "View Two"}, - "child": tab2_id, - }, - ] - } - }, - }, - ], - } - }) - - # 9. Icon - icon_surface_id = "demo-icon" - messages.append( - {"beginRendering": {"surfaceId": icon_surface_id, "root": "icon-root"}} - ) - messages.append({ - "surfaceUpdate": { - "surfaceId": icon_surface_id, - "components": [ - { - "id": "icon-root", - "component": { - "Row": { - "children": {"explicitList": ["icon-1", "icon-2", "icon-3"]}, - "distribution": "spaceEvenly", - "alignment": "center", - } - }, - }, - { - "id": "icon-1", - "component": {"Icon": {"name": {"literalString": "star"}}}, - }, - { - "id": "icon-2", - "component": {"Icon": {"name": {"literalString": "home"}}}, - }, - { - "id": "icon-3", - "component": {"Icon": {"name": {"literalString": "settings"}}}, - }, - ], - } - }) - - # 10. Divider - div_surface_id = "demo-divider" - messages.append({"beginRendering": {"surfaceId": div_surface_id, "root": "div-root"}}) - messages.append({ - "surfaceUpdate": { - "surfaceId": div_surface_id, - "components": [ - { - "id": "div-root", - "component": { - "Column": { - "children": { - "explicitList": ["div-text-1", "div-horiz", "div-text-2"] - }, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "div-text-1", - "component": {"Text": {"text": {"literalString": "Above Divider"}}}, - }, - {"id": "div-horiz", "component": {"Divider": {"axis": "horizontal"}}}, - { - "id": "div-text-2", - "component": {"Text": {"text": {"literalString": "Below Divider"}}}, - }, - ], - } - }) - - # 11. Card - card_surface_id = "demo-card" - messages.append( - {"beginRendering": {"surfaceId": card_surface_id, "root": "card-root"}} - ) - messages.append({ - "surfaceUpdate": { - "surfaceId": card_surface_id, - "components": [ - {"id": "card-root", "component": {"Card": {"child": "card-text"}}}, - { - "id": "card-text", - "component": { - "Text": {"text": {"literalString": "I am inside a Card"}} - }, - }, - ], - } - }) - - # 12. Video - add_demo_surface( - "demo-video", - { - "Video": { - # Still external as user only provided audio and image - "url": { - "literalString": ( - "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" - ) - } - } - }, - ) - - # 13. Modal - # Modal needs an entry point (Button) and content. - modal_surface_id = "demo-modal" - messages.append( - {"beginRendering": {"surfaceId": modal_surface_id, "root": "modal-root"}} - ) - messages.append({ - "surfaceUpdate": { - "surfaceId": modal_surface_id, - "components": [ - { - "id": "modal-root", - "component": { - "Modal": { - "entryPointChild": "modal-btn", - "contentChild": "modal-content", - } - }, - }, - { - "id": "modal-btn", - "component": { - "Button": { - "child": "modal-btn-text", - "primary": False, - "action": {"name": "noop"}, - } - }, - }, - { - "id": "modal-btn-text", - "component": {"Text": {"text": {"literalString": "Open Modal"}}}, - }, - { - "id": "modal-content", - "component": { - "Text": {"text": {"literalString": "This is the modal content!"}} - }, - }, - ], - } - }) - - # 14. List - list_surface_id = "demo-list" - messages.append( - {"beginRendering": {"surfaceId": list_surface_id, "root": "list-root"}} - ) - messages.append({ - "surfaceUpdate": { - "surfaceId": list_surface_id, - "components": [ - { - "id": "list-root", - "component": { - "List": { - "children": { - "explicitList": [ - "list-item-1", - "list-item-2", - "list-item-3", - ] - }, - "direction": "vertical", - "alignment": "stretch", - } - }, - }, - { - "id": "list-item-1", - "component": {"Text": {"text": {"literalString": "Item 1"}}}, - }, - { - "id": "list-item-2", - "component": {"Text": {"text": {"literalString": "Item 2"}}}, - }, - { - "id": "list-item-3", - "component": {"Text": {"text": {"literalString": "Item 3"}}}, - }, - ], - } - }) - - # 15. AudioPlayer - add_demo_surface( - "demo-audio", - { - "AudioPlayer": { - "url": {"literalString": "http://localhost:10005/assets/audio.mp3"}, - "description": {"literalString": "Local Audio Sample"}, - } - }, - ) - - # Response Surface - messages.append( - {"beginRendering": {"surfaceId": "response-surface", "root": "response-text"}} - ) - messages.append({ - "surfaceUpdate": { - "surfaceId": "response-surface", - "components": [{ - "id": "response-text", - "component": { - "Text": { - "text": { - "literalString": ( - "Interact with the gallery to see responses. This view is" - " updated by the agent by relaying the raw action" - " commands it received from the client" - ) - } - } - }, - }], - } - }) - - return json.dumps(messages, indent=2) + return json.dumps(messages, indent=2) diff --git a/samples/agent/adk/contact_lookup/__main__.py b/samples/agent/adk/contact_lookup/__main__.py index 69ac07eb0..622ce1ae5 100644 --- a/samples/agent/adk/contact_lookup/__main__.py +++ b/samples/agent/adk/contact_lookup/__main__.py @@ -32,57 +32,57 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @click.option("--host", default="localhost") @click.option("--port", default=10003) def main(host, port): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." + ) + + base_url = f"http://{host}:{port}" + ui_agent = ContactAgent(base_url=base_url, use_ui=True) + text_agent = ContactAgent(base_url=base_url, use_ui=False) + + agent_executor = ContactAgentExecutor(ui_agent=ui_agent, text_agent=text_agent) + + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), ) + server = A2AStarletteApplication( + agent_card=ui_agent.get_agent_card(), http_handler=request_handler + ) + import uvicorn - base_url = f"http://{host}:{port}" - ui_agent = ContactAgent(base_url=base_url, use_ui=True) - text_agent = ContactAgent(base_url=base_url, use_ui=False) - - agent_executor = ContactAgentExecutor(ui_agent=ui_agent, text_agent=text_agent) - - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - server = A2AStarletteApplication( - agent_card=ui_agent.get_agent_card(), http_handler=request_handler - ) - import uvicorn - - app = server.build() + app = server.build() - app.add_middleware( - CORSMiddleware, - allow_origin_regex=r"http://localhost:\d+", - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) + app.add_middleware( + CORSMiddleware, + allow_origin_regex=r"http://localhost:\d+", + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) - app.mount("/static", StaticFiles(directory="images"), name="static") + app.mount("/static", StaticFiles(directory="images"), name="static") - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e}") - exit(1) - except Exception as e: - logger.error(f"An error occurred during server startup: {e}") - exit(1) + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e}") + exit(1) + except Exception as e: + logger.error(f"An error occurred during server startup: {e}") + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/contact_lookup/agent.py b/samples/agent/adk/contact_lookup/agent.py index 2193d0c37..b4514232f 100644 --- a/samples/agent/adk/contact_lookup/agent.py +++ b/samples/agent/adk/contact_lookup/agent.py @@ -49,295 +49,299 @@ class ContactAgent: - """An agent that finds contact info for colleagues.""" - - SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] - - def __init__(self, base_url: str, use_ui: bool = False): - self.base_url = base_url - self.use_ui = use_ui - self._schema_manager = ( - A2uiSchemaManager( - version=VERSION_0_8, - catalogs=[ - BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") - ], - ) - if use_ui - else None - ) - self._agent = self._build_agent(use_ui) - self._user_id = "remote_agent" - self._runner = Runner( - app_name=self._agent.name, - agent=self._agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - def get_agent_card(self) -> AgentCard: - capabilities = AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - self._schema_manager.accepts_inline_catalogs, - self._schema_manager.supported_catalog_ids, + """An agent that finds contact info for colleagues.""" + + SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] + + def __init__(self, base_url: str, use_ui: bool = False): + self.base_url = base_url + self.use_ui = use_ui + self._schema_manager = ( + A2uiSchemaManager( + version=VERSION_0_8, + catalogs=[ + BasicCatalog.get_config( + version=VERSION_0_8, examples_path="examples" + ) + ], ) - ], - ) - skill = AgentSkill( - id="find_contact", - name="Find Contact Tool", - description=( - "Helps find contact information for colleagues (e.g., email, location," - " team)." - ), - tags=["contact", "directory", "people", "finder"], - examples=[ - "Who is David Chen in marketing?", - "Find Sarah Lee from engineering", - ], - ) - - return AgentCard( - name="Contact Lookup Agent", - description=( - "This agent helps find contact info for people in your organization." - ), - url=self.base_url, - version="1.0.0", - default_input_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, - capabilities=capabilities, - skills=[skill], - ) - - def get_processing_message(self) -> str: - return "Looking up contact information..." - - def _build_agent(self, use_ui: bool) -> LlmAgent: - """Builds the LLM agent for the contact agent.""" - LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - - instruction = ( - self._schema_manager.generate_system_prompt( - role_description=ROLE_DESCRIPTION, - workflow_description=WORKFLOW_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=False, # Use invalid examples to test retry logic + if use_ui + else None ) - if use_ui - else get_text_prompt() - ) - - return LlmAgent( - model=LiteLlm(model=LITELLM_MODEL), - name="contact_agent", - description="An agent that finds colleague contact info.", - instruction=instruction, - tools=[get_contact_info], - ) - - async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: - session_state = {"base_url": self.base_url} - - session = await self._runner.session_service.get_session( - app_name=self._agent.name, - user_id=self._user_id, - session_id=session_id, - ) - if session is None: - session = await self._runner.session_service.create_session( - app_name=self._agent.name, - user_id=self._user_id, - state=session_state, - session_id=session_id, - ) - elif "base_url" not in session.state: - session.state["base_url"] = self.base_url - - # --- Begin: UI Validation and Retry Logic --- - max_retries = 1 # Total 2 attempts - attempt = 0 - current_query_text = query - - # Ensure catalog schema was loaded - selected_catalog = self._schema_manager.get_selected_catalog() - if self.use_ui and not selected_catalog.catalog_schema: - logger.error( - "--- ContactAgent.stream: A2UI_SCHEMA is not loaded. " - "Cannot perform UI validation. ---" - ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm facing an internal configuration error with" - " my UI components. Please contact support." - ) - ) - ) - ], - } - return - - while attempt <= max_retries: - attempt += 1 - logger.info( - f"--- ContactAgent.stream: Attempt {attempt}/{max_retries + 1} " - f"for session {session_id} ---" - ) - - current_message = types.Content( - role="user", parts=[types.Part.from_text(text=current_query_text)] - ) - final_response_content = None - - async for event in self._runner.run_async( - user_id=self._user_id, - session_id=session.id, - new_message=current_message, - ): - logger.info(f"Event from runner: {event}") - if event.is_final_response(): - if event.content and event.content.parts and event.content.parts[0].text: - final_response_content = "\n".join( - [p.text for p in event.content.parts if p.text] - ) - break # Got the final response, stop consuming events - else: - logger.info(f"Intermediate event: {event}") - # Yield intermediate updates on every attempt - yield { - "is_task_complete": False, - "updates": self.get_processing_message(), - } - - if final_response_content is None: - logger.warning( - "--- ContactAgent.stream: Received no final response content from runner " - f"(Attempt {attempt}). ---" + self._agent = self._build_agent(use_ui) + self._user_id = "remote_agent" + self._runner = Runner( + app_name=self._agent.name, + agent=self._agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), ) - if attempt <= max_retries: - current_query_text = ( - "I received no response. Please try again." - f"Please retry the original request: '{query}'" - ) - continue # Go to next retry - else: - # Retries exhausted on no-response - final_response_content = ( - "I'm sorry, I encountered an error and couldn't process your request." - ) - # Fall through to send this as a text-only error - - is_valid = False - error_message = "" - - if self.use_ui: - logger.info( - "--- ContactAgent.stream: Validating UI response (Attempt" - f" {attempt})... ---" + + def get_agent_card(self) -> AgentCard: + capabilities = AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + self._schema_manager.accepts_inline_catalogs, + self._schema_manager.supported_catalog_ids, + ) + ], ) - try: - response_parts = parse_response(final_response_content) - - for part in response_parts: - if not part.a2ui_json: - continue - - parsed_json_data = part.a2ui_json - - # Handle the "no results found" or empty JSON case - if parsed_json_data == []: - logger.info( - "--- ContactAgent.stream: Empty JSON list found. " - "Assuming valid (e.g., 'no results'). ---" - ) - is_valid = True - else: - # --- Validation Steps --- - # Check if it validates against the A2UI_SCHEMA - # This will raise jsonschema.exceptions.ValidationError if it fails - logger.info( - "--- ContactAgent.stream: Validating against A2UI_SCHEMA... ---" - ) - selected_catalog.validator.validate(parsed_json_data) - # --- End Validation Steps --- - - logger.info( - "--- ContactAgent.stream: UI JSON successfully parsed AND validated" - f" against schema. Validation OK (Attempt {attempt}). ---" - ) - is_valid = True - except ( - ValueError, - json.JSONDecodeError, - jsonschema.exceptions.ValidationError, - ) as e: - logger.warning( - f"--- ContactAgent.stream: A2UI validation failed: {e} (Attempt" - f" {attempt}) ---" - ) - logger.warning( - f"--- Failed response content: {final_response_content[:500]}... ---" - ) - error_message = f"Validation failed: {e}." - - else: # Not using UI, so text is always "valid" - is_valid = True - - if is_valid: - logger.info( - "--- ContactAgent.stream: Response is valid. Sending final response" - f" (Attempt {attempt}). ---" + skill = AgentSkill( + id="find_contact", + name="Find Contact Tool", + description=( + "Helps find contact information for colleagues (e.g., email, location," + " team)." + ), + tags=["contact", "directory", "people", "finder"], + examples=[ + "Who is David Chen in marketing?", + "Find Sarah Lee from engineering", + ], ) - final_parts = parse_response_to_parts( - final_response_content, fallback_text="OK." + + return AgentCard( + name="Contact Lookup Agent", + description=( + "This agent helps find contact info for people in your organization." + ), + url=self.base_url, + version="1.0.0", + default_input_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, + capabilities=capabilities, + skills=[skill], ) - yield { - "is_task_complete": True, - "parts": final_parts, - } - return # We're done, exit the generator + def get_processing_message(self) -> str: + return "Looking up contact information..." + + def _build_agent(self, use_ui: bool) -> LlmAgent: + """Builds the LLM agent for the contact agent.""" + LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + + instruction = ( + self._schema_manager.generate_system_prompt( + role_description=ROLE_DESCRIPTION, + workflow_description=WORKFLOW_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=False, # Use invalid examples to test retry logic + ) + if use_ui + else get_text_prompt() + ) + + return LlmAgent( + model=LiteLlm(model=LITELLM_MODEL), + name="contact_agent", + description="An agent that finds colleague contact info.", + instruction=instruction, + tools=[get_contact_info], + ) - # --- If we're here, it means validation failed --- + async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: + session_state = {"base_url": self.base_url} - if attempt <= max_retries: - logger.warning( - f"--- ContactAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" + session = await self._runner.session_service.get_session( + app_name=self._agent.name, + user_id=self._user_id, + session_id=session_id, ) - # Prepare the query for the retry - current_query_text = ( - f"Your previous response was invalid. {error_message} You MUST generate a" - " valid response that strictly follows the A2UI JSON SCHEMA. The response" - " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" - f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" - f" original request: '{query}'" + if session is None: + session = await self._runner.session_service.create_session( + app_name=self._agent.name, + user_id=self._user_id, + state=session_state, + session_id=session_id, + ) + elif "base_url" not in session.state: + session.state["base_url"] = self.base_url + + # --- Begin: UI Validation and Retry Logic --- + max_retries = 1 # Total 2 attempts + attempt = 0 + current_query_text = query + + # Ensure catalog schema was loaded + selected_catalog = self._schema_manager.get_selected_catalog() + if self.use_ui and not selected_catalog.catalog_schema: + logger.error( + "--- ContactAgent.stream: A2UI_SCHEMA is not loaded. " + "Cannot perform UI validation. ---" + ) + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm facing an internal configuration error with" + " my UI components. Please contact support." + ) + ) + ) + ], + } + return + + while attempt <= max_retries: + attempt += 1 + logger.info( + f"--- ContactAgent.stream: Attempt {attempt}/{max_retries + 1} " + f"for session {session_id} ---" + ) + + current_message = types.Content( + role="user", parts=[types.Part.from_text(text=current_query_text)] + ) + final_response_content = None + + async for event in self._runner.run_async( + user_id=self._user_id, + session_id=session.id, + new_message=current_message, + ): + logger.info(f"Event from runner: {event}") + if event.is_final_response(): + if ( + event.content + and event.content.parts + and event.content.parts[0].text + ): + final_response_content = "\n".join( + [p.text for p in event.content.parts if p.text] + ) + break # Got the final response, stop consuming events + else: + logger.info(f"Intermediate event: {event}") + # Yield intermediate updates on every attempt + yield { + "is_task_complete": False, + "updates": self.get_processing_message(), + } + + if final_response_content is None: + logger.warning( + "--- ContactAgent.stream: Received no final response content from runner " + f"(Attempt {attempt}). ---" + ) + if attempt <= max_retries: + current_query_text = ( + "I received no response. Please try again." + f"Please retry the original request: '{query}'" + ) + continue # Go to next retry + else: + # Retries exhausted on no-response + final_response_content = "I'm sorry, I encountered an error and couldn't process your request." + # Fall through to send this as a text-only error + + is_valid = False + error_message = "" + + if self.use_ui: + logger.info( + "--- ContactAgent.stream: Validating UI response (Attempt" + f" {attempt})... ---" + ) + try: + response_parts = parse_response(final_response_content) + + for part in response_parts: + if not part.a2ui_json: + continue + + parsed_json_data = part.a2ui_json + + # Handle the "no results found" or empty JSON case + if parsed_json_data == []: + logger.info( + "--- ContactAgent.stream: Empty JSON list found. " + "Assuming valid (e.g., 'no results'). ---" + ) + is_valid = True + else: + # --- Validation Steps --- + # Check if it validates against the A2UI_SCHEMA + # This will raise jsonschema.exceptions.ValidationError if it fails + logger.info( + "--- ContactAgent.stream: Validating against A2UI_SCHEMA... ---" + ) + selected_catalog.validator.validate(parsed_json_data) + # --- End Validation Steps --- + + logger.info( + "--- ContactAgent.stream: UI JSON successfully parsed AND validated" + f" against schema. Validation OK (Attempt {attempt}). ---" + ) + is_valid = True + except ( + ValueError, + json.JSONDecodeError, + jsonschema.exceptions.ValidationError, + ) as e: + logger.warning( + f"--- ContactAgent.stream: A2UI validation failed: {e} (Attempt" + f" {attempt}) ---" + ) + logger.warning( + f"--- Failed response content: {final_response_content[:500]}... ---" + ) + error_message = f"Validation failed: {e}." + + else: # Not using UI, so text is always "valid" + is_valid = True + + if is_valid: + logger.info( + "--- ContactAgent.stream: Response is valid. Sending final response" + f" (Attempt {attempt}). ---" + ) + final_parts = parse_response_to_parts( + final_response_content, fallback_text="OK." + ) + + yield { + "is_task_complete": True, + "parts": final_parts, + } + return # We're done, exit the generator + + # --- If we're here, it means validation failed --- + + if attempt <= max_retries: + logger.warning( + f"--- ContactAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" + ) + # Prepare the query for the retry + current_query_text = ( + f"Your previous response was invalid. {error_message} You MUST generate a" + " valid response that strictly follows the A2UI JSON SCHEMA. The response" + " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" + f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" + f" original request: '{query}'" + ) + # Loop continues... + + # --- If we're here, it means we've exhausted retries --- + logger.error( + "--- ContactAgent.stream: Max retries exhausted. Sending text-only error. ---" ) - # Loop continues... - - # --- If we're here, it means we've exhausted retries --- - logger.error( - "--- ContactAgent.stream: Max retries exhausted. Sending text-only error. ---" - ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm having trouble generating the interface for" - " that request right now. Please try again in a moment." + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm having trouble generating the interface for" + " that request right now. Please try again in a moment." + ) ) ) - ) - ], - } - # --- End: UI Validation and Retry Logic --- + ], + } + # --- End: UI Validation and Retry Logic --- diff --git a/samples/agent/adk/contact_lookup/agent_executor.py b/samples/agent/adk/contact_lookup/agent_executor.py index f4e49aea5..245dbf123 100644 --- a/samples/agent/adk/contact_lookup/agent_executor.py +++ b/samples/agent/adk/contact_lookup/agent_executor.py @@ -38,127 +38,131 @@ class ContactAgentExecutor(AgentExecutor): - """Contact AgentExecutor Example.""" - - def __init__(self, ui_agent: ContactAgent, text_agent: ContactAgent): - # Instantiate two agents: one for UI and one for text-only. - # The appropriate one will be chosen at execution time. - self.ui_agent = ui_agent - self.text_agent = text_agent - - async def execute( - self, - context: RequestContext, - event_queue: EventQueue, - ) -> None: - query = "" - ui_event_part = None - action = None - - logger.info(f"--- Client requested extensions: {context.requested_extensions} ---") - use_ui = try_activate_a2ui_extension(context) - - # Determine which agent to use based on whether the a2ui extension is active. - if use_ui: - agent = self.ui_agent - logger.info("--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---") - else: - agent = self.text_agent - logger.info( - "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" - ) - - if context.message and context.message.parts: - logger.info( - f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" - " parts ---" - ) - for i, part in enumerate(context.message.parts): - if isinstance(part.root, DataPart): - if "userAction" in part.root.data: - logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") - ui_event_part = part.root.data["userAction"] - else: - logger.info(f" Part {i}: DataPart (data: {part.root.data})") - elif isinstance(part.root, TextPart): - logger.info(f" Part {i}: TextPart (text: {part.root.text})") - else: - logger.info(f" Part {i}: Unknown part type ({type(part.root)})") - - if ui_event_part: - logger.info(f"Received a2ui ClientEvent: {ui_event_part}") - # Fix: Check both 'actionName' and 'name' - action = ui_event_part.get("name") - ctx = ui_event_part.get("context", {}) - - if action == "view_profile": - contact_name = ctx.get("contactName", "Unknown") - department = ctx.get("department", "") - query = f"WHO_IS: {contact_name} from {department}" - - elif action == "send_email": - contact_name = ctx.get("contactName", "Unknown") - email = ctx.get("email", "Unknown") - query = f"USER_WANTS_TO_EMAIL: {contact_name} at {email}" - - elif action == "send_message": - contact_name = ctx.get("contactName", "Unknown") - query = f"USER_WANTS_TO_MESSAGE: {contact_name}" - - elif action == "follow_contact": - query = "ACTION: follow_contact" - - elif action == "view_full_profile": - contact_name = ctx.get("contactName", "Unknown") - query = f"USER_WANTS_FULL_PROFILE: {contact_name}" - - else: - query = f"User submitted an event: {action} with data: {ctx}" - else: - logger.info("No a2ui UI event part found. Falling back to text input.") - query = context.get_user_input() - - logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") - - task = context.current_task - - if not task: - task = new_task(context.message) - await event_queue.enqueue_event(task) - updater = TaskUpdater(event_queue, task.id, task.context_id) - - async for item in agent.stream(query, task.context_id): - is_task_complete = item["is_task_complete"] - if not is_task_complete: - await updater.update_status( - TaskState.working, - new_agent_text_message(item["updates"], task.context_id, task.id), + """Contact AgentExecutor Example.""" + + def __init__(self, ui_agent: ContactAgent, text_agent: ContactAgent): + # Instantiate two agents: one for UI and one for text-only. + # The appropriate one will be chosen at execution time. + self.ui_agent = ui_agent + self.text_agent = text_agent + + async def execute( + self, + context: RequestContext, + event_queue: EventQueue, + ) -> None: + query = "" + ui_event_part = None + action = None + + logger.info( + f"--- Client requested extensions: {context.requested_extensions} ---" ) - continue - - final_state = TaskState.input_required # Default - if action in ["send_email", "send_message", "view_full_profile"]: - final_state = TaskState.completed - - final_parts = item["parts"] - - logger.info("--- FINAL PARTS TO BE SENT ---") - for i, part in enumerate(final_parts): - logger.info(f" - Part {i}: Type = {type(part.root)}") - if isinstance(part.root, TextPart): - logger.info(f" - Text: {part.root.text[:200]}...") - elif isinstance(part.root, DataPart): - logger.info(f" - Data: {str(part.root.data)[:200]}...") - logger.info("-----------------------------") - - await updater.update_status( - final_state, - new_agent_parts_message(final_parts, task.context_id, task.id), - final=(final_state == TaskState.completed), - ) - break - - async def cancel( - self, request: RequestContext, event_queue: EventQueue - ) -> Task | None: - raise ServerError(error=UnsupportedOperationError()) + use_ui = try_activate_a2ui_extension(context) + + # Determine which agent to use based on whether the a2ui extension is active. + if use_ui: + agent = self.ui_agent + logger.info( + "--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---" + ) + else: + agent = self.text_agent + logger.info( + "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" + ) + + if context.message and context.message.parts: + logger.info( + f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" + " parts ---" + ) + for i, part in enumerate(context.message.parts): + if isinstance(part.root, DataPart): + if "userAction" in part.root.data: + logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") + ui_event_part = part.root.data["userAction"] + else: + logger.info(f" Part {i}: DataPart (data: {part.root.data})") + elif isinstance(part.root, TextPart): + logger.info(f" Part {i}: TextPart (text: {part.root.text})") + else: + logger.info(f" Part {i}: Unknown part type ({type(part.root)})") + + if ui_event_part: + logger.info(f"Received a2ui ClientEvent: {ui_event_part}") + # Fix: Check both 'actionName' and 'name' + action = ui_event_part.get("name") + ctx = ui_event_part.get("context", {}) + + if action == "view_profile": + contact_name = ctx.get("contactName", "Unknown") + department = ctx.get("department", "") + query = f"WHO_IS: {contact_name} from {department}" + + elif action == "send_email": + contact_name = ctx.get("contactName", "Unknown") + email = ctx.get("email", "Unknown") + query = f"USER_WANTS_TO_EMAIL: {contact_name} at {email}" + + elif action == "send_message": + contact_name = ctx.get("contactName", "Unknown") + query = f"USER_WANTS_TO_MESSAGE: {contact_name}" + + elif action == "follow_contact": + query = "ACTION: follow_contact" + + elif action == "view_full_profile": + contact_name = ctx.get("contactName", "Unknown") + query = f"USER_WANTS_FULL_PROFILE: {contact_name}" + + else: + query = f"User submitted an event: {action} with data: {ctx}" + else: + logger.info("No a2ui UI event part found. Falling back to text input.") + query = context.get_user_input() + + logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") + + task = context.current_task + + if not task: + task = new_task(context.message) + await event_queue.enqueue_event(task) + updater = TaskUpdater(event_queue, task.id, task.context_id) + + async for item in agent.stream(query, task.context_id): + is_task_complete = item["is_task_complete"] + if not is_task_complete: + await updater.update_status( + TaskState.working, + new_agent_text_message(item["updates"], task.context_id, task.id), + ) + continue + + final_state = TaskState.input_required # Default + if action in ["send_email", "send_message", "view_full_profile"]: + final_state = TaskState.completed + + final_parts = item["parts"] + + logger.info("--- FINAL PARTS TO BE SENT ---") + for i, part in enumerate(final_parts): + logger.info(f" - Part {i}: Type = {type(part.root)}") + if isinstance(part.root, TextPart): + logger.info(f" - Text: {part.root.text[:200]}...") + elif isinstance(part.root, DataPart): + logger.info(f" - Data: {str(part.root.data)[:200]}...") + logger.info("-----------------------------") + + await updater.update_status( + final_state, + new_agent_parts_message(final_parts, task.context_id, task.id), + final=(final_state == TaskState.completed), + ) + break + + async def cancel( + self, request: RequestContext, event_queue: EventQueue + ) -> Task | None: + raise ServerError(error=UnsupportedOperationError()) diff --git a/samples/agent/adk/contact_lookup/prompt_builder.py b/samples/agent/adk/contact_lookup/prompt_builder.py index 8fc94b641..63128161f 100644 --- a/samples/agent/adk/contact_lookup/prompt_builder.py +++ b/samples/agent/adk/contact_lookup/prompt_builder.py @@ -44,10 +44,10 @@ def get_text_prompt() -> str: - """ - Constructs the prompt for a text-only agent. - """ - return """ + """ + Constructs the prompt for a text-only agent. + """ + return """ You are a helpful contact lookup assistant. Your final output MUST be a text response. To generate the response, you MUST follow these rules: @@ -63,19 +63,21 @@ def get_text_prompt() -> str: if __name__ == "__main__": - # Example of how to use the A2UI Schema Manager to generate a system prompt - contact_prompt = A2uiSchemaManager( - VERSION_0_8, - catalogs=[BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples")], - ).generate_system_prompt( - role_description=ROLE_DESCRIPTION, - workflow_description=WORKFLOW_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=False, - ) - print(contact_prompt) - with open("generated_prompt.txt", "w") as f: - f.write(contact_prompt) - print("\nGenerated prompt saved to generated_prompt.txt") + # Example of how to use the A2UI Schema Manager to generate a system prompt + contact_prompt = A2uiSchemaManager( + VERSION_0_8, + catalogs=[ + BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") + ], + ).generate_system_prompt( + role_description=ROLE_DESCRIPTION, + workflow_description=WORKFLOW_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=False, + ) + print(contact_prompt) + with open("generated_prompt.txt", "w") as f: + f.write(contact_prompt) + print("\nGenerated prompt saved to generated_prompt.txt") diff --git a/samples/agent/adk/contact_lookup/tools.py b/samples/agent/adk/contact_lookup/tools.py index 3bf8989eb..de8e38748 100644 --- a/samples/agent/adk/contact_lookup/tools.py +++ b/samples/agent/adk/contact_lookup/tools.py @@ -22,45 +22,49 @@ def get_contact_info(name: str, tool_context: ToolContext, department: str = "") -> str: - """Call this tool to get a list of contacts based on a name and optional department. - 'name' is the person's name to search for. - 'department' is the optional department to filter by. - """ - logger.info("--- TOOL CALLED: get_contact_info ---") - logger.info(f" - Name: {name}") - logger.info(f" - Department: {department}") + """Call this tool to get a list of contacts based on a name and optional department. + 'name' is the person's name to search for. + 'department' is the optional department to filter by. + """ + logger.info("--- TOOL CALLED: get_contact_info ---") + logger.info(f" - Name: {name}") + logger.info(f" - Department: {department}") - results = [] - try: - script_dir = os.path.dirname(__file__) - file_path = os.path.join(script_dir, "contact_data.json") - with open(file_path) as f: - contact_data_str = f.read() - if base_url := tool_context.state.get("base_url"): - contact_data_str = contact_data_str.replace("http://localhost:10002", base_url) - logger.info(f"Updated base URL from tool context: {base_url}") - all_contacts = json.loads(contact_data_str) + results = [] + try: + script_dir = os.path.dirname(__file__) + file_path = os.path.join(script_dir, "contact_data.json") + with open(file_path) as f: + contact_data_str = f.read() + if base_url := tool_context.state.get("base_url"): + contact_data_str = contact_data_str.replace( + "http://localhost:10002", base_url + ) + logger.info(f"Updated base URL from tool context: {base_url}") + all_contacts = json.loads(contact_data_str) - name_lower = name.lower() + name_lower = name.lower() - dept_lower = department.lower() if department else "" + dept_lower = department.lower() if department else "" - # Filter by name - results = [ - contact for contact in all_contacts if name_lower in contact["name"].lower() - ] + # Filter by name + results = [ + contact for contact in all_contacts if name_lower in contact["name"].lower() + ] - # If department is provided, filter results further - if dept_lower: - results = [ - contact for contact in results if dept_lower in contact["department"].lower() - ] + # If department is provided, filter results further + if dept_lower: + results = [ + contact + for contact in results + if dept_lower in contact["department"].lower() + ] - logger.info(f" - Success: Found {len(results)} matching contacts.") + logger.info(f" - Success: Found {len(results)} matching contacts.") - except FileNotFoundError: - logger.error(f" - Error: contact_data.json not found at {file_path}") - except json.JSONDecodeError: - logger.error(f" - Error: Failed to decode JSON from {file_path}") + except FileNotFoundError: + logger.error(f" - Error: contact_data.json not found at {file_path}") + except json.JSONDecodeError: + logger.error(f" - Error: Failed to decode JSON from {file_path}") - return json.dumps(results) + return json.dumps(results) diff --git a/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py b/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py index 4b0bd11e6..915c54a0f 100644 --- a/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py +++ b/samples/agent/adk/contact_multiple_surfaces/a2ui_examples.py @@ -38,7 +38,12 @@ def load_floor_plan_example(html_content: str = "") -> list[dict]: """Constructs the JSON for the location surface displaying the floor plan.""" import os - title_suffix = "(MCP Apps)" if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true" else "(iFrame)" + + title_suffix = ( + "(MCP Apps)" + if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true" + else "(iFrame)" + ) return [ { "beginRendering": { @@ -73,32 +78,36 @@ def load_floor_plan_example(html_content: str = "") -> list[dict]: "component": { "Text": { "usageHint": "h2", - "text": {"literalString": f"Office Floor Plan {title_suffix}"}, + "text": { + "literalString": f"Office Floor Plan {title_suffix}" + }, } }, }, { "id": "floor-plan-comp", - "component": { - "McpApp": { - "htmlContent": html_content, - "height": 400, - "allowedTools": ["chart_node_click"], + "component": ( + { + "McpApp": { + "htmlContent": html_content, + "height": 400, + "allowedTools": ["chart_node_click"], + } } - } if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true" else { - "WebFrame": { - "html": html_content, - "height": 400, - "interactionMode": "interactive", - "allowedEvents": ["chart_node_click"], + if os.environ.get("USE_MCP_SANDBOX", "true").lower() == "true" + else { + "WebFrame": { + "html": html_content, + "height": 400, + "interactionMode": "interactive", + "allowedEvents": ["chart_node_click"], + } } - }, + ), }, { "id": "dismiss-fp-text", - "component": { - "Text": {"text": {"literalString": "Close Map"}} - }, + "component": {"Text": {"text": {"literalString": "Close Map"}}}, }, { "id": "dismiss-fp", @@ -115,16 +124,19 @@ def load_floor_plan_example(html_content: str = "") -> list[dict]: }, ] + def load_close_modal_example() -> list[dict]: """Constructs the JSON for closing the floor plan modal.""" return [{"deleteSurface": {"surfaceId": LOCATION_SURFACE_ID}}] + def load_send_message_example(contact_name: str) -> str: """Constructs the JSON string for the send message confirmation.""" from pathlib import Path + examples_dir = Path(os.path.dirname(__file__)) / "examples" action_file = examples_dir / "action_confirmation.json" - + if action_file.exists(): json_content = action_file.read_text(encoding="utf-8").strip() if contact_name != "Unknown": diff --git a/samples/agent/adk/contact_multiple_surfaces/agent.py b/samples/agent/adk/contact_multiple_surfaces/agent.py index 36376d8cd..6967caaf7 100644 --- a/samples/agent/adk/contact_multiple_surfaces/agent.py +++ b/samples/agent/adk/contact_multiple_surfaces/agent.py @@ -101,7 +101,10 @@ def get_agent_card(self) -> AgentCard: " team)." ), tags=["contact", "directory", "people", "finder"], - examples=["Who is David Chen in marketing?", "Find Sarah Lee from engineering"], + examples=[ + "Who is David Chen in marketing?", + "Find Sarah Lee from engineering", + ], ) return AgentCard( @@ -151,7 +154,7 @@ async def _handle_action(self, query: str) -> dict[str, Any] | None: return None from a2ui_examples import load_floor_plan_example, load_close_modal_example, load_send_message_example - + if "send_message" in query: logger.info("--- ContactAgent.stream: Detected send_message ACTION ---") contact_name = "Unknown" @@ -165,7 +168,7 @@ async def _handle_action(self, query: str) -> dict[str, Any] | None: f"Message sent to {contact_name}\n" f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" ) - + return { "is_task_complete": True, "parts": parse_response_to_parts(final_response_content), @@ -183,7 +186,10 @@ async def _handle_action(self, query: str) -> dict[str, Any] | None: async with sse_client(sse_url) as (read, write): async with ClientSession(read, write) as mcp_session: await mcp_session.initialize() - logger.info("--- ContactAgent: Fetching ui://floor-plan-server/map from persistent SSE server ---") + logger.info( + "--- ContactAgent: Fetching ui://floor-plan-server/map from persistent" + " SSE server ---" + ) result = await mcp_session.read_resource("ui://floor-plan-server/map") if not result.contents or len(result.contents) == 0: @@ -192,41 +198,43 @@ async def _handle_action(self, query: str) -> dict[str, Any] | None: except Exception as e: logger.error(f"Failed to fetch floor plan: {e}") return { - "is_task_complete": True, - "parts": parse_response_to_parts(f"Failed to load floor plan data: {str(e)}") + "is_task_complete": True, + "parts": parse_response_to_parts( + f"Failed to load floor plan data: {str(e)}" + ), } json_content = json.dumps(load_floor_plan_example(html_content)) logger.info(f"--- ContactAgent.stream: Sending Floor Plan ---") - + final_response_content = ( - "Here is the floor plan.\n" - f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" + f"Here is the floor plan.\n{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" ) return { - "is_task_complete": True, - "parts": parse_response_to_parts(final_response_content) + "is_task_complete": True, + "parts": parse_response_to_parts(final_response_content), } elif "close_modal" in query: logger.info("--- ContactAgent.stream: Handling close_modal ACTION ---") # Action maps to closing the FloorPlan overlay json_content = json.dumps(load_close_modal_example()) - + final_response_content = ( - "Modal closed.\n" - f"{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" + f"Modal closed.\n{A2UI_OPEN_TAG}\n{json_content}\n{A2UI_CLOSE_TAG}" ) return { - "is_task_complete": True, - "parts": parse_response_to_parts(final_response_content) + "is_task_complete": True, + "parts": parse_response_to_parts(final_response_content), } - + return None - async def stream(self, query, session_id, client_ui_capabilities: dict[str, Any] | None = None) -> AsyncIterable[dict[str, Any]]: + async def stream( + self, query, session_id, client_ui_capabilities: dict[str, Any] | None = None + ) -> AsyncIterable[dict[str, Any]]: session_state = {"base_url": self.base_url} session = await self._runner.session_service.get_session( diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py index d65ff8377..3b206a9e6 100644 --- a/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_server.py @@ -1,3 +1,17 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio from mcp.server import Server from mcp.types import Resource, TextContent @@ -30,6 +44,7 @@ async def read_resource(uri: str) -> str | bytes: agent_static_url = os.environ.get("AGENT_STATIC_URL", "http://localhost:10004") from pathlib import Path + template_path = Path(__file__).parent / "floor_plan_template.html" html = template_path.read_text(encoding="utf-8") html = html.replace("__AGENT_STATIC_URL__", agent_static_url) diff --git a/samples/agent/adk/contact_multiple_surfaces/floor_plan_template.html b/samples/agent/adk/contact_multiple_surfaces/floor_plan_template.html index 475dad459..cc9550a20 100644 --- a/samples/agent/adk/contact_multiple_surfaces/floor_plan_template.html +++ b/samples/agent/adk/contact_multiple_surfaces/floor_plan_template.html @@ -1,3 +1,18 @@ + diff --git a/samples/agent/adk/orchestrator/__main__.py b/samples/agent/adk/orchestrator/__main__.py index f7fa23cb9..a0af560fb 100644 --- a/samples/agent/adk/orchestrator/__main__.py +++ b/samples/agent/adk/orchestrator/__main__.py @@ -32,7 +32,7 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @@ -40,51 +40,53 @@ class MissingAPIKeyError(Exception): @click.option("--port", default=10002, type=int) @click.option("--subagent_urls", multiple=True, type=str, required=True) def main(host, port, subagent_urls): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." - ) + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." + ) - base_url = f"http://{host}:{port}" + base_url = f"http://{host}:{port}" - orchestrator_agent, agent_card = asyncio.run( - OrchestratorAgent.build_agent(base_url=base_url, subagent_urls=subagent_urls) - ) - agent_executor = OrchestratorAgentExecutor(agent=orchestrator_agent) + orchestrator_agent, agent_card = asyncio.run( + OrchestratorAgent.build_agent( + base_url=base_url, subagent_urls=subagent_urls + ) + ) + agent_executor = OrchestratorAgentExecutor(agent=orchestrator_agent) - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - server = A2AStarletteApplication( - agent_card=agent_card, http_handler=request_handler - ) - import uvicorn + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + server = A2AStarletteApplication( + agent_card=agent_card, http_handler=request_handler + ) + import uvicorn - app = server.build() + app = server.build() - app.add_middleware( - CORSMiddleware, - allow_origins=["http://localhost:5173"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) + app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:5173"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e} {traceback.format_exc()}") - exit(1) - except Exception as e: - logger.error( - f"An error occurred during server startup: {e} {traceback.format_exc()}" - ) - exit(1) + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e} {traceback.format_exc()}") + exit(1) + except Exception as e: + logger.error( + f"An error occurred during server startup: {e} {traceback.format_exc()}" + ) + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/orchestrator/agent.py b/samples/agent/adk/orchestrator/agent.py index 383dbcdfb..7687db46c 100644 --- a/samples/agent/adk/orchestrator/agent.py +++ b/samples/agent/adk/orchestrator/agent.py @@ -45,222 +45,227 @@ class A2UIMetadataInterceptor(ClientCallInterceptor): - @override - async def intercept( - self, - method_name: str, - request_payload: dict[str, Any], - http_kwargs: dict[str, Any], - agent_card: AgentCard | None, - context: ClientCallContext | None, - ) -> tuple[dict[str, Any], dict[str, Any]]: - """Enables the A2UI extension header and adds A2UI client capabilities to remote agent message metadata.""" - logger.info( - "Intercepting client call to method: " - + method_name - + " and payload " - + json.dumps(request_payload) - ) - - if context and context.state and context.state.get("use_ui"): - # Add A2UI extension header - http_kwargs["headers"] = {HTTP_EXTENSION_HEADER: A2UI_EXTENSION_URI} - - # Add A2UI client capabilities (supported catalogs, etc) to message metadata - if (params := request_payload.get("params")) and ( - message := params.get("message") - ): - client_capabilities = context.state.get("client_capabilities") - if "metadata" not in message: - message["metadata"] = {} - message["metadata"][A2UI_CLIENT_CAPABILITIES_KEY] = client_capabilities + @override + async def intercept( + self, + method_name: str, + request_payload: dict[str, Any], + http_kwargs: dict[str, Any], + agent_card: AgentCard | None, + context: ClientCallContext | None, + ) -> tuple[dict[str, Any], dict[str, Any]]: + """Enables the A2UI extension header and adds A2UI client capabilities to remote agent message metadata.""" logger.info( - "Added client capabilities to remote agent message metadata:" - f" {client_capabilities}" + "Intercepting client call to method: " + + method_name + + " and payload " + + json.dumps(request_payload) ) - return request_payload, http_kwargs + if context and context.state and context.state.get("use_ui"): + # Add A2UI extension header + http_kwargs["headers"] = {HTTP_EXTENSION_HEADER: A2UI_EXTENSION_URI} + + # Add A2UI client capabilities (supported catalogs, etc) to message metadata + if (params := request_payload.get("params")) and ( + message := params.get("message") + ): + client_capabilities = context.state.get("client_capabilities") + if "metadata" not in message: + message["metadata"] = {} + message["metadata"][A2UI_CLIENT_CAPABILITIES_KEY] = client_capabilities + logger.info( + "Added client capabilities to remote agent message metadata:" + f" {client_capabilities}" + ) + + return request_payload, http_kwargs class A2AClientFactoryWithA2UIMetadata(A2AClientFactory): - @override - def create( - self, - card: AgentCard, - consumers: list[Consumer] | None = None, - interceptors: list[ClientCallInterceptor] | None = None, - ) -> Client: - # Add A2UI metadata interceptor - return super().create( - card, consumers, (interceptors or []) + [A2UIMetadataInterceptor()] - ) + @override + def create( + self, + card: AgentCard, + consumers: list[Consumer] | None = None, + interceptors: list[ClientCallInterceptor] | None = None, + ) -> Client: + # Add A2UI metadata interceptor + return super().create( + card, consumers, (interceptors or []) + [A2UIMetadataInterceptor()] + ) class OrchestratorAgent: - """An agent that runs an ecommerce dashboard""" + """An agent that runs an ecommerce dashboard""" - SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] + SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] - @classmethod - async def programmtically_route_user_action_to_subagent( - cls, - callback_context: CallbackContext, - llm_request: LlmRequest, - ) -> LlmResponse: - if ( - llm_request.contents - and (last_content := llm_request.contents[-1]).parts - and ( - a2a_part := part_converters.convert_genai_part_to_a2a_part( - last_content.parts[-1] + @classmethod + async def programmtically_route_user_action_to_subagent( + cls, + callback_context: CallbackContext, + llm_request: LlmRequest, + ) -> LlmResponse: + if ( + llm_request.contents + and (last_content := llm_request.contents[-1]).parts + and ( + a2a_part := part_converters.convert_genai_part_to_a2a_part( + last_content.parts[-1] + ) ) - ) - and is_a2ui_part(a2a_part) - and (user_action := a2a_part.root.data.get("userAction")) - and (surface_id := user_action.get("surfaceId")) - and ( - target_agent := await SubagentRouteManager.get_route_to_subagent_name( - surface_id, callback_context.state + and is_a2ui_part(a2a_part) + and (user_action := a2a_part.root.data.get("userAction")) + and (surface_id := user_action.get("surfaceId")) + and ( + target_agent := await SubagentRouteManager.get_route_to_subagent_name( + surface_id, callback_context.state + ) + ) + ): + logger.info( + f"Programmatically routing userAction for surfaceId '{surface_id}' to" + f" subagent '{target_agent}'" + ) + return LlmResponse( + content=genai_types.Content( + parts=[ + genai_types.Part( + function_call=genai_types.FunctionCall( + name="transfer_to_agent", + args={"agent_name": target_agent}, + ) + ) + ] + ) ) - ) - ): - logger.info( - f"Programmatically routing userAction for surfaceId '{surface_id}' to" - f" subagent '{target_agent}'" - ) - return LlmResponse( - content=genai_types.Content( - parts=[ - genai_types.Part( - function_call=genai_types.FunctionCall( - name="transfer_to_agent", - args={"agent_name": target_agent}, - ) - ) - ] - ) - ) - return None + return None - @classmethod - async def build_agent( - cls, base_url: str, subagent_urls: List[str] - ) -> (LlmAgent, AgentCard): - """Builds the LLM agent for the orchestrator_agent agent.""" + @classmethod + async def build_agent( + cls, base_url: str, subagent_urls: List[str] + ) -> (LlmAgent, AgentCard): + """Builds the LLM agent for the orchestrator_agent agent.""" - subagents = [] - supported_catalog_ids = set() - skills = [] - accepts_inline_catalogs = False - for subagent_url in subagent_urls: - async with httpx.AsyncClient() as httpx_client: - resolver = A2ACardResolver( - httpx_client=httpx_client, - base_url=subagent_url, - ) + subagents = [] + supported_catalog_ids = set() + skills = [] + accepts_inline_catalogs = False + for subagent_url in subagent_urls: + async with httpx.AsyncClient() as httpx_client: + resolver = A2ACardResolver( + httpx_client=httpx_client, + base_url=subagent_url, + ) - subagent_card = await resolver.get_agent_card() - for extension in subagent_card.capabilities.extensions or []: - if extension.uri == A2UI_EXTENSION_URI and extension.params: - supported_catalog_ids.update( - extension.params.get(AGENT_EXTENSION_SUPPORTED_CATALOG_IDS_KEY) or [] - ) - accepts_inline_catalogs |= bool( - extension.params.get(AGENT_EXTENSION_ACCEPTS_INLINE_CATALOGS_KEY) - ) + subagent_card = await resolver.get_agent_card() + for extension in subagent_card.capabilities.extensions or []: + if extension.uri == A2UI_EXTENSION_URI and extension.params: + supported_catalog_ids.update( + extension.params.get( + AGENT_EXTENSION_SUPPORTED_CATALOG_IDS_KEY + ) + or [] + ) + accepts_inline_catalogs |= bool( + extension.params.get( + AGENT_EXTENSION_ACCEPTS_INLINE_CATALOGS_KEY + ) + ) - skills.extend(subagent_card.skills) + skills.extend(subagent_card.skills) - logger.info( - "Successfully fetched public agent card:" - + subagent_card.model_dump_json(indent=2, exclude_none=True) - ) + logger.info( + "Successfully fetched public agent card:" + + subagent_card.model_dump_json(indent=2, exclude_none=True) + ) - # clean name for adk - clean_name = re.sub(r"[^0-9a-zA-Z_]+", "_", subagent_card.name) - if clean_name == "": - clean_name = "_" - if clean_name[0].isdigit(): - clean_name = f"_{clean_name}" + # clean name for adk + clean_name = re.sub(r"[^0-9a-zA-Z_]+", "_", subagent_card.name) + if clean_name == "": + clean_name = "_" + if clean_name[0].isdigit(): + clean_name = f"_{clean_name}" - # make remote agent - description = json.dumps( - { - "id": clean_name, - "name": subagent_card.name, - "description": subagent_card.description, - "skills": [ + # make remote agent + description = json.dumps( { - "name": skill.name, - "description": skill.description, - "examples": skill.examples, - "tags": skill.tags, - } - for skill in subagent_card.skills - ], - }, - indent=2, - ) - remote_a2a_agent = RemoteA2aAgent( - clean_name, - subagent_card, - description=description, # This will be appended to system instructions - a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, - genai_part_converter=part_converters.convert_genai_part_to_a2a_part, - a2a_client_factory=A2AClientFactoryWithA2UIMetadata( - config=A2AClientConfig( - httpx_client=httpx.AsyncClient( - timeout=httpx.Timeout(timeout=DEFAULT_TIMEOUT), + "id": clean_name, + "name": subagent_card.name, + "description": subagent_card.description, + "skills": [ + { + "name": skill.name, + "description": skill.description, + "examples": skill.examples, + "tags": skill.tags, + } + for skill in subagent_card.skills + ], + }, + indent=2, + ) + remote_a2a_agent = RemoteA2aAgent( + clean_name, + subagent_card, + description=description, # This will be appended to system instructions + a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, + genai_part_converter=part_converters.convert_genai_part_to_a2a_part, + a2a_client_factory=A2AClientFactoryWithA2UIMetadata( + config=A2AClientConfig( + httpx_client=httpx.AsyncClient( + timeout=httpx.Timeout(timeout=DEFAULT_TIMEOUT), + ), + streaming=False, + polling=False, + supported_transports=[A2ATransport.jsonrpc], + ) ), - streaming=False, - polling=False, - supported_transports=[A2ATransport.jsonrpc], ) - ), - ) - subagents.append(remote_a2a_agent) + subagents.append(remote_a2a_agent) - logger.info(f"Created remote agent with description: {description}") + logger.info(f"Created remote agent with description: {description}") - LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - agent = LlmAgent( - model=LiteLlm(model=LITELLM_MODEL), - name="orchestrator_agent", - description="An agent that orchestrates requests to multiple other agents", - instruction=( - "You are an orchestrator agent. Your sole responsibility is to analyze the" - " incoming user request, determine the user's intent, and route the task to" - " exactly one of your expert subagents" - ), - tools=[], - planner=BuiltInPlanner( - thinking_config=genai_types.ThinkingConfig( - include_thoughts=True, - ) - ), - sub_agents=subagents, - before_model_callback=cls.programmtically_route_user_action_to_subagent, - ) - - agent_card = AgentCard( - name="Orchestrator Agent", - description="This agent orchestrates requests to multiple subagents.", - url=base_url, - version="1.0.0", - default_input_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, - capabilities=AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - accepts_inline_catalogs=accepts_inline_catalogs, - supported_catalog_ids=list(supported_catalog_ids), + LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + agent = LlmAgent( + model=LiteLlm(model=LITELLM_MODEL), + name="orchestrator_agent", + description="An agent that orchestrates requests to multiple other agents", + instruction=( + "You are an orchestrator agent. Your sole responsibility is to analyze the" + " incoming user request, determine the user's intent, and route the task to" + " exactly one of your expert subagents" + ), + tools=[], + planner=BuiltInPlanner( + thinking_config=genai_types.ThinkingConfig( + include_thoughts=True, ) - ], - ), - skills=skills, - ) + ), + sub_agents=subagents, + before_model_callback=cls.programmtically_route_user_action_to_subagent, + ) + + agent_card = AgentCard( + name="Orchestrator Agent", + description="This agent orchestrates requests to multiple subagents.", + url=base_url, + version="1.0.0", + default_input_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, + capabilities=AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + accepts_inline_catalogs=accepts_inline_catalogs, + supported_catalog_ids=list(supported_catalog_ids), + ) + ], + ), + skills=skills, + ) - return agent, agent_card + return agent, agent_card diff --git a/samples/agent/adk/orchestrator/agent_executor.py b/samples/agent/adk/orchestrator/agent_executor.py index f2a3a29f2..d9c62b4be 100644 --- a/samples/agent/adk/orchestrator/agent_executor.py +++ b/samples/agent/adk/orchestrator/agent_executor.py @@ -47,113 +47,113 @@ class OrchestratorAgentExecutor(A2aAgentExecutor): - """Contact AgentExecutor Example.""" - - def __init__(self, agent: LlmAgent): - config = A2aAgentExecutorConfig( - gen_ai_part_converter=part_converters.convert_genai_part_to_a2a_part, - a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, - event_converter=self.convert_event_to_a2a_events_and_save_surface_id_to_subagent_name, - ) - - runner = Runner( - app_name=agent.name, - agent=agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - super().__init__(runner=runner, config=config) - - @classmethod - def convert_event_to_a2a_events_and_save_surface_id_to_subagent_name( - cls, - event: Event, - invocation_context: InvocationContext, - task_id: Optional[str] = None, - context_id: Optional[str] = None, - part_converter: part_converter.GenAIPartToA2APartConverter = part_converter.convert_genai_part_to_a2a_part, - ) -> List[A2AEvent]: - a2a_events = event_converter.convert_event_to_a2a_events( - event, - invocation_context, - task_id, - context_id, - part_converter, - ) - - for a2a_event in a2a_events: - # Try to populate subagent agent card if available. - subagent_card = None - if active_subagent_name := event.author: - # We need to find the subagent by name - if subagent := next( - ( - sub - for sub in invocation_context.agent.sub_agents - if sub.name == active_subagent_name - ), - None, - ): - try: - subagent_card = json.loads(subagent.description) - except Exception: - logger.warning( - f"Failed to parse agent description for {active_subagent_name}" + """Contact AgentExecutor Example.""" + + def __init__(self, agent: LlmAgent): + config = A2aAgentExecutorConfig( + gen_ai_part_converter=part_converters.convert_genai_part_to_a2a_part, + a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, + event_converter=self.convert_event_to_a2a_events_and_save_surface_id_to_subagent_name, + ) + + runner = Runner( + app_name=agent.name, + agent=agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), + ) + + super().__init__(runner=runner, config=config) + + @classmethod + def convert_event_to_a2a_events_and_save_surface_id_to_subagent_name( + cls, + event: Event, + invocation_context: InvocationContext, + task_id: Optional[str] = None, + context_id: Optional[str] = None, + part_converter: part_converter.GenAIPartToA2APartConverter = part_converter.convert_genai_part_to_a2a_part, + ) -> List[A2AEvent]: + a2a_events = event_converter.convert_event_to_a2a_events( + event, + invocation_context, + task_id, + context_id, + part_converter, + ) + + for a2a_event in a2a_events: + # Try to populate subagent agent card if available. + subagent_card = None + if active_subagent_name := event.author: + # We need to find the subagent by name + if subagent := next( + ( + sub + for sub in invocation_context.agent.sub_agents + if sub.name == active_subagent_name + ), + None, + ): + try: + subagent_card = json.loads(subagent.description) + except Exception: + logger.warning( + f"Failed to parse agent description for {active_subagent_name}" + ) + if subagent_card: + if a2a_event.metadata is None: + a2a_event.metadata = {} + a2a_event.metadata["a2a_subagent"] = subagent_card + + for a2a_part in a2a_event.status.message.parts: + if ( + is_a2ui_part(a2a_part) + and (begin_rendering := a2a_part.root.data.get("beginRendering")) + and (surface_id := begin_rendering.get("surfaceId")) + ): + asyncio.run_coroutine_threadsafe( + SubagentRouteManager.set_route_to_subagent_name( + surface_id, + event.author, + invocation_context.session_service, + invocation_context.session, + ), + asyncio.get_event_loop(), + ) + + return a2a_events + + @override + async def _prepare_session( + self, + context: RequestContext, + run_request: AgentRunRequest, + runner: Runner, + ): + session = await super()._prepare_session(context, run_request, runner) + + if try_activate_a2ui_extension(context): + client_capabilities = ( + context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) + if context.message and context.message.metadata + else None ) - if subagent_card: - if a2a_event.metadata is None: - a2a_event.metadata = {} - a2a_event.metadata["a2a_subagent"] = subagent_card - - for a2a_part in a2a_event.status.message.parts: - if ( - is_a2ui_part(a2a_part) - and (begin_rendering := a2a_part.root.data.get("beginRendering")) - and (surface_id := begin_rendering.get("surfaceId")) - ): - asyncio.run_coroutine_threadsafe( - SubagentRouteManager.set_route_to_subagent_name( - surface_id, - event.author, - invocation_context.session_service, - invocation_context.session, - ), - asyncio.get_event_loop(), - ) - - return a2a_events - - @override - async def _prepare_session( - self, - context: RequestContext, - run_request: AgentRunRequest, - runner: Runner, - ): - session = await super()._prepare_session(context, run_request, runner) - - if try_activate_a2ui_extension(context): - client_capabilities = ( - context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) - if context.message and context.message.metadata - else None - ) - - await runner.session_service.append_event( - session, - Event( - invocation_id=new_invocation_context_id(), - author="system", - actions=EventActions( - state_delta={ - # These values are used to configure A2UI messages to remote agent calls - "use_ui": True, - "client_capabilities": client_capabilities, - } - ), - ), - ) - - return session + + await runner.session_service.append_event( + session, + Event( + invocation_id=new_invocation_context_id(), + author="system", + actions=EventActions( + state_delta={ + # These values are used to configure A2UI messages to remote agent calls + "use_ui": True, + "client_capabilities": client_capabilities, + } + ), + ), + ) + + return session diff --git a/samples/agent/adk/orchestrator/part_converters.py b/samples/agent/adk/orchestrator/part_converters.py index 8c74656a0..6d3111335 100644 --- a/samples/agent/adk/orchestrator/part_converters.py +++ b/samples/agent/adk/orchestrator/part_converters.py @@ -29,35 +29,35 @@ def convert_a2a_part_to_genai_part( a2a_part: a2a_types.Part, ) -> Optional[genai_types.Part]: - if is_a2ui_part(a2a_part): - genai_part = genai_types.Part(text=a2a_part.model_dump_json()) - logger.info( - f"Converted A2UI part from A2A: {a2a_part.model_dump_json(exclude_none=True)} to GenAI: {genai_part.model_dump_json(exclude_none=True)}"[ - :200 - ] - + "..." - ) - return genai_part - - return part_converter.convert_a2a_part_to_genai_part(a2a_part) - - -def convert_genai_part_to_a2a_part( - part: genai_types.Part, -) -> Optional[a2a_types.Part]: - if part.text: - try: - a2a_part = a2a_types.Part.model_validate_json(part.text) - if is_a2ui_part(a2a_part): + if is_a2ui_part(a2a_part): + genai_part = genai_types.Part(text=a2a_part.model_dump_json()) logger.info( - f"Converted A2UI part from GenAI: {part.model_dump_json(exclude_none=True)} to A2A: {a2a_part.model_dump_json(exclude_none=True)}"[ + f"Converted A2UI part from A2A: {a2a_part.model_dump_json(exclude_none=True)} to GenAI: {genai_part.model_dump_json(exclude_none=True)}"[ :200 ] + "..." ) - return a2a_part - except pydantic.ValidationError: - # Expected for normal text input - pass + return genai_part - return part_converter.convert_genai_part_to_a2a_part(part) + return part_converter.convert_a2a_part_to_genai_part(a2a_part) + + +def convert_genai_part_to_a2a_part( + part: genai_types.Part, +) -> Optional[a2a_types.Part]: + if part.text: + try: + a2a_part = a2a_types.Part.model_validate_json(part.text) + if is_a2ui_part(a2a_part): + logger.info( + f"Converted A2UI part from GenAI: {part.model_dump_json(exclude_none=True)} to A2A: {a2a_part.model_dump_json(exclude_none=True)}"[ + :200 + ] + + "..." + ) + return a2a_part + except pydantic.ValidationError: + # Expected for normal text input + pass + + return part_converter.convert_genai_part_to_a2a_part(part) diff --git a/samples/agent/adk/orchestrator/subagent_route_manager.py b/samples/agent/adk/orchestrator/subagent_route_manager.py index bd6dae9c7..88e603783 100644 --- a/samples/agent/adk/orchestrator/subagent_route_manager.py +++ b/samples/agent/adk/orchestrator/subagent_route_manager.py @@ -23,50 +23,50 @@ class SubagentRouteManager: - """Manages routing of tasks to sub-agents.""" + """Manages routing of tasks to sub-agents.""" - ROUTING_KEY_PREFIX = "route_to_subagent_name_for_surface_id_" + ROUTING_KEY_PREFIX = "route_to_subagent_name_for_surface_id_" - @classmethod - def _get_routing_key(cls, surface_id: str) -> str: - return cls.ROUTING_KEY_PREFIX + surface_id + @classmethod + def _get_routing_key(cls, surface_id: str) -> str: + return cls.ROUTING_KEY_PREFIX + surface_id - @classmethod - async def get_route_to_subagent_name( - cls, surface_id: str, state: State - ) -> Optional[str]: - """Gets the subagent route for the given tool call id.""" - subagent_name = state.get(cls._get_routing_key(surface_id), None) - logging.info( - "Got subagent route for surface_id %s to subagent_name %s", - surface_id, - subagent_name, - ) - return subagent_name + @classmethod + async def get_route_to_subagent_name( + cls, surface_id: str, state: State + ) -> Optional[str]: + """Gets the subagent route for the given tool call id.""" + subagent_name = state.get(cls._get_routing_key(surface_id), None) + logging.info( + "Got subagent route for surface_id %s to subagent_name %s", + surface_id, + subagent_name, + ) + return subagent_name - @classmethod - async def set_route_to_subagent_name( - cls, - surface_id: str, - subagent_name: str, - session_service: BaseSessionService, - session: Session, - ): - """Sets the subagent route for the given tool call id.""" - key = cls._get_routing_key(surface_id) + @classmethod + async def set_route_to_subagent_name( + cls, + surface_id: str, + subagent_name: str, + session_service: BaseSessionService, + session: Session, + ): + """Sets the subagent route for the given tool call id.""" + key = cls._get_routing_key(surface_id) - if session.state.get(key) != subagent_name: - await session_service.append_event( - session, - Event( - invocation_id=new_invocation_context_id(), - author="system", - actions=EventActions(state_delta={key: subagent_name}), - ), - ) + if session.state.get(key) != subagent_name: + await session_service.append_event( + session, + Event( + invocation_id=new_invocation_context_id(), + author="system", + actions=EventActions(state_delta={key: subagent_name}), + ), + ) - logging.info( - "Set subagent route for surface_id %s to subagent_name %s", - surface_id, - subagent_name, - ) + logging.info( + "Set subagent route for surface_id %s to subagent_name %s", + surface_id, + subagent_name, + ) diff --git a/samples/agent/adk/restaurant_finder/__main__.py b/samples/agent/adk/restaurant_finder/__main__.py index f816cf6d8..c28339da2 100644 --- a/samples/agent/adk/restaurant_finder/__main__.py +++ b/samples/agent/adk/restaurant_finder/__main__.py @@ -32,58 +32,58 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @click.option("--host", default="localhost") @click.option("--port", default=10002) def main(host, port): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." - ) + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." + ) - base_url = f"http://{host}:{port}" + base_url = f"http://{host}:{port}" - ui_agent = RestaurantAgent(base_url=base_url, use_ui=True) - text_agent = RestaurantAgent(base_url=base_url, use_ui=False) + ui_agent = RestaurantAgent(base_url=base_url, use_ui=True) + text_agent = RestaurantAgent(base_url=base_url, use_ui=False) - agent_executor = RestaurantAgentExecutor(ui_agent, text_agent) + agent_executor = RestaurantAgentExecutor(ui_agent, text_agent) - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - server = A2AStarletteApplication( - agent_card=ui_agent.get_agent_card(), http_handler=request_handler - ) - import uvicorn + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + server = A2AStarletteApplication( + agent_card=ui_agent.get_agent_card(), http_handler=request_handler + ) + import uvicorn - app = server.build() + app = server.build() - app.add_middleware( - CORSMiddleware, - allow_origin_regex=r"http://localhost:\d+", - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) + app.add_middleware( + CORSMiddleware, + allow_origin_regex=r"http://localhost:\d+", + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) - app.mount("/static", StaticFiles(directory="images"), name="static") + app.mount("/static", StaticFiles(directory="images"), name="static") - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e}") - exit(1) - except Exception as e: - logger.error(f"An error occurred during server startup: {e}") - exit(1) + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e}") + exit(1) + except Exception as e: + logger.error(f"An error occurred during server startup: {e}") + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/restaurant_finder/agent.py b/samples/agent/adk/restaurant_finder/agent.py index e5239c5fd..dd36c379a 100644 --- a/samples/agent/adk/restaurant_finder/agent.py +++ b/samples/agent/adk/restaurant_finder/agent.py @@ -51,283 +51,287 @@ class RestaurantAgent: - """An agent that finds restaurants based on user criteria.""" - - SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] - - def __init__(self, base_url: str, use_ui: bool = False): - self.base_url = base_url - self.use_ui = use_ui - self._schema_manager = ( - A2uiSchemaManager( - VERSION_0_8, - catalogs=[ - BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") + """An agent that finds restaurants based on user criteria.""" + + SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] + + def __init__(self, base_url: str, use_ui: bool = False): + self.base_url = base_url + self.use_ui = use_ui + self._schema_manager = ( + A2uiSchemaManager( + VERSION_0_8, + catalogs=[ + BasicCatalog.get_config( + version=VERSION_0_8, examples_path="examples" + ) + ], + schema_modifiers=[remove_strict_validation], + ) + if use_ui + else None + ) + self._agent = self._build_agent(use_ui) + self._user_id = "remote_agent" + self._runner = Runner( + app_name=self._agent.name, + agent=self._agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), + ) + + def get_agent_card(self) -> AgentCard: + capabilities = AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + self._schema_manager.accepts_inline_catalogs, + self._schema_manager.supported_catalog_ids, + ) ], - schema_modifiers=[remove_strict_validation], ) - if use_ui - else None - ) - self._agent = self._build_agent(use_ui) - self._user_id = "remote_agent" - self._runner = Runner( - app_name=self._agent.name, - agent=self._agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - def get_agent_card(self) -> AgentCard: - capabilities = AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - self._schema_manager.accepts_inline_catalogs, - self._schema_manager.supported_catalog_ids, - ) - ], - ) - skill = AgentSkill( - id="find_restaurants", - name="Find Restaurants Tool", - description=( - "Helps find restaurants based on user criteria (e.g., cuisine, location)." - ), - tags=["restaurant", "finder"], - examples=["Find me the top 10 chinese restaurants in the US"], - ) - - return AgentCard( - name="Restaurant Agent", - description="This agent helps find restaurants based on user criteria.", - url=self.base_url, - version="1.0.0", - default_input_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, - capabilities=capabilities, - skills=[skill], - ) - - def get_processing_message(self) -> str: - return "Finding restaurants that match your criteria..." - - def _build_agent(self, use_ui: bool) -> LlmAgent: - """Builds the LLM agent for the restaurant agent.""" - LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - - instruction = ( - self._schema_manager.generate_system_prompt( - role_description=ROLE_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=True, + skill = AgentSkill( + id="find_restaurants", + name="Find Restaurants Tool", + description=( + "Helps find restaurants based on user criteria (e.g., cuisine, location)." + ), + tags=["restaurant", "finder"], + examples=["Find me the top 10 chinese restaurants in the US"], + ) + + return AgentCard( + name="Restaurant Agent", + description="This agent helps find restaurants based on user criteria.", + url=self.base_url, + version="1.0.0", + default_input_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, + capabilities=capabilities, + skills=[skill], ) - if use_ui - else get_text_prompt() - ) - - return LlmAgent( - model=LiteLlm(model=LITELLM_MODEL), - name="restaurant_agent", - description="An agent that finds restaurants and helps book tables.", - instruction=instruction, - tools=[get_restaurants], - ) - - async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: - session_state = {"base_url": self.base_url} - - session = await self._runner.session_service.get_session( - app_name=self._agent.name, - user_id=self._user_id, - session_id=session_id, - ) - if session is None: - session = await self._runner.session_service.create_session( - app_name=self._agent.name, - user_id=self._user_id, - state=session_state, - session_id=session_id, - ) - elif "base_url" not in session.state: - session.state["base_url"] = self.base_url - - # --- Begin: UI Validation and Retry Logic --- - max_retries = 1 # Total 2 attempts - attempt = 0 - current_query_text = query - - # Ensure schema was loaded - selected_catalog = self._schema_manager.get_selected_catalog() - if self.use_ui and not selected_catalog.catalog_schema: - logger.error( - "--- RestaurantAgent.stream: A2UI_SCHEMA is not loaded. " - "Cannot perform UI validation. ---" - ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm facing an internal configuration error with" - " my UI components. Please contact support." - ) - ) - ) - ], - } - return - - while attempt <= max_retries: - attempt += 1 - logger.info( - f"--- RestaurantAgent.stream: Attempt {attempt}/{max_retries + 1} " - f"for session {session_id} ---" - ) - - current_message = types.Content( - role="user", parts=[types.Part.from_text(text=current_query_text)] - ) - final_response_content = None - - async for event in self._runner.run_async( - user_id=self._user_id, - session_id=session.id, - new_message=current_message, - ): - logger.info(f"Event from runner: {event}") - if event.is_final_response(): - if event.content and event.content.parts and event.content.parts[0].text: - final_response_content = "\n".join( - [p.text for p in event.content.parts if p.text] + + def get_processing_message(self) -> str: + return "Finding restaurants that match your criteria..." + + def _build_agent(self, use_ui: bool) -> LlmAgent: + """Builds the LLM agent for the restaurant agent.""" + LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + + instruction = ( + self._schema_manager.generate_system_prompt( + role_description=ROLE_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=True, ) - break # Got the final response, stop consuming events - else: - logger.info(f"Intermediate event: {event}") - # Yield intermediate updates on every attempt - yield { - "is_task_complete": False, - "updates": self.get_processing_message(), - } - - if final_response_content is None: - logger.warning( - "--- RestaurantAgent.stream: Received no final response content from" - f" runner (Attempt {attempt}). ---" + if use_ui + else get_text_prompt() ) - if attempt <= max_retries: - current_query_text = ( - "I received no response. Please try again." - f"Please retry the original request: '{query}'" - ) - continue # Go to next retry - else: - # Retries exhausted on no-response - final_response_content = ( - "I'm sorry, I encountered an error and couldn't process your request." - ) - # Fall through to send this as a text-only error - - is_valid = False - error_message = "" - - if self.use_ui: - logger.info( - "--- RestaurantAgent.stream: Validating UI response (Attempt" - f" {attempt})... ---" + + return LlmAgent( + model=LiteLlm(model=LITELLM_MODEL), + name="restaurant_agent", + description="An agent that finds restaurants and helps book tables.", + instruction=instruction, + tools=[get_restaurants], ) - try: - response_parts = parse_response(final_response_content) - for part in response_parts: - if not part.a2ui_json: - continue + async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: + session_state = {"base_url": self.base_url} - parsed_json_data = part.a2ui_json + session = await self._runner.session_service.get_session( + app_name=self._agent.name, + user_id=self._user_id, + session_id=session_id, + ) + if session is None: + session = await self._runner.session_service.create_session( + app_name=self._agent.name, + user_id=self._user_id, + state=session_state, + session_id=session_id, + ) + elif "base_url" not in session.state: + session.state["base_url"] = self.base_url + + # --- Begin: UI Validation and Retry Logic --- + max_retries = 1 # Total 2 attempts + attempt = 0 + current_query_text = query + + # Ensure schema was loaded + selected_catalog = self._schema_manager.get_selected_catalog() + if self.use_ui and not selected_catalog.catalog_schema: + logger.error( + "--- RestaurantAgent.stream: A2UI_SCHEMA is not loaded. " + "Cannot perform UI validation. ---" + ) + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm facing an internal configuration error with" + " my UI components. Please contact support." + ) + ) + ) + ], + } + return - # --- Validation Steps --- - # Check if it validates against the A2UI_SCHEMA - # This will raise jsonschema.exceptions.ValidationError if it fails + while attempt <= max_retries: + attempt += 1 logger.info( - "--- RestaurantAgent.stream: Validating against A2UI_SCHEMA... ---" + f"--- RestaurantAgent.stream: Attempt {attempt}/{max_retries + 1} " + f"for session {session_id} ---" ) - selected_catalog.validator.validate(parsed_json_data) - # --- End Validation Steps --- - logger.info( - "--- RestaurantAgent.stream: UI JSON successfully parsed AND validated" - f" against schema. Validation OK (Attempt {attempt}). ---" + current_message = types.Content( + role="user", parts=[types.Part.from_text(text=current_query_text)] ) - is_valid = True - - except ( - ValueError, - json.JSONDecodeError, - jsonschema.exceptions.ValidationError, - ) as e: - logger.warning( - f"--- RestaurantAgent.stream: A2UI validation failed: {e} (Attempt" - f" {attempt}) ---" - ) - logger.warning( - f"--- Failed response content: {final_response_content[:500]}... ---" - ) - error_message = f"Validation failed: {e}." - - else: # Not using UI, so text is always "valid" - is_valid = True - - if is_valid: - logger.info( - "--- RestaurantAgent.stream: Response is valid. Sending final response" - f" (Attempt {attempt}). ---" - ) - final_parts = parse_response_to_parts( - final_response_content, fallback_text="OK." - ) + final_response_content = None + + async for event in self._runner.run_async( + user_id=self._user_id, + session_id=session.id, + new_message=current_message, + ): + logger.info(f"Event from runner: {event}") + if event.is_final_response(): + if ( + event.content + and event.content.parts + and event.content.parts[0].text + ): + final_response_content = "\n".join( + [p.text for p in event.content.parts if p.text] + ) + break # Got the final response, stop consuming events + else: + logger.info(f"Intermediate event: {event}") + # Yield intermediate updates on every attempt + yield { + "is_task_complete": False, + "updates": self.get_processing_message(), + } + + if final_response_content is None: + logger.warning( + "--- RestaurantAgent.stream: Received no final response content from" + f" runner (Attempt {attempt}). ---" + ) + if attempt <= max_retries: + current_query_text = ( + "I received no response. Please try again." + f"Please retry the original request: '{query}'" + ) + continue # Go to next retry + else: + # Retries exhausted on no-response + final_response_content = "I'm sorry, I encountered an error and couldn't process your request." + # Fall through to send this as a text-only error + + is_valid = False + error_message = "" + + if self.use_ui: + logger.info( + "--- RestaurantAgent.stream: Validating UI response (Attempt" + f" {attempt})... ---" + ) + try: + response_parts = parse_response(final_response_content) + + for part in response_parts: + if not part.a2ui_json: + continue + + parsed_json_data = part.a2ui_json + + # --- Validation Steps --- + # Check if it validates against the A2UI_SCHEMA + # This will raise jsonschema.exceptions.ValidationError if it fails + logger.info( + "--- RestaurantAgent.stream: Validating against A2UI_SCHEMA... ---" + ) + selected_catalog.validator.validate(parsed_json_data) + # --- End Validation Steps --- + + logger.info( + "--- RestaurantAgent.stream: UI JSON successfully parsed AND validated" + f" against schema. Validation OK (Attempt {attempt}). ---" + ) + is_valid = True + + except ( + ValueError, + json.JSONDecodeError, + jsonschema.exceptions.ValidationError, + ) as e: + logger.warning( + f"--- RestaurantAgent.stream: A2UI validation failed: {e} (Attempt" + f" {attempt}) ---" + ) + logger.warning( + f"--- Failed response content: {final_response_content[:500]}... ---" + ) + error_message = f"Validation failed: {e}." - yield { - "is_task_complete": True, - "parts": final_parts, - } - return # We're done, exit the generator + else: # Not using UI, so text is always "valid" + is_valid = True - # --- If we're here, it means validation failed --- + if is_valid: + logger.info( + "--- RestaurantAgent.stream: Response is valid. Sending final response" + f" (Attempt {attempt}). ---" + ) + final_parts = parse_response_to_parts( + final_response_content, fallback_text="OK." + ) - if attempt <= max_retries: - logger.warning( - f"--- RestaurantAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" - ) - # Prepare the query for the retry - current_query_text = ( - f"Your previous response was invalid. {error_message} You MUST generate a" - " valid response that strictly follows the A2UI JSON SCHEMA. The response" - " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" - f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" - f" original request: '{query}'" + yield { + "is_task_complete": True, + "parts": final_parts, + } + return # We're done, exit the generator + + # --- If we're here, it means validation failed --- + + if attempt <= max_retries: + logger.warning( + f"--- RestaurantAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" + ) + # Prepare the query for the retry + current_query_text = ( + f"Your previous response was invalid. {error_message} You MUST generate a" + " valid response that strictly follows the A2UI JSON SCHEMA. The response" + " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" + f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" + f" original request: '{query}'" + ) + # Loop continues... + + # --- If we're here, it means we've exhausted retries --- + logger.error( + "--- RestaurantAgent.stream: Max retries exhausted. Sending text-only" + " error. ---" ) - # Loop continues... - - # --- If we're here, it means we've exhausted retries --- - logger.error( - "--- RestaurantAgent.stream: Max retries exhausted. Sending text-only" - " error. ---" - ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm having trouble generating the interface for" - " that request right now. Please try again in a moment." + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm having trouble generating the interface for" + " that request right now. Please try again in a moment." + ) ) ) - ) - ], - } - # --- End: UI Validation and Retry Logic --- + ], + } + # --- End: UI Validation and Retry Logic --- diff --git a/samples/agent/adk/restaurant_finder/agent_executor.py b/samples/agent/adk/restaurant_finder/agent_executor.py index f552b407d..54cf3682b 100644 --- a/samples/agent/adk/restaurant_finder/agent_executor.py +++ b/samples/agent/adk/restaurant_finder/agent_executor.py @@ -38,128 +38,132 @@ class RestaurantAgentExecutor(AgentExecutor): - """Restaurant AgentExecutor Example.""" - - def __init__(self, ui_agent: RestaurantAgent, text_agent: RestaurantAgent): - # Instantiate two agents: one for UI and one for text-only. - # The appropriate one will be chosen at execution time. - self.ui_agent = ui_agent - self.text_agent = text_agent - - async def execute( - self, - context: RequestContext, - event_queue: EventQueue, - ) -> None: - query = "" - ui_event_part = None - action = None - - logger.info(f"--- Client requested extensions: {context.requested_extensions} ---") - use_ui = try_activate_a2ui_extension(context) - - # Determine which agent to use based on whether the a2ui extension is active. - if use_ui: - agent = self.ui_agent - logger.info("--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---") - else: - agent = self.text_agent - logger.info( - "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" - ) - - if context.message and context.message.parts: - logger.info( - f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" - " parts ---" - ) - for i, part in enumerate(context.message.parts): - if isinstance(part.root, DataPart): - if "userAction" in part.root.data: - logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") - ui_event_part = part.root.data["userAction"] - else: - logger.info(f" Part {i}: DataPart (data: {part.root.data})") - elif isinstance(part.root, TextPart): - logger.info(f" Part {i}: TextPart (text: {part.root.text})") - else: - logger.info(f" Part {i}: Unknown part type ({type(part.root)})") - - if ui_event_part: - logger.info(f"Received a2ui ClientEvent: {ui_event_part}") - action = ui_event_part.get("actionName") - ctx = ui_event_part.get("context", {}) - - if action == "book_restaurant": - restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") - address = ctx.get("address", "Address not provided") - image_url = ctx.get("imageUrl", "") - query = ( - f"USER_WANTS_TO_BOOK: {restaurant_name}, Address: {address}, ImageURL:" - f" {image_url}" - ) - - elif action == "submit_booking": - restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") - party_size = ctx.get("partySize", "Unknown Size") - reservation_time = ctx.get("reservationTime", "Unknown Time") - dietary_reqs = ctx.get("dietary", "None") - image_url = ctx.get("imageUrl", "") - query = ( - f"User submitted a booking for {restaurant_name} for {party_size} people at" - f" {reservation_time} with dietary requirements: {dietary_reqs}. The image" - f" URL is {image_url}" + """Restaurant AgentExecutor Example.""" + + def __init__(self, ui_agent: RestaurantAgent, text_agent: RestaurantAgent): + # Instantiate two agents: one for UI and one for text-only. + # The appropriate one will be chosen at execution time. + self.ui_agent = ui_agent + self.text_agent = text_agent + + async def execute( + self, + context: RequestContext, + event_queue: EventQueue, + ) -> None: + query = "" + ui_event_part = None + action = None + + logger.info( + f"--- Client requested extensions: {context.requested_extensions} ---" ) - - else: - query = f"User submitted an event: {action} with data: {ctx}" - else: - logger.info("No a2ui UI event part found. Falling back to text input.") - query = context.get_user_input() - - logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") - - task = context.current_task - - if not task: - task = new_task(context.message) - await event_queue.enqueue_event(task) - updater = TaskUpdater(event_queue, task.id, task.context_id) - - async for item in agent.stream(query, task.context_id): - is_task_complete = item["is_task_complete"] - if not is_task_complete: - await updater.update_status( - TaskState.working, - new_agent_text_message(item["updates"], task.context_id, task.id), - ) - continue - - final_state = ( - TaskState.completed - if action == "submit_booking" - else TaskState.input_required - ) - - final_parts = item["parts"] - - logger.info("--- FINAL PARTS TO BE SENT ---") - for i, part in enumerate(final_parts): - logger.info(f" - Part {i}: Type = {type(part.root)}") - if isinstance(part.root, TextPart): - logger.info(f" - Text: {part.root.text[:200]}...") - elif isinstance(part.root, DataPart): - logger.info(f" - Data: {str(part.root.data)[:200]}...") - logger.info("-----------------------------") - - await updater.update_status( - final_state, - new_agent_parts_message(final_parts, task.context_id, task.id), - final=(final_state == TaskState.completed), - ) - break - - async def cancel( - self, request: RequestContext, event_queue: EventQueue - ) -> Task | None: - raise ServerError(error=UnsupportedOperationError()) + use_ui = try_activate_a2ui_extension(context) + + # Determine which agent to use based on whether the a2ui extension is active. + if use_ui: + agent = self.ui_agent + logger.info( + "--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---" + ) + else: + agent = self.text_agent + logger.info( + "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" + ) + + if context.message and context.message.parts: + logger.info( + f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" + " parts ---" + ) + for i, part in enumerate(context.message.parts): + if isinstance(part.root, DataPart): + if "userAction" in part.root.data: + logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") + ui_event_part = part.root.data["userAction"] + else: + logger.info(f" Part {i}: DataPart (data: {part.root.data})") + elif isinstance(part.root, TextPart): + logger.info(f" Part {i}: TextPart (text: {part.root.text})") + else: + logger.info(f" Part {i}: Unknown part type ({type(part.root)})") + + if ui_event_part: + logger.info(f"Received a2ui ClientEvent: {ui_event_part}") + action = ui_event_part.get("actionName") + ctx = ui_event_part.get("context", {}) + + if action == "book_restaurant": + restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") + address = ctx.get("address", "Address not provided") + image_url = ctx.get("imageUrl", "") + query = ( + f"USER_WANTS_TO_BOOK: {restaurant_name}, Address: {address}, ImageURL:" + f" {image_url}" + ) + + elif action == "submit_booking": + restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") + party_size = ctx.get("partySize", "Unknown Size") + reservation_time = ctx.get("reservationTime", "Unknown Time") + dietary_reqs = ctx.get("dietary", "None") + image_url = ctx.get("imageUrl", "") + query = ( + f"User submitted a booking for {restaurant_name} for {party_size} people at" + f" {reservation_time} with dietary requirements: {dietary_reqs}. The image" + f" URL is {image_url}" + ) + + else: + query = f"User submitted an event: {action} with data: {ctx}" + else: + logger.info("No a2ui UI event part found. Falling back to text input.") + query = context.get_user_input() + + logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") + + task = context.current_task + + if not task: + task = new_task(context.message) + await event_queue.enqueue_event(task) + updater = TaskUpdater(event_queue, task.id, task.context_id) + + async for item in agent.stream(query, task.context_id): + is_task_complete = item["is_task_complete"] + if not is_task_complete: + await updater.update_status( + TaskState.working, + new_agent_text_message(item["updates"], task.context_id, task.id), + ) + continue + + final_state = ( + TaskState.completed + if action == "submit_booking" + else TaskState.input_required + ) + + final_parts = item["parts"] + + logger.info("--- FINAL PARTS TO BE SENT ---") + for i, part in enumerate(final_parts): + logger.info(f" - Part {i}: Type = {type(part.root)}") + if isinstance(part.root, TextPart): + logger.info(f" - Text: {part.root.text[:200]}...") + elif isinstance(part.root, DataPart): + logger.info(f" - Data: {str(part.root.data)[:200]}...") + logger.info("-----------------------------") + + await updater.update_status( + final_state, + new_agent_parts_message(final_parts, task.context_id, task.id), + final=(final_state == TaskState.completed), + ) + break + + async def cancel( + self, request: RequestContext, event_queue: EventQueue + ) -> Task | None: + raise ServerError(error=UnsupportedOperationError()) diff --git a/samples/agent/adk/restaurant_finder/prompt_builder.py b/samples/agent/adk/restaurant_finder/prompt_builder.py index 0d4a2619d..96b3c505c 100644 --- a/samples/agent/adk/restaurant_finder/prompt_builder.py +++ b/samples/agent/adk/restaurant_finder/prompt_builder.py @@ -32,10 +32,10 @@ def get_text_prompt() -> str: - """ - Constructs the prompt for a text-only agent. - """ - return """ + """ + Constructs the prompt for a text-only agent. + """ + return """ You are a helpful restaurant finding assistant. Your final output MUST be a text response. To generate the response, you MUST follow these rules: @@ -52,27 +52,29 @@ def get_text_prompt() -> str: if __name__ == "__main__": - # Example of how to use the A2UI Schema Manager to generate a system prompt - # In your actual application, you would call this from your main agent logic. + # Example of how to use the A2UI Schema Manager to generate a system prompt + # In your actual application, you would call this from your main agent logic. - # You can now easily construct a prompt with the relevant examples. - # For a different agent (e.g., a flight booker), you would pass in - # different examples but use the same `get_ui_prompt` function. - restaurant_prompt = A2uiSchemaManager( - VERSION_0_8, - catalogs=[BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples")], - schema_modifiers=[remove_strict_validation], - ).generate_system_prompt( - role_description=ROLE_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=True, - ) + # You can now easily construct a prompt with the relevant examples. + # For a different agent (e.g., a flight booker), you would pass in + # different examples but use the same `get_ui_prompt` function. + restaurant_prompt = A2uiSchemaManager( + VERSION_0_8, + catalogs=[ + BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") + ], + schema_modifiers=[remove_strict_validation], + ).generate_system_prompt( + role_description=ROLE_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=True, + ) - print(restaurant_prompt) + print(restaurant_prompt) - # This demonstrates how you could save the prompt to a file for inspection - with open("generated_prompt.txt", "w") as f: - f.write(restaurant_prompt) - print("\nGenerated prompt saved to generated_prompt.txt") + # This demonstrates how you could save the prompt to a file for inspection + with open("generated_prompt.txt", "w") as f: + f.write(restaurant_prompt) + print("\nGenerated prompt saved to generated_prompt.txt") diff --git a/samples/agent/adk/restaurant_finder/tools.py b/samples/agent/adk/restaurant_finder/tools.py index da0e48e52..0263dd40e 100644 --- a/samples/agent/adk/restaurant_finder/tools.py +++ b/samples/agent/adk/restaurant_finder/tools.py @@ -24,36 +24,36 @@ def get_restaurants( cuisine: str, location: str, tool_context: ToolContext, count: int = 5 ) -> str: - """Call this tool to get a list of restaurants based on a cuisine and location. - 'count' is the number of restaurants to return. - """ - logger.info(f"--- TOOL CALLED: get_restaurants (count: {count}) ---") - logger.info(f" - Cuisine: {cuisine}") - logger.info(f" - Location: {location}") - - items = [] - if "new york" in location.lower() or "ny" in location.lower(): - try: - script_dir = os.path.dirname(__file__) - file_path = os.path.join(script_dir, "restaurant_data.json") - with open(file_path) as f: - restaurant_data_str = f.read() - if base_url := tool_context.state.get("base_url"): - restaurant_data_str = restaurant_data_str.replace( - "http://localhost:10002", base_url - ) - logger.info(f"Updated base URL from tool context: {base_url}") - all_items = json.loads(restaurant_data_str) - - # Slice the list to return only the requested number of items - items = all_items[:count] - logger.info( - f" - Success: Found {len(all_items)} restaurants, returning {len(items)}." - ) - - except FileNotFoundError: - logger.error(f" - Error: restaurant_data.json not found at {file_path}") - except json.JSONDecodeError: - logger.error(f" - Error: Failed to decode JSON from {file_path}") - - return json.dumps(items) + """Call this tool to get a list of restaurants based on a cuisine and location. + 'count' is the number of restaurants to return. + """ + logger.info(f"--- TOOL CALLED: get_restaurants (count: {count}) ---") + logger.info(f" - Cuisine: {cuisine}") + logger.info(f" - Location: {location}") + + items = [] + if "new york" in location.lower() or "ny" in location.lower(): + try: + script_dir = os.path.dirname(__file__) + file_path = os.path.join(script_dir, "restaurant_data.json") + with open(file_path) as f: + restaurant_data_str = f.read() + if base_url := tool_context.state.get("base_url"): + restaurant_data_str = restaurant_data_str.replace( + "http://localhost:10002", base_url + ) + logger.info(f"Updated base URL from tool context: {base_url}") + all_items = json.loads(restaurant_data_str) + + # Slice the list to return only the requested number of items + items = all_items[:count] + logger.info( + f" - Success: Found {len(all_items)} restaurants, returning {len(items)}." + ) + + except FileNotFoundError: + logger.error(f" - Error: restaurant_data.json not found at {file_path}") + except json.JSONDecodeError: + logger.error(f" - Error: Failed to decode JSON from {file_path}") + + return json.dumps(items) diff --git a/samples/agent/adk/rizzcharts/__main__.py b/samples/agent/adk/rizzcharts/__main__.py index 9c988f102..edfb8b0b8 100644 --- a/samples/agent/adk/rizzcharts/__main__.py +++ b/samples/agent/adk/rizzcharts/__main__.py @@ -41,93 +41,93 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @click.option("--host", default="localhost") @click.option("--port", default=10002) def main(host, port): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." + ) + + lite_llm_model = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + + base_url = f"http://{host}:{port}" + + schema_manager = A2uiSchemaManager( + VERSION_0_8, + catalogs=[ + CatalogConfig.from_path( + name="rizzcharts", + catalog_path="rizzcharts_catalog_definition.json", + examples_path="examples/rizzcharts_catalog", + ), + BasicCatalog.get_config( + version=VERSION_0_8, + examples_path="examples/standard_catalog", + ), + ], + accepts_inline_catalogs=True, ) - lite_llm_model = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - - base_url = f"http://{host}:{port}" - - schema_manager = A2uiSchemaManager( - VERSION_0_8, - catalogs=[ - CatalogConfig.from_path( - name="rizzcharts", - catalog_path="rizzcharts_catalog_definition.json", - examples_path="examples/rizzcharts_catalog", - ), - BasicCatalog.get_config( - version=VERSION_0_8, - examples_path="examples/standard_catalog", - ), - ], - accepts_inline_catalogs=True, - ) - - agent = RizzchartsAgent( - base_url=base_url, - model=LiteLlm(model=lite_llm_model), - schema_manager=schema_manager, - a2ui_enabled_provider=get_a2ui_enabled, - a2ui_catalog_provider=get_a2ui_catalog, - a2ui_examples_provider=get_a2ui_examples, - ) - runner = Runner( - app_name=agent.name, - agent=agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - agent_executor = RizzchartsAgentExecutor( - base_url=base_url, - runner=runner, - schema_manager=schema_manager, - ) - - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - server = A2AStarletteApplication( - agent_card=agent.get_agent_card(), http_handler=request_handler - ) - import uvicorn - - app = server.build() - - app.add_middleware( - CORSMiddleware, - allow_origins=["http://localhost:5173"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) - - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e} {traceback.format_exc()}") - exit(1) - except Exception as e: - logger.error( - f"An error occurred during server startup: {e} {traceback.format_exc()}" - ) - exit(1) + agent = RizzchartsAgent( + base_url=base_url, + model=LiteLlm(model=lite_llm_model), + schema_manager=schema_manager, + a2ui_enabled_provider=get_a2ui_enabled, + a2ui_catalog_provider=get_a2ui_catalog, + a2ui_examples_provider=get_a2ui_examples, + ) + runner = Runner( + app_name=agent.name, + agent=agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), + ) + + agent_executor = RizzchartsAgentExecutor( + base_url=base_url, + runner=runner, + schema_manager=schema_manager, + ) + + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + server = A2AStarletteApplication( + agent_card=agent.get_agent_card(), http_handler=request_handler + ) + import uvicorn + + app = server.build() + + app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:5173"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e} {traceback.format_exc()}") + exit(1) + except Exception as e: + logger.error( + f"An error occurred during server startup: {e} {traceback.format_exc()}" + ) + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/rizzcharts/agent.py b/samples/agent/adk/rizzcharts/agent.py index 850b6cc12..78b7fdf2b 100644 --- a/samples/agent/adk/rizzcharts/agent.py +++ b/samples/agent/adk/rizzcharts/agent.py @@ -28,9 +28,9 @@ from pydantic import PrivateAttr try: - from .tools import get_sales_data, get_store_sales + from .tools import get_sales_data, get_store_sales except ImportError: - from tools import get_sales_data, get_store_sales + from tools import get_sales_data, get_store_sales logger = logging.getLogger(__name__) @@ -83,122 +83,129 @@ class RizzchartsAgent(LlmAgent): - """An agent that runs an ecommerce dashboard""" - - SUPPORTED_CONTENT_TYPES: ClassVar[list[str]] = ["text", "text/plain"] - base_url: str = "" - schema_manager: A2uiSchemaManager = None - _a2ui_enabled_provider: A2uiEnabledProvider = PrivateAttr() - _a2ui_catalog_provider: A2uiCatalogProvider = PrivateAttr() - _a2ui_examples_provider: A2uiExamplesProvider = PrivateAttr() - - def __init__( - self, - model: Any, - base_url: str, - schema_manager: A2uiSchemaManager, - a2ui_enabled_provider: A2uiEnabledProvider, - a2ui_catalog_provider: A2uiCatalogProvider, - a2ui_examples_provider: A2uiExamplesProvider, - ): - """Initializes the RizzchartsAgent. - - Args: - model: The LLM model to use. - base_url: The base URL for the agent. - schema_manager: The A2UI schema manager. - a2ui_enabled_provider: A provider to check if A2UI is enabled. - a2ui_catalog_provider: A provider to retrieve the A2UI catalog (A2uiCatalog object). - a2ui_examples_provider: A provider to retrieve the A2UI examples (str). - """ - - system_instructions = schema_manager.generate_system_prompt( - role_description=ROLE_DESCRIPTION, - workflow_description=WORKFLOW_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=False, - include_examples=False, - validate_examples=False, - ) - super().__init__( - model=model, - name="rizzcharts_agent", - description="An agent that lets sales managers request sales data.", - instruction=system_instructions, - tools=[ - get_store_sales, - get_sales_data, - SendA2uiToClientToolset( - a2ui_catalog=a2ui_catalog_provider, - a2ui_enabled=a2ui_enabled_provider, - a2ui_examples=a2ui_examples_provider, - ), - ], - planner=BuiltInPlanner( - thinking_config=types.ThinkingConfig( - include_thoughts=True, - ) - ), - disallow_transfer_to_peers=True, - base_url=base_url, - schema_manager=schema_manager, - ) - - self._a2ui_enabled_provider = a2ui_enabled_provider - self._a2ui_catalog_provider = a2ui_catalog_provider - self._a2ui_examples_provider = a2ui_examples_provider - - def get_agent_card(self) -> AgentCard: - """Returns the AgentCard defining this agent's metadata and skills. - - Returns: - An AgentCard object. - """ - return AgentCard( - name="Ecommerce Dashboard Agent", - description=( - "This agent visualizes ecommerce data, showing sales breakdowns, YOY" - " revenue performance, and regional sales outliers." - ), - url=self.base_url, - version="1.0.0", - default_input_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, - capabilities=AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - self.schema_manager.accepts_inline_catalogs, - self.schema_manager.supported_catalog_ids, - ) - ], - ), - skills=[ - AgentSkill( - id="view_sales_by_category", - name="View Sales by Category", - description=( - "Displays a pie chart of sales broken down by product category for" - " a given time period." + """An agent that runs an ecommerce dashboard""" + + SUPPORTED_CONTENT_TYPES: ClassVar[list[str]] = ["text", "text/plain"] + base_url: str = "" + schema_manager: A2uiSchemaManager = None + _a2ui_enabled_provider: A2uiEnabledProvider = PrivateAttr() + _a2ui_catalog_provider: A2uiCatalogProvider = PrivateAttr() + _a2ui_examples_provider: A2uiExamplesProvider = PrivateAttr() + + def __init__( + self, + model: Any, + base_url: str, + schema_manager: A2uiSchemaManager, + a2ui_enabled_provider: A2uiEnabledProvider, + a2ui_catalog_provider: A2uiCatalogProvider, + a2ui_examples_provider: A2uiExamplesProvider, + ): + """Initializes the RizzchartsAgent. + + Args: + model: The LLM model to use. + base_url: The base URL for the agent. + schema_manager: The A2UI schema manager. + a2ui_enabled_provider: A provider to check if A2UI is enabled. + a2ui_catalog_provider: A provider to retrieve the A2UI catalog (A2uiCatalog object). + a2ui_examples_provider: A provider to retrieve the A2UI examples (str). + """ + + system_instructions = schema_manager.generate_system_prompt( + role_description=ROLE_DESCRIPTION, + workflow_description=WORKFLOW_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=False, + include_examples=False, + validate_examples=False, + ) + super().__init__( + model=model, + name="rizzcharts_agent", + description="An agent that lets sales managers request sales data.", + instruction=system_instructions, + tools=[ + get_store_sales, + get_sales_data, + SendA2uiToClientToolset( + a2ui_catalog=a2ui_catalog_provider, + a2ui_enabled=a2ui_enabled_provider, + a2ui_examples=a2ui_examples_provider, ), - tags=["sales", "breakdown", "category", "pie chart", "revenue"], - examples=[ - "show my sales breakdown by product category for q3", - "What's the sales breakdown for last month?", - ], + ], + planner=BuiltInPlanner( + thinking_config=types.ThinkingConfig( + include_thoughts=True, + ) ), - AgentSkill( - id="view_regional_outliers", - name="View Regional Sales Outliers", - description=( - "Displays a map showing regional sales outliers or store-level" - " performance." - ), - tags=["sales", "regional", "outliers", "stores", "map", "performance"], - examples=[ - "interesting. were there any outlier stores", - "show me a map of store performance", + disallow_transfer_to_peers=True, + base_url=base_url, + schema_manager=schema_manager, + ) + + self._a2ui_enabled_provider = a2ui_enabled_provider + self._a2ui_catalog_provider = a2ui_catalog_provider + self._a2ui_examples_provider = a2ui_examples_provider + + def get_agent_card(self) -> AgentCard: + """Returns the AgentCard defining this agent's metadata and skills. + + Returns: + An AgentCard object. + """ + return AgentCard( + name="Ecommerce Dashboard Agent", + description=( + "This agent visualizes ecommerce data, showing sales breakdowns, YOY" + " revenue performance, and regional sales outliers." + ), + url=self.base_url, + version="1.0.0", + default_input_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, + capabilities=AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + self.schema_manager.accepts_inline_catalogs, + self.schema_manager.supported_catalog_ids, + ) ], ), - ], - ) + skills=[ + AgentSkill( + id="view_sales_by_category", + name="View Sales by Category", + description=( + "Displays a pie chart of sales broken down by product category for" + " a given time period." + ), + tags=["sales", "breakdown", "category", "pie chart", "revenue"], + examples=[ + "show my sales breakdown by product category for q3", + "What's the sales breakdown for last month?", + ], + ), + AgentSkill( + id="view_regional_outliers", + name="View Regional Sales Outliers", + description=( + "Displays a map showing regional sales outliers or store-level" + " performance." + ), + tags=[ + "sales", + "regional", + "outliers", + "stores", + "map", + "performance", + ], + examples=[ + "interesting. were there any outlier stores", + "show me a map of store performance", + ], + ), + ], + ) diff --git a/samples/agent/adk/rizzcharts/agent_executor.py b/samples/agent/adk/rizzcharts/agent_executor.py index 5892eea94..6ea59d2c8 100644 --- a/samples/agent/adk/rizzcharts/agent_executor.py +++ b/samples/agent/adk/rizzcharts/agent_executor.py @@ -44,96 +44,96 @@ def get_a2ui_catalog(ctx: ReadonlyContext): - """Retrieves the A2UI catalog from the session state. + """Retrieves the A2UI catalog from the session state. - Args: - ctx: The ReadonlyContext for resolving the catalog. + Args: + ctx: The ReadonlyContext for resolving the catalog. - Returns: - The A2UI catalog or None if not found. - """ - return ctx.state.get(_A2UI_CATALOG_KEY) + Returns: + The A2UI catalog or None if not found. + """ + return ctx.state.get(_A2UI_CATALOG_KEY) def get_a2ui_examples(ctx: ReadonlyContext): - """Retrieves the A2UI examples from the session state. + """Retrieves the A2UI examples from the session state. - Args: - ctx: The ReadonlyContext for resolving the examples. + Args: + ctx: The ReadonlyContext for resolving the examples. - Returns: - The A2UI examples or None if not found. - """ - return ctx.state.get(_A2UI_EXAMPLES_KEY) + Returns: + The A2UI examples or None if not found. + """ + return ctx.state.get(_A2UI_EXAMPLES_KEY) def get_a2ui_enabled(ctx: ReadonlyContext): - """Checks if A2UI is enabled in the current session. + """Checks if A2UI is enabled in the current session. - Args: - ctx: The ReadonlyContext for resolving enablement. + Args: + ctx: The ReadonlyContext for resolving enablement. - Returns: - True if A2UI is enabled, False otherwise. - """ - return ctx.state.get(_A2UI_ENABLED_KEY, False) + Returns: + True if A2UI is enabled, False otherwise. + """ + return ctx.state.get(_A2UI_ENABLED_KEY, False) class RizzchartsAgentExecutor(A2aAgentExecutor): - """Executor for the Rizzcharts agent that handles A2UI session setup.""" - - def __init__( - self, - base_url: str, - runner: Runner, - schema_manager: A2uiSchemaManager, - ): - self._base_url = base_url - self.schema_manager = schema_manager - - config = A2aAgentExecutorConfig(event_converter=A2uiEventConverter()) - super().__init__(runner=runner, config=config) - - @override - async def _prepare_session( - self, - context: RequestContext, - run_request: AgentRunRequest, - runner: Runner, - ): - logger.info(f"Loading session for message {context.message}") - - session = await super()._prepare_session(context, run_request, runner) - - if "base_url" not in session.state: - session.state["base_url"] = self._base_url - - use_ui = try_activate_a2ui_extension(context) - if use_ui: - capabilities = ( - context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) - if context.message and context.message.metadata - else None - ) - a2ui_catalog = self.schema_manager.get_selected_catalog( - client_ui_capabilities=capabilities - ) - - examples = self.schema_manager.load_examples(a2ui_catalog, validate=True) - - await runner.session_service.append_event( - session, - Event( - invocation_id=new_invocation_context_id(), - author="system", - actions=EventActions( - state_delta={ - _A2UI_ENABLED_KEY: True, - _A2UI_CATALOG_KEY: a2ui_catalog, - _A2UI_EXAMPLES_KEY: examples, - } - ), - ), - ) - - return session + """Executor for the Rizzcharts agent that handles A2UI session setup.""" + + def __init__( + self, + base_url: str, + runner: Runner, + schema_manager: A2uiSchemaManager, + ): + self._base_url = base_url + self.schema_manager = schema_manager + + config = A2aAgentExecutorConfig(event_converter=A2uiEventConverter()) + super().__init__(runner=runner, config=config) + + @override + async def _prepare_session( + self, + context: RequestContext, + run_request: AgentRunRequest, + runner: Runner, + ): + logger.info(f"Loading session for message {context.message}") + + session = await super()._prepare_session(context, run_request, runner) + + if "base_url" not in session.state: + session.state["base_url"] = self._base_url + + use_ui = try_activate_a2ui_extension(context) + if use_ui: + capabilities = ( + context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) + if context.message and context.message.metadata + else None + ) + a2ui_catalog = self.schema_manager.get_selected_catalog( + client_ui_capabilities=capabilities + ) + + examples = self.schema_manager.load_examples(a2ui_catalog, validate=True) + + await runner.session_service.append_event( + session, + Event( + invocation_id=new_invocation_context_id(), + author="system", + actions=EventActions( + state_delta={ + _A2UI_ENABLED_KEY: True, + _A2UI_CATALOG_KEY: a2ui_catalog, + _A2UI_EXAMPLES_KEY: examples, + } + ), + ), + ) + + return session diff --git a/samples/agent/adk/rizzcharts/tools.py b/samples/agent/adk/rizzcharts/tools.py index 9acca87a0..61424872e 100644 --- a/samples/agent/adk/rizzcharts/tools.py +++ b/samples/agent/adk/rizzcharts/tools.py @@ -19,89 +19,89 @@ def get_store_sales(region: str = "all", **kwargs: Any) -> dict[str, Any]: - """ - Gets individual store sales + """ + Gets individual store sales - Args: - region: The region to get store sales for. - **kwargs: Additional arguments. + Args: + region: The region to get store sales for. + **kwargs: Additional arguments. - Returns: - A dict containing the stores with locations and their sales, and with outlier stores highlighted - """ - logger.info("get_store_sales called with region=%s, kwargs=%s", region, kwargs) + Returns: + A dict containing the stores with locations and their sales, and with outlier stores highlighted + """ + logger.info("get_store_sales called with region=%s, kwargs=%s", region, kwargs) - return { - "center": {"lat": 34, "lng": -118.2437}, - "zoom": 10, - "locations": [ - { - "lat": 34.0195, - "lng": -118.4912, - "name": "Santa Monica Branch", - "description": "High traffic coastal location.", - "outlier_reason": "Yes, 15% sales over baseline", - "background": "#4285F4", - "borderColor": "#FFFFFF", - "glyphColor": "#FFFFFF", - }, - {"lat": 34.0488, "lng": -118.2518, "name": "Downtown Flagship"}, - {"lat": 34.1016, "lng": -118.3287, "name": "Hollywood Boulevard Store"}, - {"lat": 34.1478, "lng": -118.1445, "name": "Pasadena Location"}, - {"lat": 33.7701, "lng": -118.1937, "name": "Long Beach Outlet"}, - {"lat": 34.0736, "lng": -118.4004, "name": "Beverly Hills Boutique"}, - ], - } + return { + "center": {"lat": 34, "lng": -118.2437}, + "zoom": 10, + "locations": [ + { + "lat": 34.0195, + "lng": -118.4912, + "name": "Santa Monica Branch", + "description": "High traffic coastal location.", + "outlier_reason": "Yes, 15% sales over baseline", + "background": "#4285F4", + "borderColor": "#FFFFFF", + "glyphColor": "#FFFFFF", + }, + {"lat": 34.0488, "lng": -118.2518, "name": "Downtown Flagship"}, + {"lat": 34.1016, "lng": -118.3287, "name": "Hollywood Boulevard Store"}, + {"lat": 34.1478, "lng": -118.1445, "name": "Pasadena Location"}, + {"lat": 33.7701, "lng": -118.1937, "name": "Long Beach Outlet"}, + {"lat": 34.0736, "lng": -118.4004, "name": "Beverly Hills Boutique"}, + ], + } def get_sales_data(time_period: str = "year", **kwargs: Any) -> dict[str, Any]: - """ - Gets the sales data. + """ + Gets the sales data. - Args: - time_period: The time period to get sales data for (e.g. 'Q1', 'year'). Defaults to 'year'. - **kwargs: Additional arguments. + Args: + time_period: The time period to get sales data for (e.g. 'Q1', 'year'). Defaults to 'year'. + **kwargs: Additional arguments. - Returns: - A dict containing the sales breakdown by product category. - """ - logger.info( - "get_sales_data called with time_period=%s, kwargs=%s", time_period, kwargs - ) + Returns: + A dict containing the sales breakdown by product category. + """ + logger.info( + "get_sales_data called with time_period=%s, kwargs=%s", time_period, kwargs + ) - return { - "sales_data": [ - { - "label": "Apparel", - "value": 41, - "drillDown": [ - {"label": "Tops", "value": 31}, - {"label": "Bottoms", "value": 38}, - {"label": "Outerwear", "value": 20}, - {"label": "Footwear", "value": 11}, - ], - }, - { - "label": "Home Goods", - "value": 15, - "drillDown": [ - {"label": "Pillow", "value": 8}, - {"label": "Coffee Maker", "value": 16}, - {"label": "Area Rug", "value": 3}, - {"label": "Bath Towels", "value": 14}, - ], - }, - { - "label": "Electronics", - "value": 28, - "drillDown": [ - {"label": "Phones", "value": 25}, - {"label": "Laptops", "value": 27}, - {"label": "TVs", "value": 21}, - {"label": "Other", "value": 27}, - ], - }, - {"label": "Health & Beauty", "value": 10}, - {"label": "Other", "value": 6}, - ] - } + return { + "sales_data": [ + { + "label": "Apparel", + "value": 41, + "drillDown": [ + {"label": "Tops", "value": 31}, + {"label": "Bottoms", "value": 38}, + {"label": "Outerwear", "value": 20}, + {"label": "Footwear", "value": 11}, + ], + }, + { + "label": "Home Goods", + "value": 15, + "drillDown": [ + {"label": "Pillow", "value": 8}, + {"label": "Coffee Maker", "value": 16}, + {"label": "Area Rug", "value": 3}, + {"label": "Bath Towels", "value": 14}, + ], + }, + { + "label": "Electronics", + "value": 28, + "drillDown": [ + {"label": "Phones", "value": 25}, + {"label": "Laptops", "value": 27}, + {"label": "TVs", "value": 21}, + {"label": "Other", "value": 27}, + ], + }, + {"label": "Health & Beauty", "value": 10}, + {"label": "Other", "value": 6}, + ] + } diff --git a/samples/agent/mcp/server.py b/samples/agent/mcp/server.py index 5d4958571..cef4b5492 100644 --- a/samples/agent/mcp/server.py +++ b/samples/agent/mcp/server.py @@ -26,32 +26,32 @@ def load_a2ui_schema() -> dict[str, Any]: - current_dir = pathlib.Path(__file__).resolve().parent - spec_root = current_dir / "../../../specification/v0_8/json" + current_dir = pathlib.Path(__file__).resolve().parent + spec_root = current_dir / "../../../specification/v0_8/json" - server_to_client_content = (spec_root / "server_to_client.json").read_text() - server_to_client_json = json.loads(server_to_client_content) + server_to_client_content = (spec_root / "server_to_client.json").read_text() + server_to_client_json = json.loads(server_to_client_content) - standard_catalog_content = ( - spec_root / "standard_catalog_definition.json" - ).read_text() - standard_catalog_json = json.loads(standard_catalog_content) + standard_catalog_content = ( + spec_root / "standard_catalog_definition.json" + ).read_text() + standard_catalog_json = json.loads(standard_catalog_content) - server_to_client_json["properties"]["surfaceUpdate"]["properties"]["components"][ - "items" - ]["properties"]["component"]["properties"] = standard_catalog_json + server_to_client_json["properties"]["surfaceUpdate"]["properties"]["components"][ + "items" + ]["properties"]["component"]["properties"] = standard_catalog_json - return wrap_as_json_array(server_to_client_json) + return wrap_as_json_array(server_to_client_json) def load_a2ui_client_to_server_schema() -> dict[str, Any]: - current_dir = pathlib.Path(__file__).resolve().parent - spec_root = current_dir / "../../../specification/v0_8/json" + current_dir = pathlib.Path(__file__).resolve().parent + spec_root = current_dir / "../../../specification/v0_8/json" - client_to_server_content = (spec_root / "client_to_server.json").read_text() - client_to_server_json = json.loads(client_to_server_content) + client_to_server_content = (spec_root / "client_to_server.json").read_text() + client_to_server_json = json.loads(client_to_server_content) - return client_to_server_json + return client_to_server_json @click.command() @@ -63,124 +63,130 @@ def load_a2ui_client_to_server_schema() -> dict[str, Any]: help="Transport type", ) def main(port: int, transport: str) -> int: - a2ui_schema = load_a2ui_schema() - print(f"Loaded A2UI schema: {a2ui_schema}") + a2ui_schema = load_a2ui_schema() + print(f"Loaded A2UI schema: {a2ui_schema}") - recipe_a2ui_json = json.loads( - (pathlib.Path(__file__).resolve().parent / "recipe_a2ui.json").read_text() - ) - jsonschema.validate(instance=recipe_a2ui_json, schema=a2ui_schema) - print(f"Loaded Recipe A2UI JSON: {recipe_a2ui_json}") + recipe_a2ui_json = json.loads( + (pathlib.Path(__file__).resolve().parent / "recipe_a2ui.json").read_text() + ) + jsonschema.validate(instance=recipe_a2ui_json, schema=a2ui_schema) + print(f"Loaded Recipe A2UI JSON: {recipe_a2ui_json}") - a2ui_client_to_server_schema = load_a2ui_client_to_server_schema() - print(f"Loaded A2UI client to server schema: {a2ui_client_to_server_schema}") + a2ui_client_to_server_schema = load_a2ui_client_to_server_schema() + print(f"Loaded A2UI client to server schema: {a2ui_client_to_server_schema}") - app = Server("a2ui-over-mcp-demo") + app = Server("a2ui-over-mcp-demo") - @app.call_tool() - async def handle_call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]: - if name == "get_recipe_a2ui": - return {"events": recipe_a2ui_json} + @app.call_tool() + async def handle_call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]: + if name == "get_recipe_a2ui": + return {"events": recipe_a2ui_json} - if name == "send_a2ui_user_action": - return {"response": f"Received A2UI user action", "args": arguments} + if name == "send_a2ui_user_action": + return {"response": f"Received A2UI user action", "args": arguments} - if name == "send_a2ui_error": - return {"response": f"Received A2UI error", "args": arguments} + if name == "send_a2ui_error": + return {"response": f"Received A2UI error", "args": arguments} - raise ValueError(f"Unknown tool: {name}") + raise ValueError(f"Unknown tool: {name}") - @app.list_resources() - async def list_resources() -> list[types.Resource]: - return [ - types.Resource( - uri="ui://calculator/app", - name="Calculator App", - mimeType="text/html;profile=mcp-app", - description="A simple calculator application", - ) - ] - - @app.read_resource() - async def read_resource(uri: Any) -> str | bytes: - if str(uri) == "ui://calculator/app": - return (pathlib.Path(__file__).parent / "apps" / "calculator.html").read_text() - raise ValueError(f"Unknown resource: {uri}") - - @app.list_tools() - async def list_tools() -> list[types.Tool]: - return [ - types.Tool( - name="get_recipe_a2ui", - title="Get Recipe A2UI", - description="Returns the A2UI JSON to show a recipe", - inputSchema={"type": "object", "additionalProperties": False}, - # MCP throws an error for "type":"array" so wrapping in an object - # TODO fix this in MCP SDK - outputSchema={ - "type": "object", - "properties": {"events": a2ui_schema}, - "required": ["events"], - "additionalProperties": False, - }, - ), - types.Tool( - name="send_a2ui_user_action", - title="Send A2UI User Action", - description="Sends an A2UI user action", - inputSchema=a2ui_client_to_server_schema["properties"]["userAction"], - ), - types.Tool( - name="send_a2ui_error", - title="Send A2UI Error", - description="Sends an A2UI error", - inputSchema=a2ui_client_to_server_schema["properties"]["error"], - ), - ] - - if transport == "sse": - from mcp.server.sse import SseServerTransport - from starlette.applications import Starlette - from starlette.responses import Response - from starlette.routing import Mount, Route - from starlette.middleware import Middleware - from starlette.middleware.cors import CORSMiddleware - - sse = SseServerTransport("/messages/") - - async def handle_sse(request: Request): - async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage] - await app.run(streams[0], streams[1], app.create_initialization_options()) - return Response() - - starlette_app = Starlette( - debug=True, - routes=[ - Route("/sse", endpoint=handle_sse, methods=["GET"]), - Mount("/messages/", app=sse.handle_post_message), - ], - middleware=[ - Middleware( - CORSMiddleware, - allow_origins=["*"], - allow_methods=["*"], - allow_headers=["*"], + @app.list_resources() + async def list_resources() -> list[types.Resource]: + return [ + types.Resource( + uri="ui://calculator/app", + name="Calculator App", + mimeType="text/html;profile=mcp-app", + description="A simple calculator application", ) - ], - ) + ] + + @app.read_resource() + async def read_resource(uri: Any) -> str | bytes: + if str(uri) == "ui://calculator/app": + return ( + pathlib.Path(__file__).parent / "apps" / "calculator.html" + ).read_text() + raise ValueError(f"Unknown resource: {uri}") + + @app.list_tools() + async def list_tools() -> list[types.Tool]: + return [ + types.Tool( + name="get_recipe_a2ui", + title="Get Recipe A2UI", + description="Returns the A2UI JSON to show a recipe", + inputSchema={"type": "object", "additionalProperties": False}, + # MCP throws an error for "type":"array" so wrapping in an object + # TODO fix this in MCP SDK + outputSchema={ + "type": "object", + "properties": {"events": a2ui_schema}, + "required": ["events"], + "additionalProperties": False, + }, + ), + types.Tool( + name="send_a2ui_user_action", + title="Send A2UI User Action", + description="Sends an A2UI user action", + inputSchema=a2ui_client_to_server_schema["properties"]["userAction"], + ), + types.Tool( + name="send_a2ui_error", + title="Send A2UI Error", + description="Sends an A2UI error", + inputSchema=a2ui_client_to_server_schema["properties"]["error"], + ), + ] + + if transport == "sse": + from mcp.server.sse import SseServerTransport + from starlette.applications import Starlette + from starlette.responses import Response + from starlette.routing import Mount, Route + from starlette.middleware import Middleware + from starlette.middleware.cors import CORSMiddleware + + sse = SseServerTransport("/messages/") + + async def handle_sse(request: Request): + async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage] + await app.run( + streams[0], streams[1], app.create_initialization_options() + ) + return Response() + + starlette_app = Starlette( + debug=True, + routes=[ + Route("/sse", endpoint=handle_sse, methods=["GET"]), + Mount("/messages/", app=sse.handle_post_message), + ], + middleware=[ + Middleware( + CORSMiddleware, + allow_origins=["*"], + allow_methods=["*"], + allow_headers=["*"], + ) + ], + ) - import uvicorn + import uvicorn - print(f"Server running at 127.0.0.1:{port} using sse") - uvicorn.run(starlette_app, host="127.0.0.1", port=port) - else: - from mcp.server.stdio import stdio_server + print(f"Server running at 127.0.0.1:{port} using sse") + uvicorn.run(starlette_app, host="127.0.0.1", port=port) + else: + from mcp.server.stdio import stdio_server - async def arun(): - async with stdio_server() as streams: - await app.run(streams[0], streams[1], app.create_initialization_options()) + async def arun(): + async with stdio_server() as streams: + await app.run( + streams[0], streams[1], app.create_initialization_options() + ) - click.echo("Server running using stdio", err=True) - anyio.run(arun) + click.echo("Server running using stdio", err=True) + anyio.run(arun) - return 0 + return 0 diff --git a/samples/client/lit/contact/sandbox.html b/samples/client/lit/contact/sandbox.html index 2a9960c1d..06bc7b678 100644 --- a/samples/client/lit/contact/sandbox.html +++ b/samples/client/lit/contact/sandbox.html @@ -1,3 +1,18 @@ + diff --git a/samples/client/lit/contact/ui/sandbox.ts b/samples/client/lit/contact/ui/sandbox.ts index 7c39446ce..e750637d4 100644 --- a/samples/client/lit/contact/ui/sandbox.ts +++ b/samples/client/lit/contact/ui/sandbox.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import type { McpUiSandboxProxyReadyNotification, McpUiSandboxResourceReadyNotification } from "@modelcontextprotocol/ext-apps/app-bridge"; import { buildAllowAttribute } from "@modelcontextprotocol/ext-apps/app-bridge"; diff --git a/samples/personalized_learning/agent/agent.py b/samples/personalized_learning/agent/agent.py index 39db9cb09..6035cbf9d 100644 --- a/samples/personalized_learning/agent/agent.py +++ b/samples/personalized_learning/agent/agent.py @@ -36,8 +36,8 @@ # Try multiple possible .env locations env_paths = [ Path(__file__).parent.parent / ".env", # samples/personalized_learning/.env - Path(__file__).parent / ".env", # agent/.env - Path.cwd() / ".env", # current working directory + Path(__file__).parent / ".env", # agent/.env + Path.cwd() / ".env", # current working directory ] for env_path in env_paths: if env_path.exists(): @@ -63,6 +63,7 @@ from .context_loader import get_combined_context, load_context_file from .a2ui_templates import get_system_prompt, SURFACE_ID as _IMPORTED_SURFACE_ID from .openstax_content import fetch_content_for_topic + _HAS_EXTERNAL_MODULES = True _HAS_OPENSTAX = True except Exception as e: @@ -78,7 +79,7 @@ logger.error( "Required modules (context_loader, a2ui_templates) not available. " "Import error: %s", - _IMPORT_ERROR if '_IMPORT_ERROR' in globals() else "unknown" + _IMPORT_ERROR if "_IMPORT_ERROR" in globals() else "unknown", ) if not _HAS_OPENSTAX: @@ -97,7 +98,6 @@ SURFACE_ID = _IMPORTED_SURFACE_ID if _HAS_EXTERNAL_MODULES else "learningContent" - # Context cache with TTL for performance _CONTEXT_CACHE: dict[str, Tuple[str, float]] = {} _CONTEXT_CACHE_TTL = 300 # 5 minutes @@ -216,12 +216,15 @@ async def generate_flashcards( openstax_content = content_result.get("combined_content", "") sources = content_result.get("sources", []) matched_chapters = content_result.get("matched_chapters", []) - logger.info(f"OpenStax: matched {len(matched_chapters)} chapters, {len(openstax_content)} chars") + logger.info( + f"OpenStax: matched {len(matched_chapters)} chapters, {len(openstax_content)} chars" + ) if not openstax_content: logger.warning("NO CONTENT RETURNED from OpenStax fetch!") except Exception as e: logger.error(f"FAILED to fetch OpenStax content: {e}") import traceback + logger.error(traceback.format_exc()) # Combine learner context with OpenStax source material @@ -369,9 +372,7 @@ async def get_audio_content( }, { "id": "audioIcon", - "component": { - "Icon": {"name": {"literalString": "podcasts"}} - }, + "component": {"Icon": {"name": {"literalString": "podcasts"}}}, }, { "id": "audioTitle", @@ -586,7 +587,9 @@ async def _generate_a2ui_content( if not project: logger.error("GOOGLE_CLOUD_PROJECT not configured") - return {"error": "GOOGLE_CLOUD_PROJECT not configured. Set it in environment or deploy.py."} + return { + "error": "GOOGLE_CLOUD_PROJECT not configured. Set it in environment or deploy.py." + } client = genai.Client( vertexai=True, @@ -700,6 +703,7 @@ async def _generate_a2ui_content( and explain the content to the learner. """ + def create_agent() -> Agent: """Create the ADK agent with all tools.""" return Agent( @@ -719,5 +723,3 @@ def create_agent() -> Agent: # Module-level agent for local development with `adk web` root_agent = create_agent() - - diff --git a/samples/personalized_learning/agent/download_openstax.py b/samples/personalized_learning/agent/download_openstax.py index 33d354a98..b277e0f4b 100644 --- a/samples/personalized_learning/agent/download_openstax.py +++ b/samples/personalized_learning/agent/download_openstax.py @@ -140,7 +140,9 @@ def upload_module(module_id: str) -> tuple[str, bool, str]: # Use thread pool for parallel uploads with ThreadPoolExecutor(max_workers=workers) as executor: - futures = {executor.submit(upload_module, mid): mid for mid in sorted(module_ids)} + futures = { + executor.submit(upload_module, mid): mid for mid in sorted(module_ids) + } for future in as_completed(futures): module_id, success, message = future.result() @@ -302,7 +304,9 @@ def main(): local_success, local_fail = copy_modules_locally( modules_dir, local_dir, needed_modules ) - print(f"Local copy complete: {local_success} succeeded, {local_fail} failed") + print( + f"Local copy complete: {local_success} succeeded, {local_fail} failed" + ) # Upload to GCS if not local-only if not args.local_only and args.bucket: diff --git a/samples/personalized_learning/agent/openstax_chapters.py b/samples/personalized_learning/agent/openstax_chapters.py index c41a12745..222ee04d6 100644 --- a/samples/personalized_learning/agent/openstax_chapters.py +++ b/samples/personalized_learning/agent/openstax_chapters.py @@ -34,7 +34,9 @@ """ # GitHub raw content base URL for fetching module content -GITHUB_RAW_BASE = "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" +GITHUB_RAW_BASE = ( + "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" +) # OpenStax website base URL for citations OPENSTAX_WEB_BASE = "https://openstax.org/books/biology-ap-courses/pages" @@ -52,7 +54,6 @@ "3-3-lipids": "Lipids", "3-4-proteins": "Proteins", "3-5-nucleic-acids": "Nucleic Acids", - # Unit 2: The Cell "4-1-studying-cells": "Studying Cells", "4-2-prokaryotic-cells": "Prokaryotic Cells", @@ -88,7 +89,6 @@ "10-3-control-of-the-cell-cycle": "Control of the Cell Cycle", "10-4-cancer-and-the-cell-cycle": "Cancer and the Cell Cycle", "10-5-prokaryotic-cell-division": "Prokaryotic Cell Division", - # Unit 3: Genetics "11-1-the-process-of-meiosis": "The Process of Meiosis", "11-2-sexual-reproduction": "Sexual Reproduction", @@ -120,7 +120,6 @@ "17-3-whole-genome-sequencing": "Whole-Genome Sequencing", "17-4-applying-genomics": "Applying Genomics", "17-5-genomics-and-proteomics": "Genomics and Proteomics", - # Unit 4: Evolutionary Processes "18-1-understanding-evolution": "Understanding Evolution", "18-2-formation-of-new-species": "Formation of New Species", @@ -131,7 +130,6 @@ "20-1-organizing-life-on-earth": "Organizing Life on Earth", "20-2-determining-evolutionary-relationships": "Determining Evolutionary Relationships", "20-3-perspectives-on-the-phylogenetic-tree": "Perspectives on the Phylogenetic Tree", - # Unit 5: Biological Diversity "21-1-viral-evolution-morphology-and-classification": "Viral Evolution, Morphology, and Classification", "21-2-virus-infection-and-hosts": "Virus Infection and Hosts", @@ -142,7 +140,6 @@ "22-3-prokaryotic-metabolism": "Prokaryotic Metabolism", "22-4-bacterial-diseases-in-humans": "Bacterial Diseases in Humans", "22-5-beneficial-prokaryotes": "Beneficial Prokaryotes", - # Unit 6: Plant Structure and Function "23-1-the-plant-body": "The Plant Body", "23-2-stems": "Stems", @@ -150,7 +147,6 @@ "23-4-leaves": "Leaves", "23-5-transport-of-water-and-solutes-in-plants": "Transport of Water and Solutes in Plants", "23-6-plant-sensory-systems-and-responses": "Plant Sensory Systems and Responses", - # Unit 7: Animal Structure and Function "24-1-animal-form-and-function": "Animal Form and Function", "24-2-animal-primary-tissues": "Animal Primary Tissues", @@ -202,7 +198,6 @@ "34-5-fertilization-and-early-embryonic-development": "Fertilization and Early Embryonic Development", "34-6-organogenesis-and-vertebrate-axis-formation": "Organogenesis and Vertebrate Axis Formation", "34-7-human-pregnancy-and-birth": "Human Pregnancy and Birth", - # Unit 8: Ecology "35-1-the-scope-of-ecology": "The Scope of Ecology", "35-2-biogeography": "Biogeography", @@ -225,6 +220,7 @@ "38-4-preserving-biodiversity": "Preserving Biodiversity", } + # Build a formatted string for LLM context def get_chapter_list_for_llm() -> str: """Return a formatted list of all chapters for LLM context.""" @@ -243,13 +239,19 @@ def get_chapter_list_for_llm() -> str: "adenosine triphosphate": ["6-4-atp-adenosine-triphosphate"], "adp": ["6-4-atp-adenosine-triphosphate"], "adenosine diphosphate": ["6-4-atp-adenosine-triphosphate"], - "cellular energy": ["6-4-atp-adenosine-triphosphate", "7-1-energy-in-living-systems"], + "cellular energy": [ + "6-4-atp-adenosine-triphosphate", + "7-1-energy-in-living-systems", + ], "cell energy": ["6-4-atp-adenosine-triphosphate", "7-1-energy-in-living-systems"], "high energy bond": ["6-4-atp-adenosine-triphosphate"], "phosphate bond": ["6-4-atp-adenosine-triphosphate"], "phosphate group": ["6-4-atp-adenosine-triphosphate"], "energy currency": ["6-4-atp-adenosine-triphosphate"], - "energy transfer": ["6-4-atp-adenosine-triphosphate", "7-4-oxidative-phosphorylation"], + "energy transfer": [ + "6-4-atp-adenosine-triphosphate", + "7-4-oxidative-phosphorylation", + ], "bond breaking": ["6-4-atp-adenosine-triphosphate"], "bond energy": ["6-4-atp-adenosine-triphosphate", "6-1-energy-and-metabolism"], "hydrolysis": ["6-4-atp-adenosine-triphosphate"], @@ -261,13 +263,19 @@ def get_chapter_list_for_llm() -> str: "first law": ["6-3-the-laws-of-thermodynamics"], "second law": ["6-3-the-laws-of-thermodynamics"], "entropy": ["6-3-the-laws-of-thermodynamics"], - "photosynthesis": ["8-1-overview-of-photosynthesis", "8-2-the-light-dependent-reaction-of-photosynthesis"], + "photosynthesis": [ + "8-1-overview-of-photosynthesis", + "8-2-the-light-dependent-reaction-of-photosynthesis", + ], "plants make food": ["8-1-overview-of-photosynthesis"], "chloroplast": ["8-1-overview-of-photosynthesis", "4-3-eukaryotic-cells"], "chlorophyll": ["8-2-the-light-dependent-reaction-of-photosynthesis"], "calvin cycle": ["8-3-using-light-to-make-organic-molecules"], "light reaction": ["8-2-the-light-dependent-reaction-of-photosynthesis"], - "cellular respiration": ["7-1-energy-in-living-systems", "7-4-oxidative-phosphorylation"], + "cellular respiration": [ + "7-1-energy-in-living-systems", + "7-4-oxidative-phosphorylation", + ], "glycolysis": ["7-2-glycolysis"], "krebs": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle"], "citric acid": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle"], @@ -278,21 +286,25 @@ def get_chapter_list_for_llm() -> str: "anaerobic": ["7-5-metabolism-without-oxygen"], "mitochondria": ["7-4-oxidative-phosphorylation", "4-3-eukaryotic-cells"], "mitochondrion": ["7-4-oxidative-phosphorylation", "4-3-eukaryotic-cells"], - # Cell Division "mitosis": ["10-1-cell-division", "10-2-the-cell-cycle"], "meiosis": ["11-1-the-process-of-meiosis"], "cell cycle": ["10-2-the-cell-cycle", "10-3-control-of-the-cell-cycle"], "cell division": ["10-1-cell-division"], "cancer": ["10-4-cancer-and-the-cell-cycle", "16-7-cancer-and-gene-regulation"], - # Molecular Biology "dna": ["14-2-dna-structure-and-sequencing", "14-3-basics-of-dna-replication"], "rna": ["15-4-rna-processing-in-eukaryotes", "3-5-nucleic-acids"], - "mrna": ["15-4-rna-processing-in-eukaryotes", "15-5-ribosomes-and-protein-synthesis"], + "mrna": [ + "15-4-rna-processing-in-eukaryotes", + "15-5-ribosomes-and-protein-synthesis", + ], "trna": ["15-5-ribosomes-and-protein-synthesis"], "rrna": ["15-5-ribosomes-and-protein-synthesis"], - "transcription": ["15-2-prokaryotic-transcription", "15-3-eukaryotic-transcription"], + "transcription": [ + "15-2-prokaryotic-transcription", + "15-3-eukaryotic-transcription", + ], "translation": ["15-5-ribosomes-and-protein-synthesis"], "protein synthesis": ["15-5-ribosomes-and-protein-synthesis"], "protein": ["3-4-proteins", "15-5-ribosomes-and-protein-synthesis"], @@ -303,8 +315,10 @@ def get_chapter_list_for_llm() -> str: "codon": ["15-1-the-genetic-code"], "anticodon": ["15-5-ribosomes-and-protein-synthesis"], "ribosome": ["15-5-ribosomes-and-protein-synthesis", "4-3-eukaryotic-cells"], - "replication": ["14-3-basics-of-dna-replication", "14-4-dna-replication-in-prokaryotes"], - + "replication": [ + "14-3-basics-of-dna-replication", + "14-4-dna-replication-in-prokaryotes", + ], # Cell Structure "cell membrane": ["5-1-components-and-structure"], "plasma membrane": ["5-1-components-and-structure"], @@ -322,31 +336,39 @@ def get_chapter_list_for_llm() -> str: "vesicle": ["5-4-bulk-transport", "4-4-the-endomembrane-system-and-proteins"], "endocytosis": ["5-4-bulk-transport"], "exocytosis": ["5-4-bulk-transport"], - "signal transduction": ["9-1-signaling-molecules-and-cellular-receptors", "9-2-propagation-of-the-signal"], + "signal transduction": [ + "9-1-signaling-molecules-and-cellular-receptors", + "9-2-propagation-of-the-signal", + ], "cell signaling": ["9-1-signaling-molecules-and-cellular-receptors"], - # Nervous System "neuron": ["26-1-neurons-and-glial-cells", "26-2-how-neurons-communicate"], - "nervous system": ["26-1-neurons-and-glial-cells", "26-3-the-central-nervous-system"], + "nervous system": [ + "26-1-neurons-and-glial-cells", + "26-3-the-central-nervous-system", + ], "brain": ["26-3-the-central-nervous-system"], "action potential": ["26-2-how-neurons-communicate"], "synapse": ["26-2-how-neurons-communicate"], "senses": ["27-1-sensory-processes"], "vision": ["27-5-vision"], "hearing": ["27-4-hearing-and-vestibular-sensation"], - # Circulatory System - "heart": ["31-1-overview-of-the-circulatory-system", "31-3-mammalian-heart-and-blood-vessels"], - "blood": ["31-2-components-of-the-blood", "31-1-overview-of-the-circulatory-system"], + "heart": [ + "31-1-overview-of-the-circulatory-system", + "31-3-mammalian-heart-and-blood-vessels", + ], + "blood": [ + "31-2-components-of-the-blood", + "31-1-overview-of-the-circulatory-system", + ], "circulatory": ["31-1-overview-of-the-circulatory-system"], "cardiovascular": ["31-1-overview-of-the-circulatory-system"], - # Immune System "immune": ["33-1-innate-immune-response", "33-2-adaptive-immune-response"], "antibod": ["33-3-antibodies"], "infection": ["33-1-innate-immune-response"], "vaccine": ["33-2-adaptive-immune-response"], - # Other Body Systems "respiration": ["30-1-systems-of-gas-exchange", "30-3-breathing"], "breathing": ["30-3-breathing"], @@ -354,9 +376,22 @@ def get_chapter_list_for_llm() -> str: "digestion": ["25-1-digestive-systems", "25-3-digestive-system-processes"], "stomach": ["25-1-digestive-systems"], "intestine": ["25-3-digestive-system-processes"], - "hormone": ["28-1-types-of-hormones", "28-2-how-hormones-work", "28-4-regulation-of-hormone-production"], - "endocrine": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work"], - "endocrine system": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work", "28-3-regulation-of-body-processes"], + "hormone": [ + "28-1-types-of-hormones", + "28-2-how-hormones-work", + "28-4-regulation-of-hormone-production", + ], + "endocrine": [ + "28-5-endocrine-glands", + "28-1-types-of-hormones", + "28-2-how-hormones-work", + ], + "endocrine system": [ + "28-5-endocrine-glands", + "28-1-types-of-hormones", + "28-2-how-hormones-work", + "28-3-regulation-of-body-processes", + ], "pituitary": ["28-5-endocrine-glands", "28-4-regulation-of-hormone-production"], "thyroid": ["28-5-endocrine-glands", "28-3-regulation-of-body-processes"], "adrenal": ["28-5-endocrine-glands"], @@ -368,30 +403,46 @@ def get_chapter_list_for_llm() -> str: "skeleton": ["29-1-types-of-skeletal-systems"], "kidney": ["32-2-the-kidneys-and-osmoregulatory-organs"], "excretion": ["32-3-excretion-systems"], - "reproduction": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], - "reproductive": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], - "reproductive system": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis", "34-4-hormonal-control-of-human-reproduction"], + "reproduction": [ + "34-1-reproduction-methods", + "34-3-human-reproductive-anatomy-and-gametogenesis", + ], + "reproductive": [ + "34-1-reproduction-methods", + "34-3-human-reproductive-anatomy-and-gametogenesis", + ], + "reproductive system": [ + "34-1-reproduction-methods", + "34-3-human-reproductive-anatomy-and-gametogenesis", + "34-4-hormonal-control-of-human-reproduction", + ], "pregnancy": ["34-7-human-pregnancy-and-birth"], "embryo": ["34-5-fertilization-and-early-embryonic-development"], - # Evolution & Genetics "evolution": ["18-1-understanding-evolution", "19-1-population-evolution"], "darwin": ["18-1-understanding-evolution"], - "natural selection": ["19-3-adaptive-evolution", "36-2-life-histories-and-natural-selection"], + "natural selection": [ + "19-3-adaptive-evolution", + "36-2-life-histories-and-natural-selection", + ], "speciation": ["18-2-formation-of-new-species"], - "genetics": ["12-1-mendels-experiments-and-the-laws-of-probability", "12-3-laws-of-inheritance"], + "genetics": [ + "12-1-mendels-experiments-and-the-laws-of-probability", + "12-3-laws-of-inheritance", + ], "mendel": ["12-1-mendels-experiments-and-the-laws-of-probability"], "inheritance": ["12-3-laws-of-inheritance"], "heredity": ["12-3-laws-of-inheritance"], "mutation": ["14-6-dna-repair"], "phylogen": ["20-2-determining-evolutionary-relationships"], - # Microorganisms - "virus": ["21-1-viral-evolution-morphology-and-classification", "21-2-virus-infection-and-hosts"], + "virus": [ + "21-1-viral-evolution-morphology-and-classification", + "21-2-virus-infection-and-hosts", + ], "bacteria": ["22-1-prokaryotic-diversity", "22-4-bacterial-diseases-in-humans"], "prokaryote": ["4-2-prokaryotic-cells", "22-1-prokaryotic-diversity"], "eukaryote": ["4-3-eukaryotic-cells"], - # Plants "plant": ["23-1-the-plant-body"], "leaf": ["23-4-leaves"], @@ -399,20 +450,21 @@ def get_chapter_list_for_llm() -> str: "stem": ["23-2-stems"], "xylem": ["23-5-transport-of-water-and-solutes-in-plants"], "phloem": ["23-5-transport-of-water-and-solutes-in-plants"], - # Ecology "ecology": ["35-1-the-scope-of-ecology", "36-6-community-ecology"], "ecosystem": ["37-1-ecology-for-ecosystems", "37-2-energy-flow-through-ecosystems"], "food chain": ["37-2-energy-flow-through-ecosystems"], "food web": ["37-2-energy-flow-through-ecosystems"], "biome": ["35-3-terrestrial-biomes", "35-4-aquatic-biomes"], - "population": ["36-1-population-demography", "36-3-environmental-limits-to-population-growth"], + "population": [ + "36-1-population-demography", + "36-3-environmental-limits-to-population-growth", + ], "climate": ["35-5-climate-and-the-effects-of-global-climate-change"], "climate change": ["35-5-climate-and-the-effects-of-global-climate-change"], "biodiversity": ["38-1-the-biodiversity-crisis", "38-4-preserving-biodiversity"], "carbon cycle": ["37-3-biogeochemical-cycles"], "nitrogen cycle": ["37-3-biogeochemical-cycles"], - # Chemistry Basics "atom": ["2-1-atoms-isotopes-ions-and-molecules-the-building-blocks"], "water": ["2-2-water"], @@ -420,14 +472,12 @@ def get_chapter_list_for_llm() -> str: "carbohydrate": ["3-2-carbohydrates"], "lipid": ["3-3-lipids"], "nucleic acid": ["3-5-nucleic-acids"], - # Biotechnology "biotechnology": ["17-1-biotechnology"], "crispr": ["17-1-biotechnology"], "cloning": ["17-1-biotechnology"], "genome": ["17-2-mapping-genomes", "17-3-whole-genome-sequencing"], "genomics": ["17-4-applying-genomics", "17-5-genomics-and-proteomics"], - # Additional keywords for better coverage (plurals and common phrases) # Energy & Metabolism "light reactions": ["8-2-the-light-dependent-reaction-of-photosynthesis"], @@ -437,7 +487,6 @@ def get_chapter_list_for_llm() -> str: "proteins": ["3-4-proteins", "15-5-ribosomes-and-protein-synthesis"], "nucleic acids": ["3-5-nucleic-acids"], "ribosomes": ["15-5-ribosomes-and-protein-synthesis", "4-3-eukaryotic-cells"], - # Body Systems (full names) "respiratory system": ["30-1-systems-of-gas-exchange", "30-3-breathing"], "digestive system": ["25-1-digestive-systems", "25-3-digestive-system-processes"], @@ -445,7 +494,6 @@ def get_chapter_list_for_llm() -> str: "muscular system": ["29-4-muscle-contraction-and-locomotion"], "circulatory system": ["31-1-overview-of-the-circulatory-system"], "immune system": ["33-1-innate-immune-response", "33-2-adaptive-immune-response"], - # Plurals "hormones": ["28-1-types-of-hormones", "28-2-how-hormones-work"], "neurons": ["26-1-neurons-and-glial-cells", "26-2-how-neurons-communicate"], @@ -453,16 +501,27 @@ def get_chapter_list_for_llm() -> str: "kidneys": ["32-2-the-kidneys-and-osmoregulatory-organs"], "antibodies": ["33-3-antibodies"], "mutations": ["14-6-dna-repair"], - "ecosystems": ["37-1-ecology-for-ecosystems", "37-2-energy-flow-through-ecosystems"], + "ecosystems": [ + "37-1-ecology-for-ecosystems", + "37-2-energy-flow-through-ecosystems", + ], "biomes": ["35-3-terrestrial-biomes", "35-4-aquatic-biomes"], - "viruses": ["21-1-viral-evolution-morphology-and-classification", "21-2-virus-infection-and-hosts"], + "viruses": [ + "21-1-viral-evolution-morphology-and-classification", + "21-2-virus-infection-and-hosts", + ], "prokaryotes": ["4-2-prokaryotic-cells", "22-1-prokaryotic-diversity"], "eukaryotes": ["4-3-eukaryotic-cells"], - "chromosomes": ["13-1-chromosomal-theory-and-genetic-linkages", "13-2-chromosomal-basis-of-inherited-disorders"], - + "chromosomes": [ + "13-1-chromosomal-theory-and-genetic-linkages", + "13-2-chromosomal-basis-of-inherited-disorders", + ], # Genetics "homeostasis": ["24-3-homeostasis"], - "chromosome": ["13-1-chromosomal-theory-and-genetic-linkages", "13-2-chromosomal-basis-of-inherited-disorders"], + "chromosome": [ + "13-1-chromosomal-theory-and-genetic-linkages", + "13-2-chromosomal-basis-of-inherited-disorders", + ], "allele": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], "alleles": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], "dominant": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], @@ -471,16 +530,20 @@ def get_chapter_list_for_llm() -> str: "recessive traits": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], "genetic disorders": ["13-2-chromosomal-basis-of-inherited-disorders"], "genetic disorder": ["13-2-chromosomal-basis-of-inherited-disorders"], - # Evolution "adaptation": ["19-3-adaptive-evolution"], - "phylogenetic": ["20-2-determining-evolutionary-relationships", "20-3-perspectives-on-the-phylogenetic-tree"], - "phylogenetics": ["20-2-determining-evolutionary-relationships", "20-3-perspectives-on-the-phylogenetic-tree"], + "phylogenetic": [ + "20-2-determining-evolutionary-relationships", + "20-3-perspectives-on-the-phylogenetic-tree", + ], + "phylogenetics": [ + "20-2-determining-evolutionary-relationships", + "20-3-perspectives-on-the-phylogenetic-tree", + ], "fossil": ["18-1-understanding-evolution"], "fossils": ["18-1-understanding-evolution"], "common ancestor": ["20-2-determining-evolutionary-relationships"], "ancestors": ["20-2-determining-evolutionary-relationships"], - # Ecology "energy flow": ["37-2-energy-flow-through-ecosystems"], "trophic": ["37-2-energy-flow-through-ecosystems"], diff --git a/samples/personalized_learning/agent/openstax_content.py b/samples/personalized_learning/agent/openstax_content.py index cfcf836a8..e29a7e8bd 100644 --- a/samples/personalized_learning/agent/openstax_content.py +++ b/samples/personalized_learning/agent/openstax_content.py @@ -35,22 +35,27 @@ logger = logging.getLogger(__name__) + # SSL context for GitHub fetches - uses certifi CA bundle if available def _get_ssl_context() -> ssl.SSLContext: """Get SSL context with proper CA certificates.""" try: import certifi + return ssl.create_default_context(cafile=certifi.where()) except ImportError: # certifi not available, use system defaults return ssl.create_default_context() + # GCS configuration GCS_OPENSTAX_BUCKET = os.getenv("GCS_OPENSTAX_BUCKET", "") GCS_OPENSTAX_PREFIX = os.getenv("GCS_OPENSTAX_PREFIX", "openstax_modules/") # GitHub configuration -GITHUB_RAW_BASE = "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" +GITHUB_RAW_BASE = ( + "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" +) # CNXML namespace CNXML_NS = {"cnxml": "http://cnx.rice.edu/cnxml"} @@ -147,15 +152,15 @@ def parse_cnxml_to_text(cnxml_content: str) -> str: full_text = "\n".join(text_parts) # Clean up excessive whitespace - full_text = re.sub(r'\n{3,}', '\n\n', full_text) - full_text = re.sub(r' {2,}', ' ', full_text) + full_text = re.sub(r"\n{3,}", "\n\n", full_text) + full_text = re.sub(r" {2,}", " ", full_text) return full_text.strip() except ET.ParseError as e: logger.error(f"Failed to parse CNXML: {e}") # Return raw content as fallback (stripped of XML tags) - return re.sub(r'<[^>]+>', ' ', cnxml_content).strip() + return re.sub(r"<[^>]+>", " ", cnxml_content).strip() def _extract_text_from_element(elem) -> str: @@ -219,8 +224,10 @@ def fetch_module_from_github(module_id: str) -> Optional[str]: url = f"{GITHUB_RAW_BASE}/{module_id}/index.cnxml" try: - with urllib.request.urlopen(url, timeout=10, context=_get_ssl_context()) as response: - content = response.read().decode('utf-8') + with urllib.request.urlopen( + url, timeout=10, context=_get_ssl_context() + ) as response: + content = response.read().decode("utf-8") logger.info(f"Fetched module {module_id} from GitHub") return content except urllib.error.HTTPError as e: @@ -323,8 +330,10 @@ def fetch_chapter_content(chapter_slug: str) -> Optional[dict]: if len(module_ids) > 1: # Use parallel fetching for multiple modules with ThreadPoolExecutor(max_workers=min(len(module_ids), 5)) as executor: - futures = {executor.submit(fetch_module_content_cached, mid): mid - for mid in module_ids} + futures = { + executor.submit(fetch_module_content_cached, mid): mid + for mid in module_ids + } for future in futures: try: result = future.result() @@ -373,8 +382,9 @@ def fetch_multiple_chapters(chapter_slugs: list[str]) -> list[dict]: # Parallel fetch for multiple chapters results = [] with ThreadPoolExecutor(max_workers=min(len(chapter_slugs), 3)) as executor: - futures = {executor.submit(fetch_chapter_content, slug): slug - for slug in chapter_slugs} + futures = { + executor.submit(fetch_chapter_content, slug): slug for slug in chapter_slugs + } for future in futures: try: result = future.result() @@ -430,7 +440,9 @@ async def fetch_modules_for_topic(topic: str, max_modules: int = 3) -> dict: # Search for matching modules using keyword matching logger.info("Step 1: Searching for modules using keyword matching...") matched_modules = search_modules(topic, max_results=max_modules) - logger.info(f"Keyword matching found {len(matched_modules)} modules: {[m.get('id', m.get('title', 'unknown')) for m in matched_modules]}") + logger.info( + f"Keyword matching found {len(matched_modules)} modules: {[m.get('id', m.get('title', 'unknown')) for m in matched_modules]}" + ) if not matched_modules: # Fall back to LLM matching for chapter, then get first module @@ -440,21 +452,26 @@ async def fetch_modules_for_topic(topic: str, max_modules: int = 3) -> dict: if chapter_slugs: # Import chapter-to-module mapping as fallback from .openstax_chapters import CHAPTER_TO_MODULES + if chapter_slugs[0] in CHAPTER_TO_MODULES: module_ids = CHAPTER_TO_MODULES[chapter_slugs[0]][:max_modules] logger.info(f"Found modules from chapter mapping: {module_ids}") for mid in module_ids: if mid in MODULE_INDEX: info = MODULE_INDEX[mid] - matched_modules.append({ - "id": mid, - "title": info["title"], - "unit": info["unit"], - "chapter": info["chapter"], - "url": get_module_url(mid), - }) + matched_modules.append( + { + "id": mid, + "title": info["title"], + "unit": info["unit"], + "chapter": info["chapter"], + "url": get_module_url(mid), + } + ) else: - logger.warning(f"Chapter {chapter_slugs[0]} not found in CHAPTER_TO_MODULES mapping") + logger.warning( + f"Chapter {chapter_slugs[0]} not found in CHAPTER_TO_MODULES mapping" + ) else: logger.warning("LLM matching also returned no chapters!") @@ -477,8 +494,10 @@ async def fetch_modules_for_topic(topic: str, max_modules: int = 3) -> dict: # Parallel fetch for multiple modules contents = [] with ThreadPoolExecutor(max_workers=min(len(module_ids), 5)) as executor: - futures = {executor.submit(fetch_module_content_cached, mid): mid - for mid in module_ids} + futures = { + executor.submit(fetch_module_content_cached, mid): mid + for mid in module_ids + } for future in futures: try: result = future.result() @@ -544,7 +563,11 @@ async def fetch_content_for_topic(topic: str, max_chapters: int = 3) -> dict: return { "topic": result["topic"], "matched_chapters": [ - {"slug": m.get("id", ""), "title": m.get("title", ""), "url": m.get("url", "")} + { + "slug": m.get("id", ""), + "title": m.get("title", ""), + "url": m.get("url", ""), + } for m in result.get("matched_modules", []) ], "combined_content": result.get("combined_content", ""), diff --git a/samples/personalized_learning/agent/openstax_modules.py b/samples/personalized_learning/agent/openstax_modules.py index 8a0714599..409b99485 100644 --- a/samples/personalized_learning/agent/openstax_modules.py +++ b/samples/personalized_learning/agent/openstax_modules.py @@ -284,215 +284,1035 @@ # Complete module index with titles, units, and chapters # Generated from the collection XML MODULE_INDEX = { - "m45849": {"title": "The Periodic Table of Elements", "unit": "Front Matter", "chapter": "Front Matter"}, - "m60107": {"title": "Geological Time", "unit": "Front Matter", "chapter": "Front Matter"}, - "m62716": {"title": "Introduction", "unit": "The Chemistry of Life", "chapter": "The Study of Life"}, - "m62717": {"title": "The Science of Biology", "unit": "The Chemistry of Life", "chapter": "The Study of Life"}, - "m62718": {"title": "Themes and Concepts of Biology", "unit": "The Chemistry of Life", "chapter": "The Study of Life"}, - "m62719": {"title": "Introduction", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, - "m62720": {"title": "Atoms, Isotopes, Ions, and Molecules: The Building Blocks", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, - "m62721": {"title": "Water", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, - "m62722": {"title": "Carbon", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, - "m62723": {"title": "Introduction", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, - "m62724": {"title": "Synthesis of Biological Macromolecules", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, - "m62726": {"title": "Carbohydrates", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, - "m62730": {"title": "Lipids", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, - "m62733": {"title": "Proteins", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, - "m62735": {"title": "Nucleic Acids", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, - "m62736": {"title": "Introduction", "unit": "The Cell", "chapter": "Cell Structure"}, - "m62738": {"title": "Studying Cells", "unit": "The Cell", "chapter": "Cell Structure"}, - "m62740": {"title": "Prokaryotic Cells", "unit": "The Cell", "chapter": "Cell Structure"}, - "m62742": {"title": "Eukaryotic Cells", "unit": "The Cell", "chapter": "Cell Structure"}, - "m62743": {"title": "The Endomembrane System and Proteins", "unit": "The Cell", "chapter": "Cell Structure"}, - "m62744": {"title": "Cytoskeleton", "unit": "The Cell", "chapter": "Cell Structure"}, - "m62746": {"title": "Connections between Cells and Cellular Activities", "unit": "The Cell", "chapter": "Cell Structure"}, - "m62753": {"title": "Passive Transport", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, + "m45849": { + "title": "The Periodic Table of Elements", + "unit": "Front Matter", + "chapter": "Front Matter", + }, + "m60107": { + "title": "Geological Time", + "unit": "Front Matter", + "chapter": "Front Matter", + }, + "m62716": { + "title": "Introduction", + "unit": "The Chemistry of Life", + "chapter": "The Study of Life", + }, + "m62717": { + "title": "The Science of Biology", + "unit": "The Chemistry of Life", + "chapter": "The Study of Life", + }, + "m62718": { + "title": "Themes and Concepts of Biology", + "unit": "The Chemistry of Life", + "chapter": "The Study of Life", + }, + "m62719": { + "title": "Introduction", + "unit": "The Chemistry of Life", + "chapter": "The Chemical Foundation of Life", + }, + "m62720": { + "title": "Atoms, Isotopes, Ions, and Molecules: The Building Blocks", + "unit": "The Chemistry of Life", + "chapter": "The Chemical Foundation of Life", + }, + "m62721": { + "title": "Water", + "unit": "The Chemistry of Life", + "chapter": "The Chemical Foundation of Life", + }, + "m62722": { + "title": "Carbon", + "unit": "The Chemistry of Life", + "chapter": "The Chemical Foundation of Life", + }, + "m62723": { + "title": "Introduction", + "unit": "The Chemistry of Life", + "chapter": "Biological Macromolecules", + }, + "m62724": { + "title": "Synthesis of Biological Macromolecules", + "unit": "The Chemistry of Life", + "chapter": "Biological Macromolecules", + }, + "m62726": { + "title": "Carbohydrates", + "unit": "The Chemistry of Life", + "chapter": "Biological Macromolecules", + }, + "m62730": { + "title": "Lipids", + "unit": "The Chemistry of Life", + "chapter": "Biological Macromolecules", + }, + "m62733": { + "title": "Proteins", + "unit": "The Chemistry of Life", + "chapter": "Biological Macromolecules", + }, + "m62735": { + "title": "Nucleic Acids", + "unit": "The Chemistry of Life", + "chapter": "Biological Macromolecules", + }, + "m62736": { + "title": "Introduction", + "unit": "The Cell", + "chapter": "Cell Structure", + }, + "m62738": { + "title": "Studying Cells", + "unit": "The Cell", + "chapter": "Cell Structure", + }, + "m62740": { + "title": "Prokaryotic Cells", + "unit": "The Cell", + "chapter": "Cell Structure", + }, + "m62742": { + "title": "Eukaryotic Cells", + "unit": "The Cell", + "chapter": "Cell Structure", + }, + "m62743": { + "title": "The Endomembrane System and Proteins", + "unit": "The Cell", + "chapter": "Cell Structure", + }, + "m62744": { + "title": "Cytoskeleton", + "unit": "The Cell", + "chapter": "Cell Structure", + }, + "m62746": { + "title": "Connections between Cells and Cellular Activities", + "unit": "The Cell", + "chapter": "Cell Structure", + }, + "m62753": { + "title": "Passive Transport", + "unit": "The Cell", + "chapter": "Structure and Function of Plasma Membranes", + }, "m62761": {"title": "Introduction", "unit": "The Cell", "chapter": "Metabolism"}, - "m62763": {"title": "Energy and Metabolism", "unit": "The Cell", "chapter": "Metabolism"}, - "m62764": {"title": "Potential, Kinetic, Free, and Activation Energy", "unit": "The Cell", "chapter": "Metabolism"}, - "m62767": {"title": "The Laws of Thermodynamics", "unit": "The Cell", "chapter": "Metabolism"}, - "m62768": {"title": "ATP: Adenosine Triphosphate", "unit": "The Cell", "chapter": "Metabolism"}, - "m62770": {"title": "Active Transport", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, - "m62772": {"title": "Bulk Transport", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, - "m62773": {"title": "Components and Structure", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, + "m62763": { + "title": "Energy and Metabolism", + "unit": "The Cell", + "chapter": "Metabolism", + }, + "m62764": { + "title": "Potential, Kinetic, Free, and Activation Energy", + "unit": "The Cell", + "chapter": "Metabolism", + }, + "m62767": { + "title": "The Laws of Thermodynamics", + "unit": "The Cell", + "chapter": "Metabolism", + }, + "m62768": { + "title": "ATP: Adenosine Triphosphate", + "unit": "The Cell", + "chapter": "Metabolism", + }, + "m62770": { + "title": "Active Transport", + "unit": "The Cell", + "chapter": "Structure and Function of Plasma Membranes", + }, + "m62772": { + "title": "Bulk Transport", + "unit": "The Cell", + "chapter": "Structure and Function of Plasma Membranes", + }, + "m62773": { + "title": "Components and Structure", + "unit": "The Cell", + "chapter": "Structure and Function of Plasma Membranes", + }, "m62778": {"title": "Enzymes", "unit": "The Cell", "chapter": "Metabolism"}, - "m62780": {"title": "Introduction", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, - "m62784": {"title": "Introduction", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62786": {"title": "Energy in Living Systems", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62787": {"title": "Glycolysis", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62788": {"title": "Oxidation of Pyruvate and the Citric Acid Cycle", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62789": {"title": "Oxidative Phosphorylation", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62790": {"title": "Metabolism without Oxygen", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62791": {"title": "Connections of Carbohydrate, Protein, and Lipid Metabolic Pathways", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62792": {"title": "Regulation of Cellular Respiration", "unit": "The Cell", "chapter": "Cellular Respiration"}, - "m62793": {"title": "Introduction", "unit": "The Cell", "chapter": "Photosynthesis"}, - "m62794": {"title": "Overview of Photosynthesis", "unit": "The Cell", "chapter": "Photosynthesis"}, - "m62795": {"title": "The Light-Dependent Reaction of Photosynthesis", "unit": "The Cell", "chapter": "Photosynthesis"}, - "m62796": {"title": "Using Light to Make Organic Molecules", "unit": "The Cell", "chapter": "Photosynthesis"}, - "m62797": {"title": "Introduction", "unit": "The Cell", "chapter": "Cell Communication"}, - "m62798": {"title": "Signaling Molecules and Cellular Receptors", "unit": "The Cell", "chapter": "Cell Communication"}, - "m62799": {"title": "Propagation of the Signal", "unit": "The Cell", "chapter": "Cell Communication"}, - "m62800": {"title": "Response to the Signal", "unit": "The Cell", "chapter": "Cell Communication"}, - "m62801": {"title": "Signaling in Single-Celled Organisms", "unit": "The Cell", "chapter": "Cell Communication"}, - "m62802": {"title": "Introduction", "unit": "The Cell", "chapter": "Cell Reproduction"}, - "m62803": {"title": "Cell Division", "unit": "The Cell", "chapter": "Cell Reproduction"}, - "m62804": {"title": "The Cell Cycle", "unit": "The Cell", "chapter": "Cell Reproduction"}, - "m62805": {"title": "Control of the Cell Cycle", "unit": "The Cell", "chapter": "Cell Reproduction"}, - "m62806": {"title": "Cancer and the Cell Cycle", "unit": "The Cell", "chapter": "Cell Reproduction"}, - "m62808": {"title": "Prokaryotic Cell Division", "unit": "The Cell", "chapter": "Cell Reproduction"}, - "m62809": {"title": "Introduction", "unit": "Genetics", "chapter": "Meiosis and Sexual Reproduction"}, - "m62810": {"title": "The Process of Meiosis", "unit": "Genetics", "chapter": "Meiosis and Sexual Reproduction"}, - "m62811": {"title": "Sexual Reproduction", "unit": "Genetics", "chapter": "Meiosis and Sexual Reproduction"}, - "m62812": {"title": "Introduction", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, - "m62813": {"title": "Mendel's Experiments and the Laws of Probability", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, - "m62817": {"title": "Characteristics and Traits", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, - "m62819": {"title": "Laws of Inheritance", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, - "m62820": {"title": "Introduction", "unit": "Genetics", "chapter": "Modern Understandings of Inheritance"}, - "m62821": {"title": "Chromosomal Theory and Genetic Linkages", "unit": "Genetics", "chapter": "Modern Understandings of Inheritance"}, - "m62822": {"title": "Chromosomal Basis of Inherited Disorders", "unit": "Genetics", "chapter": "Modern Understandings of Inheritance"}, - "m62823": {"title": "Introduction", "unit": "Genetics", "chapter": "DNA Structure and Function"}, - "m62824": {"title": "Historical Basis of Modern Understanding", "unit": "Genetics", "chapter": "DNA Structure and Function"}, - "m62825": {"title": "DNA Structure and Sequencing", "unit": "Genetics", "chapter": "DNA Structure and Function"}, - "m62826": {"title": "Basics of DNA Replication", "unit": "Genetics", "chapter": "DNA Structure and Function"}, - "m62828": {"title": "DNA Replication in Prokaryotes", "unit": "Genetics", "chapter": "DNA Structure and Function"}, - "m62829": {"title": "DNA Replication in Eukaryotes", "unit": "Genetics", "chapter": "DNA Structure and Function"}, - "m62830": {"title": "DNA Repair", "unit": "Genetics", "chapter": "DNA Structure and Function"}, - "m62833": {"title": "Introduction", "unit": "Genetics", "chapter": "Genes and Proteins"}, - "m62837": {"title": "The Genetic Code", "unit": "Genetics", "chapter": "Genes and Proteins"}, - "m62838": {"title": "Prokaryotic Transcription", "unit": "Genetics", "chapter": "Genes and Proteins"}, - "m62840": {"title": "Eukaryotic Transcription", "unit": "Genetics", "chapter": "Genes and Proteins"}, - "m62842": {"title": "RNA Processing in Eukaryotes", "unit": "Genetics", "chapter": "Genes and Proteins"}, - "m62843": {"title": "Ribosomes and Protein Synthesis", "unit": "Genetics", "chapter": "Genes and Proteins"}, - "m62844": {"title": "Introduction", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62845": {"title": "Regulation of Gene Expression", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62846": {"title": "Prokaryotic Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62847": {"title": "Eukaryotic Epigenetic Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62848": {"title": "Eukaryotic Transcriptional Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62849": {"title": "Eukaryotic Post-transcriptional Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62850": {"title": "Eukaryotic Translational and Post-translational Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62851": {"title": "Cancer and Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, - "m62852": {"title": "Introduction", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, - "m62853": {"title": "Biotechnology", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, - "m62855": {"title": "Mapping Genomes", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, - "m62857": {"title": "Whole-Genome Sequencing", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, - "m62860": {"title": "Applying Genomics", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, - "m62861": {"title": "Genomics and Proteomics", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, - "m62862": {"title": "Introduction", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, - "m62863": {"title": "Understanding Evolution", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, - "m62864": {"title": "Formation of New Species", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, - "m62865": {"title": "Reconnection and Rates of Speciation", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, - "m62866": {"title": "Introduction", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, - "m62868": {"title": "Population Evolution", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, - "m62870": {"title": "Population Genetics", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, - "m62871": {"title": "Adaptive Evolution", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, - "m62873": {"title": "Introduction", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, - "m62874": {"title": "Organizing Life on Earth", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, - "m62876": {"title": "Perspectives on the Phylogenetic Tree", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, - "m62877": {"title": "Introduction", "unit": "Biological Diversity", "chapter": "Viruses"}, - "m62881": {"title": "Viral Evolution, Morphology, and Classification", "unit": "Biological Diversity", "chapter": "Viruses"}, - "m62882": {"title": "Virus Infection and Hosts", "unit": "Biological Diversity", "chapter": "Viruses"}, - "m62887": {"title": "Other Acellular Entities: Prions and Viroids", "unit": "Biological Diversity", "chapter": "Viruses"}, - "m62889": {"title": "Introduction", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, - "m62891": {"title": "Prokaryotic Diversity", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, - "m62893": {"title": "Structure of Prokaryotes", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, - "m62894": {"title": "Prokaryotic Metabolism", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, - "m62896": {"title": "Bacterial Diseases in Humans", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, - "m62897": {"title": "Beneficial Prokaryotes", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, - "m62899": {"title": "Introduction", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, - "m62903": {"title": "Determining Evolutionary Relationships", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, - "m62904": {"title": "Prevention and Treatment of Viral Infections", "unit": "Biological Diversity", "chapter": "Viruses"}, - "m62905": {"title": "Stems", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, - "m62906": {"title": "Roots", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, - "m62908": {"title": "Leaves", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, - "m62912": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, - "m62916": {"title": "Animal Form and Function", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, - "m62918": {"title": "Animal Primary Tissues", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, - "m62919": {"title": "Digestive Systems", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, - "m62920": {"title": "Nutrition and Energy Production", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, - "m62921": {"title": "Digestive System Processes", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, - "m62922": {"title": "Digestive System Regulation", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, - "m62923": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, - "m62924": {"title": "Neurons and Glial Cells", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, - "m62925": {"title": "How Neurons Communicate", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, - "m62926": {"title": "The Central Nervous System", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, - "m62928": {"title": "The Peripheral Nervous System", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, - "m62929": {"title": "Nervous System Disorders", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, - "m62930": {"title": "Plant Sensory Systems and Responses", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, - "m62931": {"title": "Homeostasis", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, - "m62933": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, - "m62937": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, - "m62946": {"title": "Somatosensation", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, - "m62947": {"title": "Taste and Smell", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, - "m62951": {"title": "The Plant Body", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, - "m62954": {"title": "Hearing and Vestibular Sensation", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, - "m62957": {"title": "Vision", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, - "m62959": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, - "m62961": {"title": "Types of Hormones", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, - "m62963": {"title": "How Hormones Work", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, - "m62969": {"title": "Transport of Water and Solutes in Plants", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, - "m62971": {"title": "Regulation of Hormone Production", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, - "m62976": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, - "m62977": {"title": "Types of Skeletal Systems", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, - "m62978": {"title": "Bone", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, - "m62979": {"title": "Joints and Skeletal Movement", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, - "m62980": {"title": "Muscle Contraction and Locomotion", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, - "m62981": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, - "m62982": {"title": "Systems of Gas Exchange", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, - "m62987": {"title": "Breathing", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, - "m62988": {"title": "Transport of Gases in Human Bodily Fluids", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, - "m62989": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, - "m62990": {"title": "Overview of the Circulatory System", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, - "m62991": {"title": "Components of the Blood", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, - "m62992": {"title": "Mammalian Heart and Blood Vessels", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, - "m62993": {"title": "Blood Flow and Blood Pressure Regulation", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, - "m62994": {"title": "Sensory Processes", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, - "m62995": {"title": "Endocrine Glands", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, - "m62996": {"title": "Regulation of Body Processes", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, - "m62997": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, - "m62998": {"title": "Gas Exchange across Respiratory Surfaces", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, - "m63000": {"title": "Osmoregulation and Osmotic Balance", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, - "m63001": {"title": "The Kidneys and Osmoregulatory Organs", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, - "m63002": {"title": "Excretion Systems", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, - "m63003": {"title": "Nitrogenous Wastes", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, - "m63004": {"title": "Hormonal Control of Osmoregulatory Functions", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, - "m63005": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, - "m63006": {"title": "Innate Immune Response", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, - "m63007": {"title": "Adaptive Immune Response", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, - "m63008": {"title": "Antibodies", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, - "m63009": {"title": "Disruptions in the Immune System", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, - "m63010": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63011": {"title": "Reproduction Methods", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63012": {"title": "Fertilization", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63013": {"title": "Human Reproductive Anatomy and Gametogenesis", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63014": {"title": "Hormonal Control of Human Reproduction", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63016": {"title": "Fertilization and Early Embryonic Development", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63018": {"title": "Human Pregnancy and Birth", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63019": {"title": "Introduction", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, - "m63021": {"title": "The Scope of Ecology", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, - "m63023": {"title": "Biogeography", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, - "m63024": {"title": "Terrestrial Biomes", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, - "m63025": {"title": "Aquatic Biomes", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, - "m63026": {"title": "Climate and the Effects of Global Climate Change", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, - "m63027": {"title": "Introduction", "unit": "Ecology", "chapter": "Population and Community Ecology"}, - "m63028": {"title": "Population Demography", "unit": "Ecology", "chapter": "Population and Community Ecology"}, - "m63029": {"title": "Life Histories and Natural Selection", "unit": "Ecology", "chapter": "Population and Community Ecology"}, - "m63030": {"title": "Environmental Limits to Population Growth", "unit": "Ecology", "chapter": "Population and Community Ecology"}, - "m63031": {"title": "Population Dynamics and Regulation", "unit": "Ecology", "chapter": "Population and Community Ecology"}, - "m63032": {"title": "Human Population Growth", "unit": "Ecology", "chapter": "Population and Community Ecology"}, - "m63033": {"title": "Community Ecology", "unit": "Ecology", "chapter": "Population and Community Ecology"}, - "m63034": {"title": "Behavioral Biology: Proximate and Ultimate Causes of Behavior", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m62780": { + "title": "Introduction", + "unit": "The Cell", + "chapter": "Structure and Function of Plasma Membranes", + }, + "m62784": { + "title": "Introduction", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62786": { + "title": "Energy in Living Systems", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62787": { + "title": "Glycolysis", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62788": { + "title": "Oxidation of Pyruvate and the Citric Acid Cycle", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62789": { + "title": "Oxidative Phosphorylation", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62790": { + "title": "Metabolism without Oxygen", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62791": { + "title": "Connections of Carbohydrate, Protein, and Lipid Metabolic Pathways", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62792": { + "title": "Regulation of Cellular Respiration", + "unit": "The Cell", + "chapter": "Cellular Respiration", + }, + "m62793": { + "title": "Introduction", + "unit": "The Cell", + "chapter": "Photosynthesis", + }, + "m62794": { + "title": "Overview of Photosynthesis", + "unit": "The Cell", + "chapter": "Photosynthesis", + }, + "m62795": { + "title": "The Light-Dependent Reaction of Photosynthesis", + "unit": "The Cell", + "chapter": "Photosynthesis", + }, + "m62796": { + "title": "Using Light to Make Organic Molecules", + "unit": "The Cell", + "chapter": "Photosynthesis", + }, + "m62797": { + "title": "Introduction", + "unit": "The Cell", + "chapter": "Cell Communication", + }, + "m62798": { + "title": "Signaling Molecules and Cellular Receptors", + "unit": "The Cell", + "chapter": "Cell Communication", + }, + "m62799": { + "title": "Propagation of the Signal", + "unit": "The Cell", + "chapter": "Cell Communication", + }, + "m62800": { + "title": "Response to the Signal", + "unit": "The Cell", + "chapter": "Cell Communication", + }, + "m62801": { + "title": "Signaling in Single-Celled Organisms", + "unit": "The Cell", + "chapter": "Cell Communication", + }, + "m62802": { + "title": "Introduction", + "unit": "The Cell", + "chapter": "Cell Reproduction", + }, + "m62803": { + "title": "Cell Division", + "unit": "The Cell", + "chapter": "Cell Reproduction", + }, + "m62804": { + "title": "The Cell Cycle", + "unit": "The Cell", + "chapter": "Cell Reproduction", + }, + "m62805": { + "title": "Control of the Cell Cycle", + "unit": "The Cell", + "chapter": "Cell Reproduction", + }, + "m62806": { + "title": "Cancer and the Cell Cycle", + "unit": "The Cell", + "chapter": "Cell Reproduction", + }, + "m62808": { + "title": "Prokaryotic Cell Division", + "unit": "The Cell", + "chapter": "Cell Reproduction", + }, + "m62809": { + "title": "Introduction", + "unit": "Genetics", + "chapter": "Meiosis and Sexual Reproduction", + }, + "m62810": { + "title": "The Process of Meiosis", + "unit": "Genetics", + "chapter": "Meiosis and Sexual Reproduction", + }, + "m62811": { + "title": "Sexual Reproduction", + "unit": "Genetics", + "chapter": "Meiosis and Sexual Reproduction", + }, + "m62812": { + "title": "Introduction", + "unit": "Genetics", + "chapter": "Mendel's Experiments and Heredity", + }, + "m62813": { + "title": "Mendel's Experiments and the Laws of Probability", + "unit": "Genetics", + "chapter": "Mendel's Experiments and Heredity", + }, + "m62817": { + "title": "Characteristics and Traits", + "unit": "Genetics", + "chapter": "Mendel's Experiments and Heredity", + }, + "m62819": { + "title": "Laws of Inheritance", + "unit": "Genetics", + "chapter": "Mendel's Experiments and Heredity", + }, + "m62820": { + "title": "Introduction", + "unit": "Genetics", + "chapter": "Modern Understandings of Inheritance", + }, + "m62821": { + "title": "Chromosomal Theory and Genetic Linkages", + "unit": "Genetics", + "chapter": "Modern Understandings of Inheritance", + }, + "m62822": { + "title": "Chromosomal Basis of Inherited Disorders", + "unit": "Genetics", + "chapter": "Modern Understandings of Inheritance", + }, + "m62823": { + "title": "Introduction", + "unit": "Genetics", + "chapter": "DNA Structure and Function", + }, + "m62824": { + "title": "Historical Basis of Modern Understanding", + "unit": "Genetics", + "chapter": "DNA Structure and Function", + }, + "m62825": { + "title": "DNA Structure and Sequencing", + "unit": "Genetics", + "chapter": "DNA Structure and Function", + }, + "m62826": { + "title": "Basics of DNA Replication", + "unit": "Genetics", + "chapter": "DNA Structure and Function", + }, + "m62828": { + "title": "DNA Replication in Prokaryotes", + "unit": "Genetics", + "chapter": "DNA Structure and Function", + }, + "m62829": { + "title": "DNA Replication in Eukaryotes", + "unit": "Genetics", + "chapter": "DNA Structure and Function", + }, + "m62830": { + "title": "DNA Repair", + "unit": "Genetics", + "chapter": "DNA Structure and Function", + }, + "m62833": { + "title": "Introduction", + "unit": "Genetics", + "chapter": "Genes and Proteins", + }, + "m62837": { + "title": "The Genetic Code", + "unit": "Genetics", + "chapter": "Genes and Proteins", + }, + "m62838": { + "title": "Prokaryotic Transcription", + "unit": "Genetics", + "chapter": "Genes and Proteins", + }, + "m62840": { + "title": "Eukaryotic Transcription", + "unit": "Genetics", + "chapter": "Genes and Proteins", + }, + "m62842": { + "title": "RNA Processing in Eukaryotes", + "unit": "Genetics", + "chapter": "Genes and Proteins", + }, + "m62843": { + "title": "Ribosomes and Protein Synthesis", + "unit": "Genetics", + "chapter": "Genes and Proteins", + }, + "m62844": { + "title": "Introduction", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62845": { + "title": "Regulation of Gene Expression", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62846": { + "title": "Prokaryotic Gene Regulation", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62847": { + "title": "Eukaryotic Epigenetic Gene Regulation", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62848": { + "title": "Eukaryotic Transcriptional Gene Regulation", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62849": { + "title": "Eukaryotic Post-transcriptional Gene Regulation", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62850": { + "title": "Eukaryotic Translational and Post-translational Gene Regulation", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62851": { + "title": "Cancer and Gene Regulation", + "unit": "Genetics", + "chapter": "Gene Regulation", + }, + "m62852": { + "title": "Introduction", + "unit": "Genetics", + "chapter": "Biotechnology and Genomics", + }, + "m62853": { + "title": "Biotechnology", + "unit": "Genetics", + "chapter": "Biotechnology and Genomics", + }, + "m62855": { + "title": "Mapping Genomes", + "unit": "Genetics", + "chapter": "Biotechnology and Genomics", + }, + "m62857": { + "title": "Whole-Genome Sequencing", + "unit": "Genetics", + "chapter": "Biotechnology and Genomics", + }, + "m62860": { + "title": "Applying Genomics", + "unit": "Genetics", + "chapter": "Biotechnology and Genomics", + }, + "m62861": { + "title": "Genomics and Proteomics", + "unit": "Genetics", + "chapter": "Biotechnology and Genomics", + }, + "m62862": { + "title": "Introduction", + "unit": "Evolutionary Processes", + "chapter": "Evolution and Origin of Species", + }, + "m62863": { + "title": "Understanding Evolution", + "unit": "Evolutionary Processes", + "chapter": "Evolution and Origin of Species", + }, + "m62864": { + "title": "Formation of New Species", + "unit": "Evolutionary Processes", + "chapter": "Evolution and Origin of Species", + }, + "m62865": { + "title": "Reconnection and Rates of Speciation", + "unit": "Evolutionary Processes", + "chapter": "Evolution and Origin of Species", + }, + "m62866": { + "title": "Introduction", + "unit": "Evolutionary Processes", + "chapter": "The Evolution of Populations", + }, + "m62868": { + "title": "Population Evolution", + "unit": "Evolutionary Processes", + "chapter": "The Evolution of Populations", + }, + "m62870": { + "title": "Population Genetics", + "unit": "Evolutionary Processes", + "chapter": "The Evolution of Populations", + }, + "m62871": { + "title": "Adaptive Evolution", + "unit": "Evolutionary Processes", + "chapter": "The Evolution of Populations", + }, + "m62873": { + "title": "Introduction", + "unit": "Evolutionary Processes", + "chapter": "Phylogenies and the History of Life", + }, + "m62874": { + "title": "Organizing Life on Earth", + "unit": "Evolutionary Processes", + "chapter": "Phylogenies and the History of Life", + }, + "m62876": { + "title": "Perspectives on the Phylogenetic Tree", + "unit": "Evolutionary Processes", + "chapter": "Phylogenies and the History of Life", + }, + "m62877": { + "title": "Introduction", + "unit": "Biological Diversity", + "chapter": "Viruses", + }, + "m62881": { + "title": "Viral Evolution, Morphology, and Classification", + "unit": "Biological Diversity", + "chapter": "Viruses", + }, + "m62882": { + "title": "Virus Infection and Hosts", + "unit": "Biological Diversity", + "chapter": "Viruses", + }, + "m62887": { + "title": "Other Acellular Entities: Prions and Viroids", + "unit": "Biological Diversity", + "chapter": "Viruses", + }, + "m62889": { + "title": "Introduction", + "unit": "Biological Diversity", + "chapter": "Prokaryotes: Bacteria and Archaea", + }, + "m62891": { + "title": "Prokaryotic Diversity", + "unit": "Biological Diversity", + "chapter": "Prokaryotes: Bacteria and Archaea", + }, + "m62893": { + "title": "Structure of Prokaryotes", + "unit": "Biological Diversity", + "chapter": "Prokaryotes: Bacteria and Archaea", + }, + "m62894": { + "title": "Prokaryotic Metabolism", + "unit": "Biological Diversity", + "chapter": "Prokaryotes: Bacteria and Archaea", + }, + "m62896": { + "title": "Bacterial Diseases in Humans", + "unit": "Biological Diversity", + "chapter": "Prokaryotes: Bacteria and Archaea", + }, + "m62897": { + "title": "Beneficial Prokaryotes", + "unit": "Biological Diversity", + "chapter": "Prokaryotes: Bacteria and Archaea", + }, + "m62899": { + "title": "Introduction", + "unit": "Plant Structure and Function", + "chapter": "Plant Form and Physiology", + }, + "m62903": { + "title": "Determining Evolutionary Relationships", + "unit": "Evolutionary Processes", + "chapter": "Phylogenies and the History of Life", + }, + "m62904": { + "title": "Prevention and Treatment of Viral Infections", + "unit": "Biological Diversity", + "chapter": "Viruses", + }, + "m62905": { + "title": "Stems", + "unit": "Plant Structure and Function", + "chapter": "Plant Form and Physiology", + }, + "m62906": { + "title": "Roots", + "unit": "Plant Structure and Function", + "chapter": "Plant Form and Physiology", + }, + "m62908": { + "title": "Leaves", + "unit": "Plant Structure and Function", + "chapter": "Plant Form and Physiology", + }, + "m62912": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "The Animal Body: Basic Form and Function", + }, + "m62916": { + "title": "Animal Form and Function", + "unit": "Animal Structure and Function", + "chapter": "The Animal Body: Basic Form and Function", + }, + "m62918": { + "title": "Animal Primary Tissues", + "unit": "Animal Structure and Function", + "chapter": "The Animal Body: Basic Form and Function", + }, + "m62919": { + "title": "Digestive Systems", + "unit": "Animal Structure and Function", + "chapter": "Animal Nutrition and the Digestive System", + }, + "m62920": { + "title": "Nutrition and Energy Production", + "unit": "Animal Structure and Function", + "chapter": "Animal Nutrition and the Digestive System", + }, + "m62921": { + "title": "Digestive System Processes", + "unit": "Animal Structure and Function", + "chapter": "Animal Nutrition and the Digestive System", + }, + "m62922": { + "title": "Digestive System Regulation", + "unit": "Animal Structure and Function", + "chapter": "Animal Nutrition and the Digestive System", + }, + "m62923": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "The Nervous System", + }, + "m62924": { + "title": "Neurons and Glial Cells", + "unit": "Animal Structure and Function", + "chapter": "The Nervous System", + }, + "m62925": { + "title": "How Neurons Communicate", + "unit": "Animal Structure and Function", + "chapter": "The Nervous System", + }, + "m62926": { + "title": "The Central Nervous System", + "unit": "Animal Structure and Function", + "chapter": "The Nervous System", + }, + "m62928": { + "title": "The Peripheral Nervous System", + "unit": "Animal Structure and Function", + "chapter": "The Nervous System", + }, + "m62929": { + "title": "Nervous System Disorders", + "unit": "Animal Structure and Function", + "chapter": "The Nervous System", + }, + "m62930": { + "title": "Plant Sensory Systems and Responses", + "unit": "Plant Structure and Function", + "chapter": "Plant Form and Physiology", + }, + "m62931": { + "title": "Homeostasis", + "unit": "Animal Structure and Function", + "chapter": "The Animal Body: Basic Form and Function", + }, + "m62933": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "Animal Nutrition and the Digestive System", + }, + "m62937": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "Sensory Systems", + }, + "m62946": { + "title": "Somatosensation", + "unit": "Animal Structure and Function", + "chapter": "Sensory Systems", + }, + "m62947": { + "title": "Taste and Smell", + "unit": "Animal Structure and Function", + "chapter": "Sensory Systems", + }, + "m62951": { + "title": "The Plant Body", + "unit": "Plant Structure and Function", + "chapter": "Plant Form and Physiology", + }, + "m62954": { + "title": "Hearing and Vestibular Sensation", + "unit": "Animal Structure and Function", + "chapter": "Sensory Systems", + }, + "m62957": { + "title": "Vision", + "unit": "Animal Structure and Function", + "chapter": "Sensory Systems", + }, + "m62959": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "The Endocrine System", + }, + "m62961": { + "title": "Types of Hormones", + "unit": "Animal Structure and Function", + "chapter": "The Endocrine System", + }, + "m62963": { + "title": "How Hormones Work", + "unit": "Animal Structure and Function", + "chapter": "The Endocrine System", + }, + "m62969": { + "title": "Transport of Water and Solutes in Plants", + "unit": "Plant Structure and Function", + "chapter": "Plant Form and Physiology", + }, + "m62971": { + "title": "Regulation of Hormone Production", + "unit": "Animal Structure and Function", + "chapter": "The Endocrine System", + }, + "m62976": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "The Musculoskeletal System", + }, + "m62977": { + "title": "Types of Skeletal Systems", + "unit": "Animal Structure and Function", + "chapter": "The Musculoskeletal System", + }, + "m62978": { + "title": "Bone", + "unit": "Animal Structure and Function", + "chapter": "The Musculoskeletal System", + }, + "m62979": { + "title": "Joints and Skeletal Movement", + "unit": "Animal Structure and Function", + "chapter": "The Musculoskeletal System", + }, + "m62980": { + "title": "Muscle Contraction and Locomotion", + "unit": "Animal Structure and Function", + "chapter": "The Musculoskeletal System", + }, + "m62981": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "The Respiratory System", + }, + "m62982": { + "title": "Systems of Gas Exchange", + "unit": "Animal Structure and Function", + "chapter": "The Respiratory System", + }, + "m62987": { + "title": "Breathing", + "unit": "Animal Structure and Function", + "chapter": "The Respiratory System", + }, + "m62988": { + "title": "Transport of Gases in Human Bodily Fluids", + "unit": "Animal Structure and Function", + "chapter": "The Respiratory System", + }, + "m62989": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "The Circulatory System", + }, + "m62990": { + "title": "Overview of the Circulatory System", + "unit": "Animal Structure and Function", + "chapter": "The Circulatory System", + }, + "m62991": { + "title": "Components of the Blood", + "unit": "Animal Structure and Function", + "chapter": "The Circulatory System", + }, + "m62992": { + "title": "Mammalian Heart and Blood Vessels", + "unit": "Animal Structure and Function", + "chapter": "The Circulatory System", + }, + "m62993": { + "title": "Blood Flow and Blood Pressure Regulation", + "unit": "Animal Structure and Function", + "chapter": "The Circulatory System", + }, + "m62994": { + "title": "Sensory Processes", + "unit": "Animal Structure and Function", + "chapter": "Sensory Systems", + }, + "m62995": { + "title": "Endocrine Glands", + "unit": "Animal Structure and Function", + "chapter": "The Endocrine System", + }, + "m62996": { + "title": "Regulation of Body Processes", + "unit": "Animal Structure and Function", + "chapter": "The Endocrine System", + }, + "m62997": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "Osmotic Regulation and Excretion", + }, + "m62998": { + "title": "Gas Exchange across Respiratory Surfaces", + "unit": "Animal Structure and Function", + "chapter": "The Respiratory System", + }, + "m63000": { + "title": "Osmoregulation and Osmotic Balance", + "unit": "Animal Structure and Function", + "chapter": "Osmotic Regulation and Excretion", + }, + "m63001": { + "title": "The Kidneys and Osmoregulatory Organs", + "unit": "Animal Structure and Function", + "chapter": "Osmotic Regulation and Excretion", + }, + "m63002": { + "title": "Excretion Systems", + "unit": "Animal Structure and Function", + "chapter": "Osmotic Regulation and Excretion", + }, + "m63003": { + "title": "Nitrogenous Wastes", + "unit": "Animal Structure and Function", + "chapter": "Osmotic Regulation and Excretion", + }, + "m63004": { + "title": "Hormonal Control of Osmoregulatory Functions", + "unit": "Animal Structure and Function", + "chapter": "Osmotic Regulation and Excretion", + }, + "m63005": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "The Immune System", + }, + "m63006": { + "title": "Innate Immune Response", + "unit": "Animal Structure and Function", + "chapter": "The Immune System", + }, + "m63007": { + "title": "Adaptive Immune Response", + "unit": "Animal Structure and Function", + "chapter": "The Immune System", + }, + "m63008": { + "title": "Antibodies", + "unit": "Animal Structure and Function", + "chapter": "The Immune System", + }, + "m63009": { + "title": "Disruptions in the Immune System", + "unit": "Animal Structure and Function", + "chapter": "The Immune System", + }, + "m63010": { + "title": "Introduction", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63011": { + "title": "Reproduction Methods", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63012": { + "title": "Fertilization", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63013": { + "title": "Human Reproductive Anatomy and Gametogenesis", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63014": { + "title": "Hormonal Control of Human Reproduction", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63016": { + "title": "Fertilization and Early Embryonic Development", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63018": { + "title": "Human Pregnancy and Birth", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63019": { + "title": "Introduction", + "unit": "Ecology", + "chapter": "Ecology and the Biosphere", + }, + "m63021": { + "title": "The Scope of Ecology", + "unit": "Ecology", + "chapter": "Ecology and the Biosphere", + }, + "m63023": { + "title": "Biogeography", + "unit": "Ecology", + "chapter": "Ecology and the Biosphere", + }, + "m63024": { + "title": "Terrestrial Biomes", + "unit": "Ecology", + "chapter": "Ecology and the Biosphere", + }, + "m63025": { + "title": "Aquatic Biomes", + "unit": "Ecology", + "chapter": "Ecology and the Biosphere", + }, + "m63026": { + "title": "Climate and the Effects of Global Climate Change", + "unit": "Ecology", + "chapter": "Ecology and the Biosphere", + }, + "m63027": { + "title": "Introduction", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, + "m63028": { + "title": "Population Demography", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, + "m63029": { + "title": "Life Histories and Natural Selection", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, + "m63030": { + "title": "Environmental Limits to Population Growth", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, + "m63031": { + "title": "Population Dynamics and Regulation", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, + "m63032": { + "title": "Human Population Growth", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, + "m63033": { + "title": "Community Ecology", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, + "m63034": { + "title": "Behavioral Biology: Proximate and Ultimate Causes of Behavior", + "unit": "Ecology", + "chapter": "Population and Community Ecology", + }, "m63035": {"title": "Introduction", "unit": "Ecology", "chapter": "Ecosystems"}, - "m63036": {"title": "Ecology for Ecosystems", "unit": "Ecology", "chapter": "Ecosystems"}, - "m63037": {"title": "Energy Flow through Ecosystems", "unit": "Ecology", "chapter": "Ecosystems"}, - "m63040": {"title": "Biogeochemical Cycles", "unit": "Ecology", "chapter": "Ecosystems"}, - "m63043": {"title": "Organogenesis and Vertebrate Axis Formation", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, - "m63047": {"title": "Introduction", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, - "m63048": {"title": "The Biodiversity Crisis", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, - "m63049": {"title": "The Importance of Biodiversity to Human Life", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, - "m63050": {"title": "Threats to Biodiversity", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, - "m63051": {"title": "Preserving Biodiversity", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, + "m63036": { + "title": "Ecology for Ecosystems", + "unit": "Ecology", + "chapter": "Ecosystems", + }, + "m63037": { + "title": "Energy Flow through Ecosystems", + "unit": "Ecology", + "chapter": "Ecosystems", + }, + "m63040": { + "title": "Biogeochemical Cycles", + "unit": "Ecology", + "chapter": "Ecosystems", + }, + "m63043": { + "title": "Organogenesis and Vertebrate Axis Formation", + "unit": "Animal Structure and Function", + "chapter": "Animal Reproduction and Development", + }, + "m63047": { + "title": "Introduction", + "unit": "Ecology", + "chapter": "Conservation Biology and Biodiversity", + }, + "m63048": { + "title": "The Biodiversity Crisis", + "unit": "Ecology", + "chapter": "Conservation Biology and Biodiversity", + }, + "m63049": { + "title": "The Importance of Biodiversity to Human Life", + "unit": "Ecology", + "chapter": "Conservation Biology and Biodiversity", + }, + "m63050": { + "title": "Threats to Biodiversity", + "unit": "Ecology", + "chapter": "Conservation Biology and Biodiversity", + }, + "m63051": { + "title": "Preserving Biodiversity", + "unit": "Ecology", + "chapter": "Conservation Biology and Biodiversity", + }, "m64279": {"title": "Preface", "unit": "Front Matter", "chapter": "Front Matter"}, - "m66717": {"title": "Measurements and the Metric System", "unit": "Front Matter", "chapter": "Front Matter"}, + "m66717": { + "title": "Measurements and the Metric System", + "unit": "Front Matter", + "chapter": "Front Matter", + }, } # Expanded keyword mappings to module IDs @@ -509,7 +1329,6 @@ "life": ["m62718"], "living things": ["m62718"], "characteristics of life": ["m62718"], - # ========================================================================== # CHAPTER 2: THE CHEMICAL FOUNDATION OF LIFE # ========================================================================== @@ -541,7 +1360,6 @@ "organic molecule": ["m62722"], "hydrocarbon": ["m62722"], "functional group": ["m62722"], - # ========================================================================== # CHAPTER 3: BIOLOGICAL MACROMOLECULES # ========================================================================== @@ -587,7 +1405,6 @@ "nucleic acids": ["m62735"], "nucleotide": ["m62735"], "nucleotides": ["m62735"], - # ========================================================================== # CHAPTER 4: CELL STRUCTURE # ========================================================================== @@ -636,7 +1453,6 @@ "tight junction": ["m62746"], "gap junction": ["m62746"], "plasmodesmata": ["m62746"], - # ========================================================================== # CHAPTER 5: STRUCTURE AND FUNCTION OF PLASMA MEMBRANES # ========================================================================== @@ -662,7 +1478,6 @@ "phagocytosis": ["m62772"], "pinocytosis": ["m62772"], "bulk transport": ["m62772"], - # ========================================================================== # CHAPTER 6: METABOLISM # ========================================================================== @@ -696,7 +1511,6 @@ "noncompetitive inhibition": ["m62778"], "allosteric": ["m62778"], "feedback inhibition": ["m62778"], - # ========================================================================== # CHAPTER 7: CELLULAR RESPIRATION # ========================================================================== @@ -724,7 +1538,6 @@ "anaerobic respiration": ["m62790"], "lactic acid fermentation": ["m62790"], "alcohol fermentation": ["m62790"], - # ========================================================================== # CHAPTER 8: PHOTOSYNTHESIS # ========================================================================== @@ -744,7 +1557,6 @@ "c3 plant": ["m62796"], "c4 plant": ["m62796"], "cam plant": ["m62796"], - # ========================================================================== # CHAPTER 9: CELL COMMUNICATION # ========================================================================== @@ -763,7 +1575,6 @@ "phosphatase": ["m62799"], "apoptosis": ["m62800"], "programmed cell death": ["m62800"], - # ========================================================================== # CHAPTER 10: CELL REPRODUCTION # ========================================================================== @@ -791,7 +1602,6 @@ "tumor suppressor": ["m62806"], "p53": ["m62806"], "binary fission": ["m62808"], - # ========================================================================== # CHAPTER 11: MEIOSIS AND SEXUAL REPRODUCTION # ========================================================================== @@ -812,7 +1622,6 @@ "sexual reproduction": ["m62811"], "asexual reproduction": ["m62811"], "genetic variation": ["m62811"], - # ========================================================================== # CHAPTER 12: MENDEL'S EXPERIMENTS AND HEREDITY # ========================================================================== @@ -836,7 +1645,6 @@ "monohybrid cross": ["m62813"], "dihybrid cross": ["m62819"], "test cross": ["m62813"], - # ========================================================================== # CHAPTER 13: MODERN UNDERSTANDINGS OF INHERITANCE # ========================================================================== @@ -861,7 +1669,6 @@ "duplication": ["m62822"], "inversion": ["m62822"], "translocation": ["m62822"], - # ========================================================================== # CHAPTER 14: DNA STRUCTURE AND FUNCTION # ========================================================================== @@ -892,7 +1699,6 @@ "dna repair": ["m62830"], "mismatch repair": ["m62830"], "mutation": ["m62830"], - # ========================================================================== # CHAPTER 15: GENES AND PROTEINS # ========================================================================== @@ -921,7 +1727,6 @@ "transfer rna": ["m62843"], "rrna": ["m62843"], "ribosomal rna": ["m62843"], - # ========================================================================== # CHAPTER 16: GENE EXPRESSION # ========================================================================== @@ -946,7 +1751,6 @@ "microrna": ["m62849"], "sirna": ["m62849"], "rna interference": ["m62849"], - # ========================================================================== # CHAPTER 17: BIOTECHNOLOGY AND GENOMICS # ========================================================================== @@ -975,7 +1779,6 @@ "human genome project": ["m62857"], "proteomics": ["m62861"], "bioinformatics": ["m62860"], - # ========================================================================== # CHAPTER 18: EVOLUTION AND THE ORIGIN OF SPECIES # ========================================================================== @@ -997,7 +1800,6 @@ "convergent evolution": ["m62865"], "divergent evolution": ["m62865"], "coevolution": ["m62865"], - # ========================================================================== # CHAPTER 19: THE EVOLUTION OF POPULATIONS # ========================================================================== @@ -1017,7 +1819,6 @@ "stabilizing selection": ["m62871"], "disruptive selection": ["m62871"], "balancing selection": ["m62871"], - # ========================================================================== # CHAPTER 20: PHYLOGENIES AND THE HISTORY OF LIFE # ========================================================================== @@ -1039,7 +1840,6 @@ "homology": ["m62903"], "analogy": ["m62903"], "molecular clock": ["m62903"], - # ========================================================================== # CHAPTER 21: VIRUSES # ========================================================================== @@ -1060,7 +1860,6 @@ "antiviral": ["m62904"], "prion": ["m62887"], "viroid": ["m62887"], - # ========================================================================== # CHAPTER 22: PROKARYOTES: BACTERIA AND ARCHAEA # ========================================================================== @@ -1079,7 +1878,6 @@ "bacterial disease": ["m62896"], "antibiotic": ["m62896"], "antibiotic resistance": ["m62896"], - # ========================================================================== # CHAPTER 23: PLANT FORM AND PHYSIOLOGY # ========================================================================== @@ -1113,7 +1911,6 @@ "phototropism": ["m62930"], "gravitropism": ["m62930"], "photoperiodism": ["m62930"], - # ========================================================================== # CHAPTER 24: THE ANIMAL BODY # ========================================================================== @@ -1132,7 +1929,6 @@ "negative feedback": ["m62931"], "positive feedback": ["m62931"], "thermoregulation": ["m62931"], - # ========================================================================== # CHAPTER 25: NUTRITION AND THE DIGESTIVE SYSTEM # ========================================================================== @@ -1157,7 +1953,6 @@ "peristalsis": ["m62921"], "absorption": ["m62921"], "villi": ["m62921"], - # ========================================================================== # CHAPTER 26: THE NERVOUS SYSTEM # ========================================================================== @@ -1190,7 +1985,6 @@ "parasympathetic": ["m62928"], "somatic nervous system": ["m62928"], "reflex": ["m62928"], - # ========================================================================== # CHAPTER 27: SENSORY SYSTEMS # ========================================================================== @@ -1220,7 +2014,6 @@ "lens": ["m62957"], "cornea": ["m62957"], "photoreceptor": ["m62957"], - # ========================================================================== # CHAPTER 28: THE ENDOCRINE SYSTEM # ========================================================================== @@ -1251,7 +2044,6 @@ "estrogen": ["m62995"], "progesterone": ["m62995"], "feedback loop": ["m62971"], - # ========================================================================== # CHAPTER 29: THE MUSCULOSKELETAL SYSTEM # ========================================================================== @@ -1276,7 +2068,6 @@ "actin": ["m62980"], "myosin": ["m62980"], "sliding filament": ["m62980"], - # ========================================================================== # CHAPTER 30: THE RESPIRATORY SYSTEM # ========================================================================== @@ -1298,7 +2089,6 @@ "hemoglobin": ["m62988"], "oxygen transport": ["m62988"], "carbon dioxide transport": ["m62988"], - # ========================================================================== # CHAPTER 31: THE CIRCULATORY SYSTEM # ========================================================================== @@ -1322,7 +2112,6 @@ "diastole": ["m62992"], "atrium": ["m62992"], "ventricle": ["m62992"], - # ========================================================================== # CHAPTER 32: OSMOTIC REGULATION AND EXCRETION # ========================================================================== @@ -1346,7 +2135,6 @@ "antidiuretic hormone": ["m63004"], "adh": ["m63004"], "aldosterone": ["m63004"], - # ========================================================================== # CHAPTER 33: THE IMMUNE SYSTEM # ========================================================================== @@ -1378,7 +2166,6 @@ "autoimmune": ["m63009"], "autoimmune disease": ["m63009"], "immunodeficiency": ["m63009"], - # ========================================================================== # CHAPTER 34: ANIMAL REPRODUCTION AND DEVELOPMENT # ========================================================================== @@ -1417,7 +2204,6 @@ "fetus": ["m63018"], "labor": ["m63018"], "birth": ["m63018"], - # ========================================================================== # CHAPTER 35: ECOLOGY AND THE BIOSPHERE # ========================================================================== @@ -1446,7 +2232,6 @@ "global warming": ["m63026"], "greenhouse effect": ["m63026"], "greenhouse gas": ["m63026"], - # ========================================================================== # CHAPTER 36: POPULATION AND COMMUNITY ECOLOGY # ========================================================================== @@ -1483,7 +2268,6 @@ "animal behavior": ["m63034"], "innate behavior": ["m63034"], "learned behavior": ["m63034"], - # ========================================================================== # CHAPTER 37: ECOSYSTEMS # ========================================================================== @@ -1510,7 +2294,6 @@ "phosphorus cycle": ["m63040"], "water cycle": ["m63040"], "hydrologic cycle": ["m63040"], - # ========================================================================== # CHAPTER 38: CONSERVATION BIOLOGY AND BIODIVERSITY # ========================================================================== @@ -1558,12 +2341,12 @@ def get_module_url(module_id: str) -> str: title = info["title"] # Generate slug from title as last resort - slug = re.sub(r'[^a-z0-9]+', '-', title.lower()).strip('-') + slug = re.sub(r"[^a-z0-9]+", "-", title.lower()).strip("-") # For introduction pages, use chapter name if title == "Introduction": chapter = info["chapter"] - slug = re.sub(r'[^a-z0-9]+', '-', chapter.lower()).strip('-') + slug = re.sub(r"[^a-z0-9]+", "-", chapter.lower()).strip("-") return f"{OPENSTAX_BASE_URL}/{slug}" @@ -1580,6 +2363,7 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: List of module info dicts with id, title, unit, chapter, and url """ import logging + logger = logging.getLogger(__name__) logger.info("=" * 50) @@ -1597,21 +2381,23 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: for keyword, module_ids in KEYWORD_TO_MODULES.items(): # Use word boundary matching for single-word keywords # For multi-word keywords, require exact substring match - if ' ' in keyword: + if " " in keyword: # Multi-word keyword - exact substring match is fine if keyword in topic_lower: matched_ids.update(module_ids) matched_keywords.append(keyword) else: # Single-word keyword - require word boundaries - pattern = r'\b' + re.escape(keyword) + r'\b' + pattern = r"\b" + re.escape(keyword) + r"\b" if re.search(pattern, topic_lower): matched_ids.update(module_ids) matched_keywords.append(keyword) if matched_keywords: logger.info(f"KEYWORD MATCHES FOUND: {matched_keywords}") - logger.info(f"Matched module IDs: {list(matched_ids)[:10]}{'...' if len(matched_ids) > 10 else ''}") + logger.info( + f"Matched module IDs: {list(matched_ids)[:10]}{'...' if len(matched_ids) > 10 else ''}" + ) else: logger.info("No keyword matches found, falling back to title search...") @@ -1622,9 +2408,9 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: chapter_lower = info["chapter"].lower() # Check if any word from topic is in title or chapter - topic_words = set(re.findall(r'\b\w+\b', topic_lower)) - title_words = set(re.findall(r'\b\w+\b', title_lower)) - chapter_words = set(re.findall(r'\b\w+\b', chapter_lower)) + topic_words = set(re.findall(r"\b\w+\b", topic_lower)) + title_words = set(re.findall(r"\b\w+\b", title_lower)) + chapter_words = set(re.findall(r"\b\w+\b", chapter_lower)) if topic_words & title_words or topic_words & chapter_words: matched_ids.add(module_id) @@ -1642,13 +2428,15 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: # Skip introduction modules unless specifically requested if info["title"] == "Introduction" and "introduction" not in topic_lower: continue - results.append({ - "id": mid, - "title": info["title"], - "unit": info["unit"], - "chapter": info["chapter"], - "url": get_module_url(mid), - }) + results.append( + { + "id": mid, + "title": info["title"], + "unit": info["unit"], + "chapter": info["chapter"], + "url": get_module_url(mid), + } + ) logger.info(f"Returning {len(results)} results: {[r['id'] for r in results]}") return results[:max_results] diff --git a/samples/personalized_learning/deploy.py b/samples/personalized_learning/deploy.py index edd677746..b91ef72c0 100644 --- a/samples/personalized_learning/deploy.py +++ b/samples/personalized_learning/deploy.py @@ -38,6 +38,7 @@ try: import certifi + _HAS_CERTIFI = True except ImportError: _HAS_CERTIFI = False @@ -81,7 +82,9 @@ def main(): args = parser.parse_args() if not args.project: - print("ERROR: --project flag or GOOGLE_CLOUD_PROJECT environment variable is required") + print( + "ERROR: --project flag or GOOGLE_CLOUD_PROJECT environment variable is required" + ) sys.exit(1) # Set context bucket (default to {project}-learner-context) @@ -119,7 +122,7 @@ def main(): # ========================================================================= # CREATE THE ADK AGENT # ========================================================================= - # Create an Agent, wrap it in AdkApp, and deploy the AdkApp directly. + # Create an Agent, wrap it in AdkApp, and deploy the AdkApp directly. # AdkApp is designed to be picklable. # ========================================================================= @@ -353,7 +356,9 @@ def main(): "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle": ["m62788"], "7-4-oxidative-phosphorylation": ["m62789"], "7-5-metabolism-without-oxygen": ["m62790"], - "7-6-connections-of-carbohydrate-protein-and-lipid-metabolic-pathways": ["m62791"], + "7-6-connections-of-carbohydrate-protein-and-lipid-metabolic-pathways": [ + "m62791" + ], "7-7-regulation-of-cellular-respiration": ["m62792"], "8-1-overview-of-photosynthesis": ["m62794"], "8-2-the-light-dependent-reaction-of-photosynthesis": ["m62795"], @@ -390,7 +395,9 @@ def main(): "16-3-eukaryotic-epigenetic-gene-regulation": ["m62847"], "16-4-eukaryotic-transcriptional-gene-regulation": ["m62848"], "16-5-eukaryotic-post-transcriptional-gene-regulation": ["m62849"], - "16-6-eukaryotic-translational-and-post-translational-gene-regulation": ["m62850"], + "16-6-eukaryotic-translational-and-post-translational-gene-regulation": [ + "m62850" + ], "16-7-cancer-and-gene-regulation": ["m62851"], "17-1-biotechnology": ["m62853"], "17-2-mapping-genomes": ["m62855"], @@ -505,12 +512,24 @@ def main(): "oxidative phosphorylation": ["7-4-oxidative-phosphorylation"], "fermentation": ["7-5-metabolism-without-oxygen"], "anaerobic": ["7-5-metabolism-without-oxygen"], - "cellular respiration": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", "7-4-oxidative-phosphorylation"], - "mitochondria": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", "7-4-oxidative-phosphorylation"], - "mitochondrion": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", "7-4-oxidative-phosphorylation"], + "cellular respiration": [ + "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", + "7-4-oxidative-phosphorylation", + ], + "mitochondria": [ + "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", + "7-4-oxidative-phosphorylation", + ], + "mitochondrion": [ + "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", + "7-4-oxidative-phosphorylation", + ], "atp": ["6-4-atp-adenosine-triphosphate", "7-4-oxidative-phosphorylation"], "adenosine triphosphate": ["6-4-atp-adenosine-triphosphate"], - "photosynthesis": ["8-1-overview-of-photosynthesis", "8-2-the-light-dependent-reaction-of-photosynthesis"], + "photosynthesis": [ + "8-1-overview-of-photosynthesis", + "8-2-the-light-dependent-reaction-of-photosynthesis", + ], "plants make food": ["8-1-overview-of-photosynthesis"], "chloroplast": ["8-1-overview-of-photosynthesis", "4-3-eukaryotic-cells"], "chlorophyll": ["8-2-the-light-dependent-reaction-of-photosynthesis"], @@ -525,21 +544,33 @@ def main(): # Molecular Biology "dna": ["14-2-dna-structure-and-sequencing", "14-3-basics-of-dna-replication"], "rna": ["15-4-rna-processing-in-eukaryotes", "3-5-nucleic-acids"], - "mrna": ["15-4-rna-processing-in-eukaryotes", "15-5-ribosomes-and-protein-synthesis"], + "mrna": [ + "15-4-rna-processing-in-eukaryotes", + "15-5-ribosomes-and-protein-synthesis", + ], "trna": ["15-5-ribosomes-and-protein-synthesis"], "rrna": ["15-5-ribosomes-and-protein-synthesis"], - "transcription": ["15-2-prokaryotic-transcription", "15-3-eukaryotic-transcription"], + "transcription": [ + "15-2-prokaryotic-transcription", + "15-3-eukaryotic-transcription", + ], "translation": ["15-5-ribosomes-and-protein-synthesis"], "protein synthesis": ["15-5-ribosomes-and-protein-synthesis"], "protein": ["3-4-proteins", "15-5-ribosomes-and-protein-synthesis"], "enzyme": ["6-5-enzymes"], "gene expression": ["16-1-regulation-of-gene-expression"], "genetic code": ["15-1-the-genetic-code"], - "central dogma": ["15-1-the-genetic-code", "15-5-ribosomes-and-protein-synthesis"], + "central dogma": [ + "15-1-the-genetic-code", + "15-5-ribosomes-and-protein-synthesis", + ], "codon": ["15-1-the-genetic-code"], "anticodon": ["15-5-ribosomes-and-protein-synthesis"], "ribosome": ["15-5-ribosomes-and-protein-synthesis", "4-3-eukaryotic-cells"], - "replication": ["14-3-basics-of-dna-replication", "14-4-dna-replication-in-prokaryotes"], + "replication": [ + "14-3-basics-of-dna-replication", + "14-4-dna-replication-in-prokaryotes", + ], # Cell Structure "cell membrane": ["5-1-components-and-structure"], "plasma membrane": ["5-1-components-and-structure"], @@ -549,7 +580,10 @@ def main(): "diffusion": ["5-2-passive-transport"], "active transport": ["5-3-active-transport"], "cytoskeleton": ["4-5-cytoskeleton"], - "organelle": ["4-3-eukaryotic-cells", "4-4-the-endomembrane-system-and-proteins"], + "organelle": [ + "4-3-eukaryotic-cells", + "4-4-the-endomembrane-system-and-proteins", + ], "nucleus": ["4-3-eukaryotic-cells"], "endoplasmic reticulum": ["4-4-the-endomembrane-system-and-proteins"], "golgi": ["4-4-the-endomembrane-system-and-proteins"], @@ -557,11 +591,17 @@ def main(): "vesicle": ["5-4-bulk-transport", "4-4-the-endomembrane-system-and-proteins"], "endocytosis": ["5-4-bulk-transport"], "exocytosis": ["5-4-bulk-transport"], - "signal transduction": ["9-1-signaling-molecules-and-cellular-receptors", "9-2-propagation-of-the-signal"], + "signal transduction": [ + "9-1-signaling-molecules-and-cellular-receptors", + "9-2-propagation-of-the-signal", + ], "cell signaling": ["9-1-signaling-molecules-and-cellular-receptors"], # Nervous System "neuron": ["26-1-neurons-and-glial-cells", "26-2-how-neurons-communicate"], - "nervous system": ["26-1-neurons-and-glial-cells", "26-3-the-central-nervous-system"], + "nervous system": [ + "26-1-neurons-and-glial-cells", + "26-3-the-central-nervous-system", + ], "brain": ["26-3-the-central-nervous-system"], "action potential": ["26-2-how-neurons-communicate"], "synapse": ["26-2-how-neurons-communicate"], @@ -569,8 +609,14 @@ def main(): "vision": ["27-5-vision"], "hearing": ["27-4-hearing-and-vestibular-sensation"], # Circulatory System - "heart": ["31-1-overview-of-the-circulatory-system", "31-3-mammalian-heart-and-blood-vessels"], - "blood": ["31-2-components-of-the-blood", "31-1-overview-of-the-circulatory-system"], + "heart": [ + "31-1-overview-of-the-circulatory-system", + "31-3-mammalian-heart-and-blood-vessels", + ], + "blood": [ + "31-2-components-of-the-blood", + "31-1-overview-of-the-circulatory-system", + ], "circulatory": ["31-1-overview-of-the-circulatory-system"], "cardiovascular": ["31-1-overview-of-the-circulatory-system"], # Immune System @@ -586,31 +632,58 @@ def main(): "stomach": ["25-1-digestive-systems"], "intestine": ["25-3-digestive-system-processes"], "hormone": ["28-1-types-of-hormones", "28-2-how-hormones-work"], - "endocrine": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work"], - "endocrine system": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work"], + "endocrine": [ + "28-5-endocrine-glands", + "28-1-types-of-hormones", + "28-2-how-hormones-work", + ], + "endocrine system": [ + "28-5-endocrine-glands", + "28-1-types-of-hormones", + "28-2-how-hormones-work", + ], "muscle": ["29-4-muscle-contraction-and-locomotion"], "bone": ["29-2-bone"], "skeleton": ["29-1-types-of-skeletal-systems"], "kidney": ["32-2-the-kidneys-and-osmoregulatory-organs"], "excretion": ["32-3-excretion-systems"], - "reproduction": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], - "reproductive": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], - "reproductive system": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis", "34-4-hormonal-control-of-human-reproduction"], + "reproduction": [ + "34-1-reproduction-methods", + "34-3-human-reproductive-anatomy-and-gametogenesis", + ], + "reproductive": [ + "34-1-reproduction-methods", + "34-3-human-reproductive-anatomy-and-gametogenesis", + ], + "reproductive system": [ + "34-1-reproduction-methods", + "34-3-human-reproductive-anatomy-and-gametogenesis", + "34-4-hormonal-control-of-human-reproduction", + ], "pregnancy": ["34-7-human-pregnancy-and-birth"], "embryo": ["34-5-fertilization-and-early-embryonic-development"], # Evolution & Genetics "evolution": ["18-1-understanding-evolution", "19-1-population-evolution"], "darwin": ["18-1-understanding-evolution"], - "natural selection": ["19-3-adaptive-evolution", "36-2-life-histories-and-natural-selection"], + "natural selection": [ + "19-3-adaptive-evolution", + "36-2-life-histories-and-natural-selection", + ], "speciation": ["18-2-formation-of-new-species"], - "genetics": ["12-1-mendels-experiments-and-the-laws-of-probability", "12-3-laws-of-inheritance"], + "genetics": [ + "12-1-mendels-experiments-and-the-laws-of-probability", + "12-3-laws-of-inheritance", + ], "mendel": ["12-1-mendels-experiments-and-the-laws-of-probability"], "inheritance": ["12-3-laws-of-inheritance"], "heredity": ["12-3-laws-of-inheritance"], "mutation": ["14-6-dna-repair"], "phylogen": ["20-2-determining-evolutionary-relationships"], # Microorganisms - "virus": ["21-1-viral-evolution-morphology-and-classification", "21-2-virus-infection-and-hosts"], + "virus": [ + "21-1-viral-evolution-morphology-and-classification", + "21-2-virus-infection-and-hosts", + ], "bacteria": ["22-1-prokaryotic-diversity", "22-4-bacterial-diseases-in-humans"], "prokaryote": ["4-2-prokaryotic-cells", "22-1-prokaryotic-diversity"], "eukaryote": ["4-3-eukaryotic-cells"], @@ -623,14 +696,23 @@ def main(): "phloem": ["23-5-transport-of-water-and-solutes-in-plants"], # Ecology "ecology": ["35-1-the-scope-of-ecology", "36-6-community-ecology"], - "ecosystem": ["37-1-ecology-for-ecosystems", "37-2-energy-flow-through-ecosystems"], + "ecosystem": [ + "37-1-ecology-for-ecosystems", + "37-2-energy-flow-through-ecosystems", + ], "food chain": ["37-2-energy-flow-through-ecosystems"], "food web": ["37-2-energy-flow-through-ecosystems"], "biome": ["35-3-terrestrial-biomes", "35-4-aquatic-biomes"], - "population": ["36-1-population-demography", "36-3-environmental-limits-to-population-growth"], + "population": [ + "36-1-population-demography", + "36-3-environmental-limits-to-population-growth", + ], "climate": ["35-5-climate-and-the-effects-of-global-climate-change"], "climate change": ["35-5-climate-and-the-effects-of-global-climate-change"], - "biodiversity": ["38-1-the-biodiversity-crisis", "38-4-preserving-biodiversity"], + "biodiversity": [ + "38-1-the-biodiversity-crisis", + "38-4-preserving-biodiversity", + ], "carbon cycle": ["37-3-biogeochemical-cycles"], "nitrogen cycle": ["37-3-biogeochemical-cycles"], # Chemistry Basics @@ -681,10 +763,10 @@ def extract_text(elem): text_parts.append(para_text.strip()) full_text = "\n".join(text_parts) - full_text = re.sub(r'\n{3,}', '\n\n', full_text) + full_text = re.sub(r"\n{3,}", "\n\n", full_text) return full_text.strip() except Exception: - return re.sub(r'<[^>]+>', ' ', cnxml_content).strip() + return re.sub(r"<[^>]+>", " ", cnxml_content).strip() def get_chapter_list_for_llm() -> str: """Return a formatted list of all chapters for LLM context. @@ -767,14 +849,16 @@ def fetch_openstax_content(topic: str) -> dict: import urllib.error topic_lower = topic.lower() - matched_slugs = [] # Use list to preserve order (first match = highest priority) + matched_slugs = ( + [] + ) # Use list to preserve order (first match = highest priority) # First try keyword matching (fast path) # Use word boundary matching to avoid false positives like "vision" in "cell division" for keyword, slugs in KEYWORD_HINTS.items(): # Check for word boundary match using regex # This ensures "vision" doesn't match "cell division" - pattern = r'\b' + re.escape(keyword) + r'\b' + pattern = r"\b" + re.escape(keyword) + r"\b" if re.search(pattern, topic_lower): for slug in slugs: if slug not in matched_slugs: @@ -793,7 +877,7 @@ def fetch_openstax_content(topic: str) -> dict: return { "content": "", "sources": [], - "note": f"I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum." + "note": f"I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum.", } chapter_slugs = list(matched_slugs)[:2] @@ -819,8 +903,10 @@ def fetch_openstax_content(topic: str) -> dict: for module_id in module_ids: github_url = f"https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules/{module_id}/index.cnxml" try: - with urllib.request.urlopen(github_url, timeout=10, context=ssl_ctx) as response: - cnxml = response.read().decode('utf-8') + with urllib.request.urlopen( + github_url, timeout=10, context=ssl_ctx + ) as response: + cnxml = response.read().decode("utf-8") text = parse_cnxml_to_text(cnxml) if text: content_parts.append(f"## {title}\n\n{text}") @@ -830,7 +916,13 @@ def fetch_openstax_content(topic: str) -> dict: # Only add source if we actually got content for this chapter if chapter_content_found: - sources.append({"title": title, "url": url, "provider": "OpenStax Biology for AP Courses"}) + sources.append( + { + "title": title, + "url": url, + "provider": "OpenStax Biology for AP Courses", + } + ) return { "content": "\n\n---\n\n".join(content_parts) if content_parts else "", @@ -871,31 +963,77 @@ async def generate_flashcards( # If no OpenStax content found, return an error message instead of making up content if not textbook_context or not sources: components = [ - {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "message"]}, "distribution": "start", "alignment": "stretch"}}}, - {"id": "header", "component": {"Text": {"text": {"literalString": f"No Content Available: {topic}"}, "usageHint": "h3"}}}, - {"id": "message", "component": {"Text": {"text": {"literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms."}}}}, + { + "id": "mainColumn", + "component": { + "Column": { + "children": {"explicitList": ["header", "message"]}, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + { + "id": "header", + "component": { + "Text": { + "text": {"literalString": f"No Content Available: {topic}"}, + "usageHint": "h3", + } + }, + }, + { + "id": "message", + "component": { + "Text": { + "text": { + "literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms." + } + } + }, + }, ] a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, {"surfaceUpdate": {"surfaceId": SURFACE_ID, "components": components}}, ] - return json.dumps({"format": "flashcards", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": {"title": "No content found", "url": "", "provider": "OpenStax Biology for AP Courses"}}) + return json.dumps( + { + "format": "flashcards", + "a2ui": a2ui, + "surfaceId": SURFACE_ID, + "source": { + "title": "No content found", + "url": "", + "provider": "OpenStax Biology for AP Courses", + }, + } + ) - prompt = f'''Create 4 MCAT study flashcards about "{topic}" for Maria (pre-med, loves gym analogies). + prompt = f"""Create 4 MCAT study flashcards about "{topic}" for Maria (pre-med, loves gym analogies). Use gym/sports analogies in the answers where appropriate. IMPORTANT: Base all content ONLY on the textbook content provided below. Do not add information not present in the source. Textbook source content: -{textbook_context[:4000]}''' +{textbook_context[:4000]}""" flashcard_schema = { "type": "array", "items": { "type": "object", "properties": { - "front": {"type": "string", "description": "The question on the front of the flashcard"}, - "back": {"type": "string", "description": "The answer on the back, using gym analogies"}, - "category": {"type": "string", "description": "Category like Biochemistry"}, + "front": { + "type": "string", + "description": "The question on the front of the flashcard", + }, + "back": { + "type": "string", + "description": "The answer on the back, using gym analogies", + }, + "category": { + "type": "string", + "description": "Category like Biochemistry", + }, }, "required": ["front", "back", "category"], }, @@ -913,40 +1051,72 @@ async def generate_flashcards( # Handle case where LLM returns empty or invalid response if not cards or not isinstance(cards, list) or len(cards) == 0: - logger.warning(f"LLM returned empty flashcards for topic: {topic}, sources: {[s.get('title') for s in sources]}") + logger.warning( + f"LLM returned empty flashcards for topic: {topic}, sources: {[s.get('title') for s in sources]}" + ) # Create fallback flashcards - this usually means content mismatch - source_title = sources[0].get('title', topic) if sources else topic + source_title = sources[0].get("title", topic) if sources else topic cards = [ { "front": f"What are the key concepts in {source_title}?", "back": f"Review the OpenStax chapter on {source_title} for detailed information about {topic}.", - "category": "Biology" + "category": "Biology", }, { "front": f"Why is {topic} important in biology?", "back": f"Understanding {topic} is fundamental to biology. Check the source material for specific details.", - "category": "Biology" + "category": "Biology", }, ] # Build proper A2UI structure programmatically card_ids = [f"c{i+1}" for i in range(len(cards))] components = [ - {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "row"]}, "distribution": "start", "alignment": "stretch"}}}, - {"id": "header", "component": {"Text": {"text": {"literalString": f"Study Flashcards: {topic}"}, "usageHint": "h3"}}}, - {"id": "row", "component": {"Row": {"children": {"explicitList": card_ids}, "distribution": "start", "alignment": "stretch"}}}, - ] - for i, card in enumerate(cards): - components.append({ - "id": card_ids[i], + { + "id": "mainColumn", "component": { - "Flashcard": { - "front": {"literalString": card.get("front", "")}, - "back": {"literalString": card.get("back", "")}, - "category": {"literalString": card.get("category", "Biochemistry")}, + "Column": { + "children": {"explicitList": ["header", "row"]}, + "distribution": "start", + "alignment": "stretch", } + }, + }, + { + "id": "header", + "component": { + "Text": { + "text": {"literalString": f"Study Flashcards: {topic}"}, + "usageHint": "h3", + } + }, + }, + { + "id": "row", + "component": { + "Row": { + "children": {"explicitList": card_ids}, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + ] + for i, card in enumerate(cards): + components.append( + { + "id": card_ids[i], + "component": { + "Flashcard": { + "front": {"literalString": card.get("front", "")}, + "back": {"literalString": card.get("back", "")}, + "category": { + "literalString": card.get("category", "Biochemistry") + }, + } + }, } - }) + ) a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, @@ -960,7 +1130,14 @@ async def generate_flashcards( "provider": sources[0].get("provider", "OpenStax Biology for AP Courses"), } - return json.dumps({"format": "flashcards", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": source_info}) + return json.dumps( + { + "format": "flashcards", + "a2ui": a2ui, + "surfaceId": SURFACE_ID, + "source": source_info, + } + ) async def generate_quiz( tool_context: ToolContext, @@ -992,44 +1169,99 @@ async def generate_quiz( # If no OpenStax content found, return an error message instead of making up content if not textbook_context or not sources: components = [ - {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "message"]}, "distribution": "start", "alignment": "stretch"}}}, - {"id": "header", "component": {"Text": {"text": {"literalString": f"No Content Available: {topic}"}, "usageHint": "h3"}}}, - {"id": "message", "component": {"Text": {"text": {"literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms."}}}}, + { + "id": "mainColumn", + "component": { + "Column": { + "children": {"explicitList": ["header", "message"]}, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + { + "id": "header", + "component": { + "Text": { + "text": {"literalString": f"No Content Available: {topic}"}, + "usageHint": "h3", + } + }, + }, + { + "id": "message", + "component": { + "Text": { + "text": { + "literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms." + } + } + }, + }, ] a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, {"surfaceUpdate": {"surfaceId": SURFACE_ID, "components": components}}, ] - return json.dumps({"format": "quiz", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": {"title": "No content found", "url": "", "provider": "OpenStax Biology for AP Courses"}}) + return json.dumps( + { + "format": "quiz", + "a2ui": a2ui, + "surfaceId": SURFACE_ID, + "source": { + "title": "No content found", + "url": "", + "provider": "OpenStax Biology for AP Courses", + }, + } + ) - prompt = f'''Create 2 MCAT quiz questions about "{topic}" for Maria (pre-med, loves gym analogies). + prompt = f"""Create 2 MCAT quiz questions about "{topic}" for Maria (pre-med, loves gym analogies). Each question should have 4 options (a, b, c, d) with exactly one correct answer. Use gym/sports analogies in explanations where appropriate. IMPORTANT: Base all content ONLY on the textbook content provided below. Do not add information not present in the source. Textbook source content: -{textbook_context[:4000]}''' +{textbook_context[:4000]}""" quiz_schema = { "type": "array", "items": { "type": "object", "properties": { - "question": {"type": "string", "description": "The MCAT-style question"}, + "question": { + "type": "string", + "description": "The MCAT-style question", + }, "options": { "type": "array", "items": { "type": "object", "properties": { - "label": {"type": "string", "description": "The option text"}, - "value": {"type": "string", "description": "Option identifier (a, b, c, or d)"}, - "isCorrect": {"type": "boolean", "description": "True if this is the correct answer"}, + "label": { + "type": "string", + "description": "The option text", + }, + "value": { + "type": "string", + "description": "Option identifier (a, b, c, or d)", + }, + "isCorrect": { + "type": "boolean", + "description": "True if this is the correct answer", + }, }, "required": ["label", "value", "isCorrect"], }, }, - "explanation": {"type": "string", "description": "Detailed explanation with gym analogy"}, - "category": {"type": "string", "description": "Category like Biochemistry"}, + "explanation": { + "type": "string", + "description": "Detailed explanation with gym analogy", + }, + "category": { + "type": "string", + "description": "Category like Biochemistry", + }, }, "required": ["question", "options", "explanation", "category"], }, @@ -1049,45 +1281,97 @@ async def generate_quiz( if not quizzes or not isinstance(quizzes, list) or len(quizzes) == 0: logger.warning(f"LLM returned empty quiz for topic: {topic}") # Create a default quiz question based on the source content - quizzes = [{ - "question": f"Which of the following best describes {topic}?", - "options": [ - {"label": f"A key concept in {sources[0].get('title', 'biology')}", "value": "a", "isCorrect": True}, - {"label": "A topic not covered in AP Biology", "value": "b", "isCorrect": False}, - {"label": "An unrelated scientific concept", "value": "c", "isCorrect": False}, - {"label": "None of the above", "value": "d", "isCorrect": False}, - ], - "explanation": f"Review the OpenStax chapter on {sources[0].get('title', topic)} for more details.", - "category": "Biology" - }] + quizzes = [ + { + "question": f"Which of the following best describes {topic}?", + "options": [ + { + "label": f"A key concept in {sources[0].get('title', 'biology')}", + "value": "a", + "isCorrect": True, + }, + { + "label": "A topic not covered in AP Biology", + "value": "b", + "isCorrect": False, + }, + { + "label": "An unrelated scientific concept", + "value": "c", + "isCorrect": False, + }, + { + "label": "None of the above", + "value": "d", + "isCorrect": False, + }, + ], + "explanation": f"Review the OpenStax chapter on {sources[0].get('title', topic)} for more details.", + "category": "Biology", + } + ] # Build proper A2UI structure programmatically quiz_ids = [f"q{i+1}" for i in range(len(quizzes))] components = [ - {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "row"]}, "distribution": "start", "alignment": "stretch"}}}, - {"id": "header", "component": {"Text": {"text": {"literalString": f"Quick Quiz: {topic}"}, "usageHint": "h3"}}}, - {"id": "row", "component": {"Row": {"children": {"explicitList": quiz_ids}, "distribution": "start", "alignment": "stretch"}}}, + { + "id": "mainColumn", + "component": { + "Column": { + "children": {"explicitList": ["header", "row"]}, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + { + "id": "header", + "component": { + "Text": { + "text": {"literalString": f"Quick Quiz: {topic}"}, + "usageHint": "h3", + } + }, + }, + { + "id": "row", + "component": { + "Row": { + "children": {"explicitList": quiz_ids}, + "distribution": "start", + "alignment": "stretch", + } + }, + }, ] for i, quiz in enumerate(quizzes): # Transform options to A2UI format options = [] for opt in quiz.get("options", []): - options.append({ - "label": {"literalString": opt.get("label", "")}, - "value": opt.get("value", ""), - "isCorrect": opt.get("isCorrect", False), - }) - components.append({ - "id": quiz_ids[i], - "component": { - "QuizCard": { - "question": {"literalString": quiz.get("question", "")}, - "options": options, - "explanation": {"literalString": quiz.get("explanation", "")}, - "category": {"literalString": quiz.get("category", "Biochemistry")}, + options.append( + { + "label": {"literalString": opt.get("label", "")}, + "value": opt.get("value", ""), + "isCorrect": opt.get("isCorrect", False), } + ) + components.append( + { + "id": quiz_ids[i], + "component": { + "QuizCard": { + "question": {"literalString": quiz.get("question", "")}, + "options": options, + "explanation": { + "literalString": quiz.get("explanation", "") + }, + "category": { + "literalString": quiz.get("category", "Biochemistry") + }, + } + }, } - }) + ) a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, @@ -1101,7 +1385,14 @@ async def generate_quiz( "provider": sources[0].get("provider", "OpenStax Biology for AP Courses"), } - return json.dumps({"format": "quiz", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": source_info}) + return json.dumps( + { + "format": "quiz", + "a2ui": a2ui, + "surfaceId": SURFACE_ID, + "source": source_info, + } + ) async def get_textbook_content( tool_context: ToolContext, @@ -1121,25 +1412,31 @@ async def get_textbook_content( sources = openstax_data.get("sources", []) if not content: - return json.dumps({ - "content": f"No specific textbook content found for '{topic}'. Please use general biology knowledge.", - "sources": [] - }) + return json.dumps( + { + "content": f"No specific textbook content found for '{topic}'. Please use general biology knowledge.", + "sources": [], + } + ) # Format source citations source_citations = [] for src in sources: - source_citations.append({ - "title": src.get("title", ""), - "url": src.get("url", ""), - "provider": src.get("provider", "OpenStax Biology for AP Courses"), - }) - - return json.dumps({ - # Limit content length. Okay for a demo but could be improved - "content": content[:4000], - "sources": source_citations - }) + source_citations.append( + { + "title": src.get("title", ""), + "url": src.get("url", ""), + "provider": src.get("provider", "OpenStax Biology for AP Courses"), + } + ) + + return json.dumps( + { + # Limit content length. Okay for a demo but could be improved + "content": content[:4000], + "sources": source_citations, + } + ) # GCS media URLs (publicly accessible) # Media bucket follows pattern: {PROJECT_ID}-media @@ -1158,10 +1455,46 @@ async def get_audio_content(tool_context: ToolContext) -> str: A2UI JSON string for AudioPlayer component """ components = [ - {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "descText", "player"]}, "distribution": "start", "alignment": "stretch"}}}, - {"id": "header", "component": {"Text": {"text": {"literalString": "Personalized Learning Podcast"}, "usageHint": "h3"}}}, - {"id": "descText", "component": {"Text": {"text": {"literalString": "A podcast tailored for Maria covering ATP, bond energy, and common MCAT misconceptions. Uses gym and sports analogies to explain complex biochemistry concepts."}}}}, - {"id": "player", "component": {"AudioPlayer": {"url": {"literalString": PODCAST_URL}, "description": {"literalString": "ATP & Bond Energy - MCAT Review"}}}}, + { + "id": "mainColumn", + "component": { + "Column": { + "children": {"explicitList": ["header", "descText", "player"]}, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + { + "id": "header", + "component": { + "Text": { + "text": {"literalString": "Personalized Learning Podcast"}, + "usageHint": "h3", + } + }, + }, + { + "id": "descText", + "component": { + "Text": { + "text": { + "literalString": "A podcast tailored for Maria covering ATP, bond energy, and common MCAT misconceptions. Uses gym and sports analogies to explain complex biochemistry concepts." + } + } + }, + }, + { + "id": "player", + "component": { + "AudioPlayer": { + "url": {"literalString": PODCAST_URL}, + "description": { + "literalString": "ATP & Bond Energy - MCAT Review" + }, + } + }, + }, ] a2ui = [ @@ -1179,10 +1512,41 @@ async def get_video_content(tool_context: ToolContext) -> str: A2UI JSON string for Video component """ components = [ - {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "descText", "videoPlayer"]}, "distribution": "start", "alignment": "stretch"}}}, - {"id": "header", "component": {"Text": {"text": {"literalString": "Video Lesson"}, "usageHint": "h3"}}}, - {"id": "descText", "component": {"Text": {"text": {"literalString": "A visual explanation of ATP hydrolysis and bond energy concepts, designed for visual learners preparing for the MCAT."}}}}, - {"id": "videoPlayer", "component": {"Video": {"url": {"literalString": VIDEO_URL}}}}, + { + "id": "mainColumn", + "component": { + "Column": { + "children": { + "explicitList": ["header", "descText", "videoPlayer"] + }, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + { + "id": "header", + "component": { + "Text": { + "text": {"literalString": "Video Lesson"}, + "usageHint": "h3", + } + }, + }, + { + "id": "descText", + "component": { + "Text": { + "text": { + "literalString": "A visual explanation of ATP hydrolysis and bond energy concepts, designed for visual learners preparing for the MCAT." + } + } + }, + }, + { + "id": "videoPlayer", + "component": {"Video": {"url": {"literalString": VIDEO_URL}}}, + }, ] a2ui = [ @@ -1223,7 +1587,13 @@ async def get_video_content(tool_context: ToolContext) -> str: - Visual-kinesthetic learner Always use gym/sports analogies where appropriate. Be encouraging and supportive.""", - tools=[generate_flashcards, generate_quiz, get_textbook_content, get_audio_content, get_video_content], + tools=[ + generate_flashcards, + generate_quiz, + get_textbook_content, + get_audio_content, + get_video_content, + ], ) # Wrap agent in AdkApp for deployment (skip App wrapper to avoid version issues) @@ -1252,9 +1622,11 @@ async def get_video_content(tool_context: ToolContext) -> str: print("Next steps:") print(" 1. Copy the Resource ID above") print(" 2. Paste it into the notebook's AGENT_RESOURCE_ID variable") - print(f" 3. Upload learner context files to gs://{context_bucket}/learner_context/") + print( + f" 3. Upload learner context files to gs://{context_bucket}/learner_context/" + ) print(" 4. Run the remaining notebook cells to configure and start the demo") if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/samples/personalized_learning/deploy_hosting.py b/samples/personalized_learning/deploy_hosting.py index 80ff9f1ef..be7ad8e79 100755 --- a/samples/personalized_learning/deploy_hosting.py +++ b/samples/personalized_learning/deploy_hosting.py @@ -60,7 +60,9 @@ DEFAULT_REGION = "us-central1" -def run_command(cmd: list[str], check: bool = True, capture: bool = False) -> subprocess.CompletedProcess: +def run_command( + cmd: list[str], check: bool = True, capture: bool = False +) -> subprocess.CompletedProcess: """Run a shell command and optionally capture output.""" print(f" → {' '.join(cmd)}") return subprocess.run( @@ -126,7 +128,11 @@ def prepare_build_context(demo_dir: Path) -> Path: shutil.rmtree(web_core_dest) print(f" Copying {web_core_source} → {web_core_dest}") - shutil.copytree(web_core_source, web_core_dest, ignore=shutil.ignore_patterns("node_modules", ".git")) + shutil.copytree( + web_core_source, + web_core_dest, + ignore=shutil.ignore_patterns("node_modules", ".git"), + ) # Copy lit (the main web-lib) a2ui_source = renderers_dir / "lit" @@ -142,13 +148,18 @@ def prepare_build_context(demo_dir: Path) -> Path: # Copy the dependency (excluding node_modules, but keeping dist/ for pre-built output) print(f" Copying {a2ui_source} → {a2ui_dest}") - shutil.copytree(a2ui_source, a2ui_dest, ignore=shutil.ignore_patterns("node_modules", ".git")) + shutil.copytree( + a2ui_source, a2ui_dest, ignore=shutil.ignore_patterns("node_modules", ".git") + ) # Update lit's package.json to point to the local web_core copy lit_package_json = a2ui_dest / "package.json" if lit_package_json.exists(): content = lit_package_json.read_text() - content = content.replace('"@a2ui/web_core": "file:../web_core"', '"@a2ui/web_core": "file:../a2ui-web-core"') + content = content.replace( + '"@a2ui/web_core": "file:../web_core"', + '"@a2ui/web_core": "file:../a2ui-web-core"', + ) lit_package_json.write_text(content) print(" Updated lit package.json to reference local web_core") @@ -180,23 +191,37 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: # Enable required APIs first and wait for propagation print("\nEnabling required APIs...") - run_command([ - "gcloud", "services", "enable", - "run.googleapis.com", - "cloudbuild.googleapis.com", - "artifactregistry.googleapis.com", - "iap.googleapis.com", - "aiplatform.googleapis.com", # For Gemini API access - "--project", project_id, - "--quiet", - ], check=False) # Don't fail if already enabled + run_command( + [ + "gcloud", + "services", + "enable", + "run.googleapis.com", + "cloudbuild.googleapis.com", + "artifactregistry.googleapis.com", + "iap.googleapis.com", + "aiplatform.googleapis.com", # For Gemini API access + "--project", + project_id, + "--quiet", + ], + check=False, + ) # Don't fail if already enabled # Get project number for IAM bindings print("\nConfiguring IAM permissions for Cloud Build...") - result = run_command([ - "gcloud", "projects", "describe", project_id, - "--format", "value(projectNumber)", - ], capture=True, check=False) + result = run_command( + [ + "gcloud", + "projects", + "describe", + project_id, + "--format", + "value(projectNumber)", + ], + capture=True, + check=False, + ) project_number = result.stdout.strip() if result.returncode == 0 else None if project_number: @@ -204,57 +229,105 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: compute_sa = f"{project_number}-compute@developer.gserviceaccount.com" # Grant storage admin to the compute service account - run_command([ - "gcloud", "projects", "add-iam-policy-binding", project_id, - "--member", f"serviceAccount:{compute_sa}", - "--role", "roles/storage.objectViewer", - "--quiet", - ], check=False) + run_command( + [ + "gcloud", + "projects", + "add-iam-policy-binding", + project_id, + "--member", + f"serviceAccount:{compute_sa}", + "--role", + "roles/storage.objectViewer", + "--quiet", + ], + check=False, + ) # Grant logging permissions so we can see build logs - run_command([ - "gcloud", "projects", "add-iam-policy-binding", project_id, - "--member", f"serviceAccount:{compute_sa}", - "--role", "roles/logging.logWriter", - "--quiet", - ], check=False) + run_command( + [ + "gcloud", + "projects", + "add-iam-policy-binding", + project_id, + "--member", + f"serviceAccount:{compute_sa}", + "--role", + "roles/logging.logWriter", + "--quiet", + ], + check=False, + ) # Grant Artifact Registry writer permission to compute service account # Cloud Run source deployments use the compute SA to push Docker images - run_command([ - "gcloud", "projects", "add-iam-policy-binding", project_id, - "--member", f"serviceAccount:{compute_sa}", - "--role", "roles/artifactregistry.writer", - "--quiet", - ], check=False) + run_command( + [ + "gcloud", + "projects", + "add-iam-policy-binding", + project_id, + "--member", + f"serviceAccount:{compute_sa}", + "--role", + "roles/artifactregistry.writer", + "--quiet", + ], + check=False, + ) # Also grant Cloud Build service account permissions cloudbuild_sa = f"{project_number}@cloudbuild.gserviceaccount.com" - run_command([ - "gcloud", "projects", "add-iam-policy-binding", project_id, - "--member", f"serviceAccount:{cloudbuild_sa}", - "--role", "roles/storage.objectViewer", - "--quiet", - ], check=False) + run_command( + [ + "gcloud", + "projects", + "add-iam-policy-binding", + project_id, + "--member", + f"serviceAccount:{cloudbuild_sa}", + "--role", + "roles/storage.objectViewer", + "--quiet", + ], + check=False, + ) # Grant Artifact Registry writer permission for pushing Docker images # This is required for Cloud Run source deployments - run_command([ - "gcloud", "projects", "add-iam-policy-binding", project_id, - "--member", f"serviceAccount:{cloudbuild_sa}", - "--role", "roles/artifactregistry.writer", - "--quiet", - ], check=False) + run_command( + [ + "gcloud", + "projects", + "add-iam-policy-binding", + project_id, + "--member", + f"serviceAccount:{cloudbuild_sa}", + "--role", + "roles/artifactregistry.writer", + "--quiet", + ], + check=False, + ) # Grant Vertex AI User permission to the compute service account # This allows Cloud Run to call the Gemini API print("\nGranting Vertex AI permissions to Cloud Run service account...") - run_command([ - "gcloud", "projects", "add-iam-policy-binding", project_id, - "--member", f"serviceAccount:{compute_sa}", - "--role", "roles/aiplatform.user", - "--quiet", - ], check=False) + run_command( + [ + "gcloud", + "projects", + "add-iam-policy-binding", + project_id, + "--member", + f"serviceAccount:{compute_sa}", + "--role", + "roles/aiplatform.user", + "--quiet", + ], + check=False, + ) print("Waiting for API and IAM permissions to propagate (30 seconds)...") time.sleep(30) @@ -281,13 +354,21 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: # We use --allow-unauthenticated since Firebase Auth handles access control. # The app requires @google.com sign-in (configurable in src/firebase-auth.ts). cmd = [ - "gcloud", "run", "deploy", service_name, - "--source", str(demo_dir), - "--region", region, - "--project", project_id, + "gcloud", + "run", + "deploy", + service_name, + "--source", + str(demo_dir), + "--region", + region, + "--project", + project_id, "--allow-unauthenticated", # Firebase Auth handles access control - "--memory", "1Gi", - "--timeout", "300", + "--memory", + "1Gi", + "--timeout", + "300", "--quiet", # Auto-confirm prompts (e.g., enabling APIs) ] @@ -298,12 +379,22 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: run_command(cmd) # Get the service URL - result = run_command([ - "gcloud", "run", "services", "describe", service_name, - "--region", region, - "--project", project_id, - "--format", "value(status.url)", - ], capture=True) + result = run_command( + [ + "gcloud", + "run", + "services", + "describe", + service_name, + "--region", + region, + "--project", + project_id, + "--format", + "value(status.url)", + ], + capture=True, + ) service_url = result.stdout.strip() print(f"\nCloud Run URL: {service_url}") @@ -357,23 +448,38 @@ def configure_iap_access( print(" The service will be protected but no one can access it yet.") print("\n To grant access later, use:") print(f" gcloud run services add-iam-policy-binding {service_name} \\") - print(f" --region={region} --member='user:EMAIL' --role='roles/run.invoker'") + print( + f" --region={region} --member='user:EMAIL' --role='roles/run.invoker'" + ) print("\n Or for a domain:") print(f" gcloud run services add-iam-policy-binding {service_name} \\") - print(f" --region={region} --member='domain:DOMAIN' --role='roles/run.invoker'") + print( + f" --region={region} --member='domain:DOMAIN' --role='roles/run.invoker'" + ) return # Grant Cloud Run Invoker role to each member for member in members_to_add: print(f"\n Granting Cloud Run Invoker to {member}...") - run_command([ - "gcloud", "run", "services", "add-iam-policy-binding", service_name, - "--region", region, - "--project", project_id, - "--member", member, - "--role", "roles/run.invoker", - "--quiet", - ], check=False) + run_command( + [ + "gcloud", + "run", + "services", + "add-iam-policy-binding", + service_name, + "--region", + region, + "--project", + project_id, + "--member", + member, + "--role", + "roles/run.invoker", + "--quiet", + ], + check=False, + ) print("\n IAP access configured successfully.") @@ -385,20 +491,10 @@ def update_firebase_config(service_name: str, region: str): config = { "hosting": { "public": "public", - "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" - ], + "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], "rewrites": [ - { - "source": "**", - "run": { - "serviceId": service_name, - "region": region - } - } - ] + {"source": "**", "run": {"serviceId": service_name, "region": region}} + ], } } @@ -413,11 +509,7 @@ def update_firebaserc(project_id: str): """Update .firebaserc with the project ID.""" firebaserc_path = Path(__file__).parent / ".firebaserc" - config = { - "projects": { - "default": project_id - } - } + config = {"projects": {"default": project_id}} with open(firebaserc_path, "w") as f: json.dump(config, f, indent=2) @@ -436,11 +528,17 @@ def deploy_firebase_hosting(project_id: str): print() # Deploy hosting only - run_command([ - "firebase", "deploy", - "--only", "hosting", - "--project", project_id, - ], check=True) + run_command( + [ + "firebase", + "deploy", + "--only", + "hosting", + "--project", + project_id, + ], + check=True, + ) def main(): @@ -506,7 +604,9 @@ def main(): sys.exit(1) if not args.cloud_run_only and not tools["firebase"]: - print("ERROR: firebase CLI not found. Install with: npm install -g firebase-tools") + print( + "ERROR: firebase CLI not found. Install with: npm install -g firebase-tools" + ) sys.exit(1) # Change to the demo directory @@ -545,7 +645,9 @@ def main(): if not args.cloud_run_only: print(f"\n✅ Demo is live at: https://{project_id}.web.app") print("\nAccess is controlled by Firebase Authentication.") - print("Users must sign in with a @google.com account (configurable in src/firebase-auth.ts).") + print( + "Users must sign in with a @google.com account (configurable in src/firebase-auth.ts)." + ) if args.cloud_run_only: print(f"\nCloud Run service: {args.service_name}") @@ -558,8 +660,12 @@ def main(): print(f" Allowed users: {args.allow_users}") else: print("\n⚠️ Cloud Run deployed with --no-allow-unauthenticated.") - print(f" Grant access with: gcloud run services add-iam-policy-binding {args.service_name} \\") - print(f" --region={args.region} --member='user:EMAIL' --role='roles/run.invoker'") + print( + f" Grant access with: gcloud run services add-iam-policy-binding {args.service_name} \\" + ) + print( + f" --region={args.region} --member='user:EMAIL' --role='roles/run.invoker'" + ) print() diff --git a/specification/scripts/validate.py b/specification/scripts/validate.py index b5c32ebb5..b819902f4 100755 --- a/specification/scripts/validate.py +++ b/specification/scripts/validate.py @@ -21,55 +21,87 @@ import sys import shutil + def run_ajv(schema_path, data_paths, refs=None): """Runs ajv validate via subprocess. Batch validates multiple data paths.""" repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) # Try to find local ajv in specification/v0_9/test first - local_ajv = os.path.join(repo_root, "specification", "v0_9", "test", "node_modules", ".bin", "ajv") - + local_ajv = os.path.join( + repo_root, "specification", "v0_9", "test", "node_modules", ".bin", "ajv" + ) + if os.path.exists(local_ajv): - cmd = [local_ajv, "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats"] + cmd = [ + local_ajv, + "validate", + "-s", + schema_path, + "--spec=draft2020", + "--strict=false", + "-c", + "ajv-formats", + ] else: # Fallback to pnpm dlx with both packages - cmd = ["pnpm", "dlx", "--package=ajv-cli", "--package=ajv-formats", "ajv", "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats"] - + cmd = [ + "pnpm", + "dlx", + "--package=ajv-cli", + "--package=ajv-formats", + "ajv", + "validate", + "-s", + schema_path, + "--spec=draft2020", + "--strict=false", + "-c", + "ajv-formats", + ] + if refs: for ref in refs: cmd.extend(["-r", ref]) - + for data_path in data_paths: cmd.extend(["-d", data_path]) - + result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0, result.stdout + result.stderr + def validate_messages(root_schema, example_files, refs=None, temp_dir="temp_val"): """Validates a list of JSON files where each file contains a list of messages.""" os.makedirs(temp_dir, exist_ok=True) success = True - + for example_file in sorted(example_files): print(f" Validating {os.path.basename(example_file)}...") - with open(example_file, 'r') as f: + with open(example_file, "r") as f: try: messages = json.load(f) except json.JSONDecodeError as e: print(f" [FAIL] Invalid JSON: {e}") success = False continue - - if isinstance(messages, dict) and "messages" in messages and isinstance(messages["messages"], list): + + if ( + isinstance(messages, dict) + and "messages" in messages + and isinstance(messages["messages"], list) + ): messages = messages["messages"] elif not isinstance(messages, list): - messages = [messages] + messages = [messages] temp_data_paths = [] for i, msg in enumerate(messages): - temp_data_path = os.path.join(temp_dir, f"msg_{os.path.basename(example_file)}_{i}.json") - with open(temp_data_path, 'w') as f: + temp_data_path = os.path.join( + temp_dir, f"msg_{os.path.basename(example_file)}_{i}.json" + ) + with open(temp_data_path, "w") as f: json.dump(msg, f) temp_data_paths.append(temp_data_path) - + if not temp_data_paths: print(" [SKIP] No messages to validate") continue @@ -84,65 +116,70 @@ def validate_messages(root_schema, example_files, refs=None, temp_dir="temp_val" return success + def main(): repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) - + overall_success = True - + # Configuration for versions configs = { "v0_8": { "root_schema": "specification/v0_8/json/server_to_client_with_standard_catalog.json", "refs": [], - "examples": "specification/v0_8/json/catalogs/basic/examples/*.json" + "examples": "specification/v0_8/json/catalogs/basic/examples/*.json", }, "v0_9": { "root_schema": "specification/v0_9/json/server_to_client.json", "refs": [ "specification/v0_9/json/common_types.json", - "specification/v0_9/json/basic_catalog.json" + "specification/v0_9/json/basic_catalog.json", ], - "examples": "specification/v0_9/json/catalogs/basic/examples/*.json" - } + "examples": "specification/v0_9/json/catalogs/basic/examples/*.json", + }, } - + for version, config in configs.items(): print(f"\n=== Validating {version} ===") - + version_temp_dir = os.path.join(repo_root, f"temp_val_{version}") if os.path.exists(version_temp_dir): shutil.rmtree(version_temp_dir) os.makedirs(version_temp_dir, exist_ok=True) - + root_schema = os.path.join(repo_root, config["root_schema"]) if not os.path.exists(root_schema): print(f"Error: Root schema not found at {root_schema}") overall_success = False continue - + refs = [] for ref in config["refs"]: ref_path = os.path.join(repo_root, ref) if "basic_catalog.json" in ref: # v0.9 basic_catalog needs aliasing to catalog.json as expected by server_to_client.json - with open(ref_path, 'r') as f: + with open(ref_path, "r") as f: catalog = json.load(f) if "$id" in catalog: - catalog["$id"] = catalog["$id"].replace("basic_catalog.json", "catalog.json") + catalog["$id"] = catalog["$id"].replace( + "basic_catalog.json", "catalog.json" + ) alias_path = os.path.join(version_temp_dir, "catalog.json") - with open(alias_path, 'w') as f: + with open(alias_path, "w") as f: json.dump(catalog, f) refs.append(alias_path) else: refs.append(ref_path) - + example_pattern = os.path.join(repo_root, config["examples"]) example_files = glob.glob(example_pattern) - + if not example_files: print(f"No examples found for {version} matching {example_pattern}") else: - if not validate_messages(root_schema, example_files, refs, version_temp_dir): + if not validate_messages( + root_schema, example_files, refs, version_temp_dir + ): overall_success = False if os.path.exists(version_temp_dir): @@ -154,5 +191,6 @@ def main(): else: print("\nOverall Validation: PASSED") + if __name__ == "__main__": main() diff --git a/specification/v0_10/test/run_tests.py b/specification/v0_10/test/run_tests.py index 6d70f6be8..52fe95062 100755 --- a/specification/v0_10/test/run_tests.py +++ b/specification/v0_10/test/run_tests.py @@ -36,6 +36,7 @@ "client_to_server.json": os.path.join(SCHEMA_DIR, "client_to_server.json"), } + def setup_catalog_alias(catalog_file="basic_catalog.json"): """ Creates a temporary catalog.json from basic_catalog.json (or the @@ -50,7 +51,7 @@ def setup_catalog_alias(catalog_file="basic_catalog.json"): print(f"Error: Catalog file not found: {catalog_file}") sys.exit(1) - with open(basic_catalog_path, 'r') as f: + with open(basic_catalog_path, "r") as f: try: catalog = json.load(f) except json.JSONDecodeError as e: @@ -65,21 +66,46 @@ def setup_catalog_alias(catalog_file="basic_catalog.json"): base_url = catalog["$id"].rsplit("/", 1)[0] catalog["$id"] = f"{base_url}/catalog.json" - - with open(TEMP_CATALOG_FILE, 'w') as f: + with open(TEMP_CATALOG_FILE, "w") as f: json.dump(catalog, f, indent=2) + def cleanup_catalog_alias(): if os.path.exists(TEMP_CATALOG_FILE): os.remove(TEMP_CATALOG_FILE) + def validate_ajv(schema_path, data_path, all_schemas): """Runs ajv validate via subprocess.""" local_ajv = os.path.join(TEST_DIR, "node_modules", ".bin", "ajv") if os.path.exists(local_ajv): - cmd = [local_ajv, "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] + cmd = [ + local_ajv, + "validate", + "-s", + schema_path, + "--spec=draft2020", + "--strict=false", + "-c", + "ajv-formats", + "-d", + data_path, + ] else: - cmd = ["pnpm", "dlx", "ajv-cli", "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] + cmd = [ + "pnpm", + "dlx", + "ajv-cli", + "validate", + "-s", + schema_path, + "--spec=draft2020", + "--strict=false", + "-c", + "ajv-formats", + "-d", + data_path, + ] # Add all other schemas as references for name, path in all_schemas.items(): @@ -90,11 +116,14 @@ def validate_ajv(schema_path, data_path, all_schemas): result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0, result.stdout + result.stderr except FileNotFoundError: - print("Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install').") + print( + "Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install')." + ) sys.exit(1) + def run_suite(suite_path): - with open(suite_path, 'r') as f: + with open(suite_path, "r") as f: try: suite = json.load(f) except json.JSONDecodeError as e: @@ -125,7 +154,7 @@ def run_suite(suite_path): data = test.get("data") # Write data to temp file - with open(TEMP_FILE, 'w') as f: + with open(TEMP_FILE, "w") as f: json.dump(data, f) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -138,12 +167,13 @@ def run_suite(suite_path): print(f" [FAIL] {description}") print(f" Expected Valid: {expect_valid}, Got Valid: {is_valid}") if not is_valid: - print(f" Output: {output.strip()}") + print(f" Output: {output.strip()}") return passed, failed finally: cleanup_catalog_alias() + def validate_jsonl_example(jsonl_path): if not os.path.exists(jsonl_path): print(f"Error: Example file not found: {jsonl_path}") @@ -158,14 +188,14 @@ def validate_jsonl_example(jsonl_path): setup_catalog_alias() try: - with open(jsonl_path, 'r') as f: + with open(jsonl_path, "r") as f: for i, line in enumerate(f): line = line.strip() if not line: continue # Use temp file for each line - with open(TEMP_FILE, 'w') as tf: + with open(TEMP_FILE, "w") as tf: tf.write(line) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -181,6 +211,7 @@ def validate_jsonl_example(jsonl_path): finally: cleanup_catalog_alias() + def main(): if not os.path.exists(CASES_DIR): print(f"No cases directory found at {CASES_DIR}") @@ -204,7 +235,7 @@ def main(): total_passed += p total_failed += f - print("\n" + "="*30) + print("\n" + "=" * 30) print(f"Total Passed: {total_passed}") print(f"Total Failed: {total_failed}") @@ -215,5 +246,6 @@ def main(): if total_failed > 0: sys.exit(1) + if __name__ == "__main__": main() diff --git a/specification/v0_9/test/run_tests.py b/specification/v0_9/test/run_tests.py index 2df780450..3bff4bccb 100755 --- a/specification/v0_9/test/run_tests.py +++ b/specification/v0_9/test/run_tests.py @@ -36,6 +36,7 @@ "client_to_server.json": os.path.join(SCHEMA_DIR, "client_to_server.json"), } + def setup_catalog_alias(): """ Creates a temporary catalog.json from basic_catalog.json @@ -46,7 +47,7 @@ def setup_catalog_alias(): print(f"Error: basic_catalog.json not found at {basic_catalog_path}") sys.exit(1) - with open(basic_catalog_path, 'r') as f: + with open(basic_catalog_path, "r") as f: try: catalog = json.load(f) except json.JSONDecodeError as e: @@ -58,21 +59,47 @@ def setup_catalog_alias(): # and have it resolve to this schema content. if "$id" in catalog: catalog["$id"] = catalog["$id"].replace("basic_catalog.json", "catalog.json") - - with open(TEMP_CATALOG_FILE, 'w') as f: + + with open(TEMP_CATALOG_FILE, "w") as f: json.dump(catalog, f, indent=2) + def cleanup_catalog_alias(): if os.path.exists(TEMP_CATALOG_FILE): os.remove(TEMP_CATALOG_FILE) + def validate_ajv(schema_path, data_path, all_schemas): """Runs ajv validate via subprocess.""" local_ajv = os.path.join(TEST_DIR, "node_modules", ".bin", "ajv") if os.path.exists(local_ajv): - cmd = [local_ajv, "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] + cmd = [ + local_ajv, + "validate", + "-s", + schema_path, + "--spec=draft2020", + "--strict=false", + "-c", + "ajv-formats", + "-d", + data_path, + ] else: - cmd = ["pnpm", "dlx", "ajv-cli", "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] + cmd = [ + "pnpm", + "dlx", + "ajv-cli", + "validate", + "-s", + schema_path, + "--spec=draft2020", + "--strict=false", + "-c", + "ajv-formats", + "-d", + data_path, + ] # Add all other schemas as references for name, path in all_schemas.items(): @@ -83,11 +110,14 @@ def validate_ajv(schema_path, data_path, all_schemas): result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0, result.stdout + result.stderr except FileNotFoundError: - print("Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install').") + print( + "Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install')." + ) sys.exit(1) + def run_suite(suite_path): - with open(suite_path, 'r') as f: + with open(suite_path, "r") as f: try: suite = json.load(f) except json.JSONDecodeError as e: @@ -114,7 +144,7 @@ def run_suite(suite_path): data = test.get("data") # Write data to temp file - with open(TEMP_FILE, 'w') as f: + with open(TEMP_FILE, "w") as f: json.dump(data, f) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -127,10 +157,11 @@ def run_suite(suite_path): print(f" [FAIL] {description}") print(f" Expected Valid: {expect_valid}, Got Valid: {is_valid}") if not is_valid: - print(f" Output: {output.strip()}") + print(f" Output: {output.strip()}") return passed, failed + def validate_jsonl_example(jsonl_path): if not os.path.exists(jsonl_path): print(f"Error: Example file not found: {jsonl_path}") @@ -143,14 +174,14 @@ def validate_jsonl_example(jsonl_path): failed = 0 schema_path = SCHEMAS["server_to_client.json"] - with open(jsonl_path, 'r') as f: + with open(jsonl_path, "r") as f: for i, line in enumerate(f): line = line.strip() if not line: continue # Use temp file for each line - with open(TEMP_FILE, 'w') as tf: + with open(TEMP_FILE, "w") as tf: tf.write(line) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -164,6 +195,7 @@ def validate_jsonl_example(jsonl_path): return passed, failed + def main(): if not os.path.exists(CASES_DIR): print(f"No cases directory found at {CASES_DIR}") @@ -190,7 +222,7 @@ def main(): total_passed += p total_failed += f - print("\n" + "="*30) + print("\n" + "=" * 30) print(f"Total Passed: {total_passed}") print(f"Total Failed: {total_failed}") @@ -203,5 +235,6 @@ def main(): if total_failed > 0: sys.exit(1) + if __name__ == "__main__": main() diff --git a/tools/build_catalog/build_catalog.py b/tools/build_catalog/build_catalog.py index e44487c98..3fca13bff 100644 --- a/tools/build_catalog/build_catalog.py +++ b/tools/build_catalog/build_catalog.py @@ -24,22 +24,26 @@ from pathlib import Path from urllib.parse import urlparse + class SchemaBundler: + def __init__(self): - self.definitions = {} # Stores the content of bundled schemas - self.ref_mapping = {} # Maps (abs_file_path + fragment) -> internal #/$defs/ key - self.file_cache = {} # Cache loaded JSON files to avoid re-reading + self.definitions = {} # Stores the content of bundled schemas + self.ref_mapping = ( + {} + ) # Maps (abs_file_path + fragment) -> internal #/$defs/ key + self.file_cache = {} # Cache loaded JSON files to avoid re-reading def load_json(self, path: Path): path_str = str(path.resolve()) if path_str in self.file_cache: return self.file_cache[path_str] - + if not path.exists(): print(f"❌ Error: File not found: {path}") sys.exit(1) - with open(path, 'r', encoding='utf-8') as f: + with open(path, "r", encoding="utf-8") as f: data = json.load(f) self.file_cache[path_str] = data return data @@ -50,7 +54,7 @@ def resolve_json_pointer(self, schema, pointer): """ if not pointer or pointer == "#": return schema - + parts = pointer.lstrip("#/").split("/") current = schema try: @@ -72,62 +76,68 @@ def get_def_key(self, full_ref_id, file_stem, pointer): clean_pointer = pointer.replace("/", "_").replace("#", "").lstrip("_") if not clean_pointer: clean_pointer = "root" - + base_key = f"{file_stem}_{clean_pointer}" final_key = base_key - + # Prevent collisions for different references used_keys = set(self.ref_mapping.values()) counter = 1 while final_key in used_keys: final_key = f"{base_key}_{counter}" counter += 1 - + return final_key def process_schema(self, schema, current_file_path: Path): """ - Recursively walks the schema. - If it finds a remote $ref, it loads it, extracts the target, + Recursively walks the schema. + If it finds a remote $ref, it loads it, extracts the target, adds it to definitions, and rewrites the ref. """ if isinstance(schema, dict): # 1. Handle $ref if "$ref" in schema: ref = schema["$ref"] - + # Check if it's an external reference (doesn't start with #) if not ref.startswith("#"): # Parse URL to separate file path from fragment parsed = urlparse(ref) file_part = parsed.path fragment = parsed.fragment or "" - + # Resolve absolute path to the target file target_path = (current_file_path.parent / file_part).resolve() - + # Create a unique ID for this specific target (file + fragment) full_ref_id = f"{target_path}#{fragment}" - + if full_ref_id in self.ref_mapping: # We already bundled this, just point to it schema["$ref"] = f"#/$defs/{self.ref_mapping[full_ref_id]}" else: # New reference: Load and Process file_data = self.load_json(target_path) - + # Extract specific section if fragment exists - target_subschema = self.resolve_json_pointer(file_data, fragment) - + target_subschema = self.resolve_json_pointer( + file_data, fragment + ) + # Generate a key for $defs - def_key = self.get_def_key(full_ref_id, target_path.stem, fragment) - + def_key = self.get_def_key( + full_ref_id, target_path.stem, fragment + ) + # Store mapping immediately to handle recursion/cycles self.ref_mapping[full_ref_id] = def_key - + # Recursively process the LOADED content (it might have its own refs!) - processed_sub = self.process_schema(target_subschema, target_path) - + processed_sub = self.process_schema( + target_subschema, target_path + ) + self.definitions[def_key] = processed_sub schema["$ref"] = f"#/$defs/{def_key}" @@ -135,24 +145,24 @@ def process_schema(self, schema, current_file_path: Path): for key, value in schema.items(): if key != "$ref": schema[key] = self.process_schema(value, current_file_path) - + elif isinstance(schema, list): for i, item in enumerate(schema): schema[i] = self.process_schema(item, current_file_path) - + return schema def bundle(self, input_path): # Resolve path to ensure absolute consistency abs_input = input_path.resolve() - + # Load and process (populates self.definitions) root_data = self.load_json(abs_input) processed_root = self.process_schema(root_data, abs_input) - + # --- Construct Final Ordered Dictionary --- final_schema = {} - + # 1. Add $defs FIRST existing_defs = processed_root.get("$defs", {}) if existing_defs or self.definitions: @@ -163,40 +173,44 @@ def bundle(self, input_path): merged_defs[k] = v for k, v in self.definitions.items(): merged_defs[k] = v - + final_schema["$defs"] = merged_defs - + # 2. Add the rest of the schema properties for key, value in processed_root.items(): if key != "$defs": final_schema[key] = value - + return final_schema + def main(): - parser = argparse.ArgumentParser(description="Bundle JSON Schema $refs into internal $defs.") + parser = argparse.ArgumentParser( + description="Bundle JSON Schema $refs into internal $defs." + ) parser.add_argument("input_file", type=Path, help="Input schema file") parser.add_argument("-o", "--output", type=Path, help="Output file") - + args = parser.parse_args() - + # Default output path logic output_path = args.output if not output_path: output_path = args.input_file.parent / "dist" / args.input_file.name print(f"📦 Bundling: {args.input_file}") - + bundler = SchemaBundler() final_schema = bundler.bundle(args.input_file) - + # Ensure directory exists output_path.parent.mkdir(parents=True, exist_ok=True) - - with open(output_path, 'w', encoding='utf-8') as f: + + with open(output_path, "w", encoding="utf-8") as f: json.dump(final_schema, f, indent=2) - + print(f"✅ Created: {output_path}") + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/tools/build_catalog/tests/test_build_catalog.py b/tools/build_catalog/tests/test_build_catalog.py index 63e5b3239..465468b8b 100644 --- a/tools/build_catalog/tests/test_build_catalog.py +++ b/tools/build_catalog/tests/test_build_catalog.py @@ -18,32 +18,35 @@ from build_catalog import SchemaBundler + def test_resolve_json_pointer(): bundler = SchemaBundler() - schema = { - "definitions": { - "User": { - "type": "object" - } - }, - "list": ["a", "b"] - } - + schema = {"definitions": {"User": {"type": "object"}}, "list": ["a", "b"]} + # Test valid resolutions - assert bundler.resolve_json_pointer(schema, "/definitions/User") == {"type": "object"} + assert bundler.resolve_json_pointer(schema, "/definitions/User") == { + "type": "object" + } assert bundler.resolve_json_pointer(schema, "/list/1") == "b" - + # Test root resolutions assert bundler.resolve_json_pointer(schema, "") == schema assert bundler.resolve_json_pointer(schema, "#") == schema - + # Test unescaping schema_with_escaped_keys = { "path/to/thing": "escaped slash", - "path~to~thing": "escaped tilde" + "path~to~thing": "escaped tilde", } - assert bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~1to~1thing") == "escaped slash" - assert bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~0to~0thing") == "escaped tilde" + assert ( + bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~1to~1thing") + == "escaped slash" + ) + assert ( + bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~0to~0thing") + == "escaped tilde" + ) + def test_resolve_json_pointer_error(): bundler = SchemaBundler() @@ -56,118 +59,127 @@ def test_resolve_json_pointer_error(): with pytest.raises(SystemExit): bundler.resolve_json_pointer({"list": []}, "/list/0") + def test_get_def_key(): bundler = SchemaBundler() - assert bundler.get_def_key("path/to/target.json#/definitions/User", "myfile", "/definitions/User") == "myfile_definitions_User" + assert ( + bundler.get_def_key( + "path/to/target.json#/definitions/User", "myfile", "/definitions/User" + ) + == "myfile_definitions_User" + ) assert bundler.get_def_key("path/to/target.json#1", "myfile", "") == "myfile_root" assert bundler.get_def_key("path/to/target.json#2", "myfile", "#") == "myfile_root" + def test_get_def_key_collision(): bundler = SchemaBundler() bundler.ref_mapping["some_other_file.json#"] = "myfile_definitions_User" - - assert bundler.get_def_key("path/to/target.json#/definitions/User", "myfile", "/definitions/User") == "myfile_definitions_User_1" - + + assert ( + bundler.get_def_key( + "path/to/target.json#/definitions/User", "myfile", "/definitions/User" + ) + == "myfile_definitions_User_1" + ) + bundler.ref_mapping["yet_another_file.json#"] = "myfile_definitions_User_1" - assert bundler.get_def_key("path/to/target.json#/definitions/User", "myfile", "/definitions/User") == "myfile_definitions_User_2" + assert ( + bundler.get_def_key( + "path/to/target.json#/definitions/User", "myfile", "/definitions/User" + ) + == "myfile_definitions_User_2" + ) + def test_load_json_caching(tmp_path): # Setup dummy JSON file test_json_path = tmp_path / "test.json" test_json_path.write_text('{"hello": "world"}') - + bundler = SchemaBundler() - + # Load first time data1 = bundler.load_json(test_json_path) assert data1 == {"hello": "world"} - + # Modify file, but bundler should return cached version test_json_path.write_text('{"hello": "changed"}') data2 = bundler.load_json(test_json_path) assert data2 == {"hello": "world"} + def test_load_json_missing(tmp_path): bundler = SchemaBundler() with pytest.raises(SystemExit): bundler.load_json(tmp_path / "does_not_exist.json") + def test_process_schema_simple_ref(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"type": "string"}') - - main_schema = { - "properties": { - "name": {"$ref": "ext.json"} - } - } - + + main_schema = {"properties": {"name": {"$ref": "ext.json"}}} + bundler = SchemaBundler() processed = bundler.process_schema(main_schema, tmp_path / "main.json") - + assert processed["properties"]["name"]["$ref"] == "#/$defs/ext_root" assert "ext_root" in bundler.definitions assert bundler.definitions["ext_root"] == {"type": "string"} + def test_process_schema_with_fragment(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"definitions": {"MyString": {"type": "string"}}}') - - main_schema = { - "properties": { - "name": {"$ref": "ext.json#/definitions/MyString"} - } - } - + + main_schema = {"properties": {"name": {"$ref": "ext.json#/definitions/MyString"}}} + bundler = SchemaBundler() processed = bundler.process_schema(main_schema, tmp_path / "main.json") - + assert processed["properties"]["name"]["$ref"] == "#/$defs/ext_definitions_MyString" assert "ext_definitions_MyString" in bundler.definitions assert bundler.definitions["ext_definitions_MyString"] == {"type": "string"} + def test_process_schema_caches_refs(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"type": "string"}') - - main_schema = { - "prop1": {"$ref": "ext.json"}, - "prop2": {"$ref": "ext.json"} - } - + + main_schema = {"prop1": {"$ref": "ext.json"}, "prop2": {"$ref": "ext.json"}} + bundler = SchemaBundler() processed = bundler.process_schema(main_schema, tmp_path / "main.json") - + assert processed["prop1"]["$ref"] == "#/$defs/ext_root" assert processed["prop2"]["$ref"] == "#/$defs/ext_root" assert len(bundler.definitions) == 1 + def test_process_schema_recursive(): bundler = SchemaBundler() - schema = { - "list": [{"a": 1}, {"b": 2}], - "nested": {"c": 3} - } + schema = {"list": [{"a": 1}, {"b": 2}], "nested": {"c": 3}} processed = bundler.process_schema(schema, Path("dummy.json")) - assert processed == { - "list": [{"a": 1}, {"b": 2}], - "nested": {"c": 3} - } + assert processed == {"list": [{"a": 1}, {"b": 2}], "nested": {"c": 3}} + def test_bundle_merges_defs(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"type": "string"}') - + main_path = tmp_path / "main.json" - main_path.write_text('{"$defs": {"ExistingDef": {"type": "number"}}, "properties": {"a": {"$ref": "ext.json"}}}') - + main_path.write_text( + '{"$defs": {"ExistingDef": {"type": "number"}}, "properties": {"a": {"$ref": "ext.json"}}}' + ) + bundler = SchemaBundler() final_schema = bundler.bundle(main_path) - + assert "$defs" in final_schema assert "ExistingDef" in final_schema["$defs"] assert "ext_root" in final_schema["$defs"] assert final_schema["$defs"]["ExistingDef"] == {"type": "number"} assert final_schema["$defs"]["ext_root"] == {"type": "string"} - - assert final_schema["properties"]["a"]["$ref"] == "#/$defs/ext_root" \ No newline at end of file + + assert final_schema["properties"]["a"]["$ref"] == "#/$defs/ext_root" From 5f3a7dbe42133aa6625def03cc637c0fe474fbb5 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Thu, 12 Mar 2026 23:36:16 -0700 Subject: [PATCH 17/19] chore: fix CI sample formatting, lit workspace, and revert agent_sdks to main --- .../src/a2ui/core/schema/common_modifiers.py | 6 +- .../python/src/a2ui/core/schema/manager.py | 9 +- .../python/src/a2ui/core/schema/utils.py | 10 - .../python/src/a2ui/core/schema/validator.py | 62 +- .../tests/core/schema/test_validator.py | 30 +- .../tests/integration/verify_load_real.py | 744 +++++---- .../agent/adk/component_gallery/__main__.py | 126 +- samples/agent/adk/component_gallery/agent.py | 136 +- .../adk/component_gallery/agent_executor.py | 70 +- .../adk/component_gallery/gallery_examples.py | 972 ++++++------ samples/agent/adk/contact_lookup/__main__.py | 80 +- samples/agent/adk/contact_lookup/agent.py | 562 ++++--- .../adk/contact_lookup/agent_executor.py | 250 ++- .../adk/contact_lookup/prompt_builder.py | 42 +- samples/agent/adk/contact_lookup/tools.py | 72 +- samples/agent/adk/orchestrator/__main__.py | 82 +- samples/agent/adk/orchestrator/agent.py | 385 +++-- .../agent/adk/orchestrator/agent_executor.py | 218 +-- .../agent/adk/orchestrator/part_converters.py | 52 +- .../orchestrator/subagent_route_manager.py | 82 +- .../agent/adk/restaurant_finder/__main__.py | 76 +- samples/agent/adk/restaurant_finder/agent.py | 526 ++++--- .../adk/restaurant_finder/agent_executor.py | 252 ++-- .../adk/restaurant_finder/prompt_builder.py | 52 +- samples/agent/adk/restaurant_finder/tools.py | 66 +- samples/agent/adk/rizzcharts/__main__.py | 158 +- samples/agent/adk/rizzcharts/agent.py | 248 +-- .../agent/adk/rizzcharts/agent_executor.py | 156 +- samples/agent/adk/rizzcharts/tools.py | 154 +- samples/client/lit/package-lock.json | 1342 ++++++++--------- 30 files changed, 3439 insertions(+), 3581 deletions(-) diff --git a/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py b/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py index 1f29c2366..36a5a3a33 100644 --- a/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py +++ b/agent_sdks/python/src/a2ui/core/schema/common_modifiers.py @@ -17,10 +17,10 @@ def remove_strict_validation(schema): if isinstance(schema, dict): new_schema = {k: remove_strict_validation(v) for k, v in schema.items()} if ( - "additionalProperties" in new_schema - and new_schema["additionalProperties"] is False + 'additionalProperties' in new_schema + and new_schema['additionalProperties'] is False ): - del new_schema["additionalProperties"] + del new_schema['additionalProperties'] return new_schema elif isinstance(schema, list): return [remove_strict_validation(item) for item in schema] diff --git a/agent_sdks/python/src/a2ui/core/schema/manager.py b/agent_sdks/python/src/a2ui/core/schema/manager.py index 97e9eefd4..5a92c8787 100644 --- a/agent_sdks/python/src/a2ui/core/schema/manager.py +++ b/agent_sdks/python/src/a2ui/core/schema/manager.py @@ -19,7 +19,7 @@ import importlib.resources from typing import List, Dict, Any, Optional, Callable from dataclasses import dataclass, field -from .utils import load_from_bundled_resource, deep_update +from .utils import load_from_bundled_resource from ..inference_strategy import InferenceStrategy from .constants import * from .catalog import CatalogConfig, A2uiCatalog @@ -146,15 +146,10 @@ def _select_catalog( # Load the first inline catalog schema. inline_catalog_schema = inline_catalogs[0] inline_catalog_schema = self._apply_modifiers(inline_catalog_schema) - - # Deep merge the standard catalog properties with the inline catalog - merged_schema = copy.deepcopy(self._supported_catalogs[0].catalog_schema) - deep_update(merged_schema, inline_catalog_schema) - return A2uiCatalog( version=self._version, name=INLINE_CATALOG_NAME, - catalog_schema=merged_schema, + catalog_schema=inline_catalog_schema, s2c_schema=self._server_to_client_schema, common_types_schema=self._common_types_schema, ) diff --git a/agent_sdks/python/src/a2ui/core/schema/utils.py b/agent_sdks/python/src/a2ui/core/schema/utils.py index 193a289c0..f68ce85b7 100644 --- a/agent_sdks/python/src/a2ui/core/schema/utils.py +++ b/agent_sdks/python/src/a2ui/core/schema/utils.py @@ -117,13 +117,3 @@ def wrap_as_json_array(a2ui_schema: dict[str, Any]) -> dict[str, Any]: if not a2ui_schema: raise ValueError("A2UI schema is empty") return {"type": "array", "items": a2ui_schema} - - -def deep_update(d: dict, u: dict) -> dict: - """Recursively update a dict with another dict.""" - for k, v in u.items(): - if isinstance(v, dict): - d[k] = deep_update(d.get(k, {}), v) - else: - d[k] = v - return d diff --git a/agent_sdks/python/src/a2ui/core/schema/validator.py b/agent_sdks/python/src/a2ui/core/schema/validator.py index f06b89da2..07c1b968a 100644 --- a/agent_sdks/python/src/a2ui/core/schema/validator.py +++ b/agent_sdks/python/src/a2ui/core/schema/validator.py @@ -274,35 +274,31 @@ def validate(self, a2ui_json: Union[Dict[str, Any], List[Any]]) -> None: msg += f"\n - {sub_error.message}" raise ValueError(msg) + root_id = _find_root_id(messages) + for message in messages: if not isinstance(message, dict): continue components = None - surface_id = None if "surfaceUpdate" in message: # v0.8 components = message["surfaceUpdate"].get(COMPONENTS) - surface_id = message["surfaceUpdate"].get("surfaceId") elif "updateComponents" in message and isinstance( message["updateComponents"], dict ): # v0.9 components = message["updateComponents"].get(COMPONENTS) - surface_id = message["updateComponents"].get("surfaceId") if components: ref_map = _extract_component_ref_fields(self._catalog) - root_id = _find_root_id(messages, surface_id) _validate_component_integrity(root_id, components, ref_map) _validate_topology(root_id, components, ref_map) _validate_recursion_and_paths(message) -def _find_root_id( - messages: List[Dict[str, Any]], surface_id: Optional[str] = None -) -> Optional[str]: +def _find_root_id(messages: List[Dict[str, Any]]) -> str: """ - Finds the root id from a list of A2UI messages for a given surface. + Finds the root id from a list of A2UI messages. - For v0.8, the root id is in the beginRendering message. - For v0.9+, the root id is 'root'. """ @@ -310,14 +306,12 @@ def _find_root_id( if not isinstance(message, dict): continue if "beginRendering" in message: - if surface_id and message["beginRendering"].get("surfaceId") != surface_id: - continue return message["beginRendering"].get(ROOT, ROOT) - return None + return ROOT def _validate_component_integrity( - root_id: Optional[str], + root_id: str, components: List[Dict[str, Any]], ref_fields_map: Dict[str, tuple[Set[str], Set[str]]], ) -> None: @@ -340,23 +334,21 @@ def _validate_component_integrity( ids.add(comp_id) # 2. Check for root component - if root_id is not None and root_id not in ids: + if root_id not in ids: raise ValueError(f"Missing root component: No component has id='{root_id}'") # 3. Check for dangling references using helper - # In an incremental update (root_id is None), components may reference IDs already on the client. - if root_id is not None: - for comp in components: - for ref_id, field_name in _get_component_references(comp, ref_fields_map): - if ref_id not in ids: - raise ValueError( - f"Component '{comp.get(ID)}' references non-existent component '{ref_id}'" - f" in field '{field_name}'" - ) + for comp in components: + for ref_id, field_name in _get_component_references(comp, ref_fields_map): + if ref_id not in ids: + raise ValueError( + f"Component '{comp.get(ID)}' references non-existent component '{ref_id}'" + f" in field '{field_name}'" + ) def _validate_topology( - root_id: Optional[str], + root_id: str, components: List[Dict[str, Any]], ref_fields_map: Dict[str, tuple[Set[str], Set[str]]], ) -> None: @@ -409,22 +401,16 @@ def dfs(node_id: str, depth: int): recursion_stack.remove(node_id) - if root_id is not None: - if root_id in all_ids: - dfs(root_id, 0) + if root_id in all_ids: + dfs(root_id, 0) - # Check for Orphans - orphans = all_ids - visited - if orphans: - sorted_orphans = sorted(list(orphans)) - raise ValueError( - f"Component '{sorted_orphans[0]}' is not reachable from '{root_id}'" - ) - else: - # Partial update: we cannot check root reachability, but we still check for cycles - for node_id in all_ids: - if node_id not in visited: - dfs(node_id, 0) + # Check for Orphans + orphans = all_ids - visited + if orphans: + sorted_orphans = sorted(list(orphans)) + raise ValueError( + f"Component '{sorted_orphans[0]}' is not reachable from '{root_id}'" + ) def _extract_component_ref_fields( diff --git a/agent_sdks/python/tests/core/schema/test_validator.py b/agent_sdks/python/tests/core/schema/test_validator.py index 9a05668cb..d46d093fa 100644 --- a/agent_sdks/python/tests/core/schema/test_validator.py +++ b/agent_sdks/python/tests/core/schema/test_validator.py @@ -48,10 +48,7 @@ def catalog_0_9(self): "catalogId": { "type": "string", }, - "theme": { - "type": "object", - "additionalProperties": True, - }, + "theme": {"type": "object", "additionalProperties": True}, }, "required": ["surfaceId", "catalogId"], "additionalProperties": False, @@ -498,10 +495,7 @@ def test_custom_catalog_0_8(self, catalog_0_8): "children": { "type": "object", "properties": { - "explicitList": { - "type": "array", - "items": {"type": "string"}, - } + "explicitList": {"type": "array", "items": {"type": "string"}} }, "required": ["explicitList"], } @@ -730,35 +724,23 @@ def make_payload(self, catalog, components=None, data_model=None): if catalog.version == VERSION_0_8: payload = { - "surfaceUpdate": { - "surfaceId": "test-surface", - "components": processed, - } + "surfaceUpdate": {"surfaceId": "test-surface", "components": processed} } else: payload = { "version": "v0.9", - "updateComponents": { - "surfaceId": "test-surface", - "components": processed, - }, + "updateComponents": {"surfaceId": "test-surface", "components": processed}, } elif data_model: if catalog.version == VERSION_0_8: payload = { - "dataModelUpdate": { - "surfaceId": "test-surface", - "contents": data_model, - } + "dataModelUpdate": {"surfaceId": "test-surface", "contents": data_model} } else: payload = { "version": "v0.9", - "updateDataModel": { - "surfaceId": "test-surface", - "value": data_model, - }, + "updateDataModel": {"surfaceId": "test-surface", "value": data_model}, } if payload is None: diff --git a/agent_sdks/python/tests/integration/verify_load_real.py b/agent_sdks/python/tests/integration/verify_load_real.py index 18a9e33b3..f4dcdb95a 100644 --- a/agent_sdks/python/tests/integration/verify_load_real.py +++ b/agent_sdks/python/tests/integration/verify_load_real.py @@ -21,7 +21,7 @@ def verify(): - print("Verifying A2uiSchemaManager...") + print('Verifying A2uiSchemaManager...') try: manager = A2uiSchemaManager( version=VERSION_0_8, @@ -30,363 +30,351 @@ def verify(): ) catalog = manager.get_selected_catalog() catalog_components = catalog.catalog_schema[CATALOG_COMPONENTS_KEY] - print(f"Successfully loaded {VERSION_0_8}: {len(catalog_components)} components") - print(f"Components found: {list(catalog_components.keys())[:5]}...") + print(f'Successfully loaded {VERSION_0_8}: {len(catalog_components)} components') + print(f'Components found: {list(catalog_components.keys())[:5]}...') a2ui_message = [ - {"beginRendering": {"surfaceId": "contact-card", "root": "main_card"}}, + {'beginRendering': {'surfaceId': 'contact-card', 'root': 'main_card'}}, { - "surfaceUpdate": { - "surfaceId": "contact-card", - "components": [ - { - "id": "profile_image", - "component": { - "Image": { - "url": {"path": "/imageUrl"}, - "usageHint": "avatar", - "fit": "cover", + 'surfaceUpdate': { + 'surfaceId': 'contact-card', + 'components': [ + { + 'id': 'profile_image', + 'component': { + 'Image': { + 'url': {'path': '/imageUrl'}, + 'usageHint': 'avatar', + 'fit': 'cover', } }, }, { - "id": "user_heading", - "weight": 1, - "component": { - "Text": {"text": {"path": "/name"}, "usageHint": "h2"} + 'id': 'user_heading', + 'weight': 1, + 'component': { + 'Text': {'text': {'path': '/name'}, 'usageHint': 'h2'} }, }, { - "id": "description_text_1", - "component": {"Text": {"text": {"path": "/title"}}}, + 'id': 'description_text_1', + 'component': {'Text': {'text': {'path': '/title'}}}, }, { - "id": "description_text_2", - "component": {"Text": {"text": {"path": "/team"}}}, + 'id': 'description_text_2', + 'component': {'Text': {'text': {'path': '/team'}}}, }, { - "id": "description_column", - "component": { - "Column": { - "children": { - "explicitList": [ - "user_heading", - "description_text_1", - "description_text_2", + 'id': 'description_column', + 'component': { + 'Column': { + 'children': { + 'explicitList': [ + 'user_heading', + 'description_text_1', + 'description_text_2', ] }, - "alignment": "center", + 'alignment': 'center', } }, }, { - "id": "calendar_icon", - "component": { - "Icon": {"name": {"literalString": "calendarToday"}} + 'id': 'calendar_icon', + 'component': { + 'Icon': {'name': {'literalString': 'calendarToday'}} }, }, { - "id": "calendar_primary_text", - "component": { - "Text": { - "usageHint": "h5", - "text": {"path": "/calendar"}, - } + 'id': 'calendar_primary_text', + 'component': { + 'Text': {'usageHint': 'h5', 'text': {'path': '/calendar'}} }, }, { - "id": "calendar_secondary_text", - "component": {"Text": {"text": {"literalString": "Calendar"}}}, + 'id': 'calendar_secondary_text', + 'component': {'Text': {'text': {'literalString': 'Calendar'}}}, }, { - "id": "calendar_text_column", - "component": { - "Column": { - "children": { - "explicitList": [ - "calendar_primary_text", - "calendar_secondary_text", + 'id': 'calendar_text_column', + 'component': { + 'Column': { + 'children': { + 'explicitList': [ + 'calendar_primary_text', + 'calendar_secondary_text', ] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, { - "id": "info_row_1", - "component": { - "Row": { - "children": { - "explicitList": [ - "calendar_icon", - "calendar_text_column", + 'id': 'info_row_1', + 'component': { + 'Row': { + 'children': { + 'explicitList': [ + 'calendar_icon', + 'calendar_text_column', ] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, { - "id": "location_icon", - "component": { - "Icon": {"name": {"literalString": "locationOn"}} + 'id': 'location_icon', + 'component': { + 'Icon': {'name': {'literalString': 'locationOn'}} }, }, { - "id": "location_primary_text", - "component": { - "Text": { - "usageHint": "h5", - "text": {"path": "/location"}, - } + 'id': 'location_primary_text', + 'component': { + 'Text': {'usageHint': 'h5', 'text': {'path': '/location'}} }, }, { - "id": "location_secondary_text", - "component": {"Text": {"text": {"literalString": "Location"}}}, + 'id': 'location_secondary_text', + 'component': {'Text': {'text': {'literalString': 'Location'}}}, }, { - "id": "location_text_column", - "component": { - "Column": { - "children": { - "explicitList": [ - "location_primary_text", - "location_secondary_text", + 'id': 'location_text_column', + 'component': { + 'Column': { + 'children': { + 'explicitList': [ + 'location_primary_text', + 'location_secondary_text', ] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, { - "id": "info_row_2", - "component": { - "Row": { - "children": { - "explicitList": [ - "location_icon", - "location_text_column", + 'id': 'info_row_2', + 'component': { + 'Row': { + 'children': { + 'explicitList': [ + 'location_icon', + 'location_text_column', ] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, { - "id": "mail_icon", - "component": {"Icon": {"name": {"literalString": "mail"}}}, + 'id': 'mail_icon', + 'component': {'Icon': {'name': {'literalString': 'mail'}}}, }, { - "id": "mail_primary_text", - "component": { - "Text": {"usageHint": "h5", "text": {"path": "/email"}} + 'id': 'mail_primary_text', + 'component': { + 'Text': {'usageHint': 'h5', 'text': {'path': '/email'}} }, }, { - "id": "mail_secondary_text", - "component": {"Text": {"text": {"literalString": "Email"}}}, + 'id': 'mail_secondary_text', + 'component': {'Text': {'text': {'literalString': 'Email'}}}, }, { - "id": "mail_text_column", - "component": { - "Column": { - "children": { - "explicitList": [ - "mail_primary_text", - "mail_secondary_text", + 'id': 'mail_text_column', + 'component': { + 'Column': { + 'children': { + 'explicitList': [ + 'mail_primary_text', + 'mail_secondary_text', ] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, { - "id": "info_row_3", - "component": { - "Row": { - "children": { - "explicitList": [ - "mail_icon", - "mail_text_column", - ] + 'id': 'info_row_3', + 'component': { + 'Row': { + 'children': { + 'explicitList': ['mail_icon', 'mail_text_column'] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, - {"id": "div", "component": {"Divider": {}}}, + {'id': 'div', 'component': {'Divider': {}}}, { - "id": "call_icon", - "component": {"Icon": {"name": {"literalString": "call"}}}, + 'id': 'call_icon', + 'component': {'Icon': {'name': {'literalString': 'call'}}}, }, { - "id": "call_primary_text", - "component": { - "Text": {"usageHint": "h5", "text": {"path": "/mobile"}} + 'id': 'call_primary_text', + 'component': { + 'Text': {'usageHint': 'h5', 'text': {'path': '/mobile'}} }, }, { - "id": "call_secondary_text", - "component": {"Text": {"text": {"literalString": "Mobile"}}}, + 'id': 'call_secondary_text', + 'component': {'Text': {'text': {'literalString': 'Mobile'}}}, }, { - "id": "call_text_column", - "component": { - "Column": { - "children": { - "explicitList": [ - "call_primary_text", - "call_secondary_text", + 'id': 'call_text_column', + 'component': { + 'Column': { + 'children': { + 'explicitList': [ + 'call_primary_text', + 'call_secondary_text', ] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, { - "id": "info_row_4", - "component": { - "Row": { - "children": { - "explicitList": [ - "call_icon", - "call_text_column", - ] + 'id': 'info_row_4', + 'component': { + 'Row': { + 'children': { + 'explicitList': ['call_icon', 'call_text_column'] }, - "distribution": "start", - "alignment": "start", + 'distribution': 'start', + 'alignment': 'start', } }, }, { - "id": "info_rows_column", - "weight": 1, - "component": { - "Column": { - "children": { - "explicitList": [ - "info_row_1", - "info_row_2", - "info_row_3", - "info_row_4", + 'id': 'info_rows_column', + 'weight': 1, + 'component': { + 'Column': { + 'children': { + 'explicitList': [ + 'info_row_1', + 'info_row_2', + 'info_row_3', + 'info_row_4', ] }, - "alignment": "stretch", + 'alignment': 'stretch', } }, }, { - "id": "button_1_text", - "component": {"Text": {"text": {"literalString": "Follow"}}}, + 'id': 'button_1_text', + 'component': {'Text': {'text': {'literalString': 'Follow'}}}, }, { - "id": "button_1", - "component": { - "Button": { - "child": "button_1_text", - "primary": True, - "action": {"name": "follow_contact"}, + 'id': 'button_1', + 'component': { + 'Button': { + 'child': 'button_1_text', + 'primary': True, + 'action': {'name': 'follow_contact'}, } }, }, { - "id": "button_2_text", - "component": {"Text": {"text": {"literalString": "Message"}}}, + 'id': 'button_2_text', + 'component': {'Text': {'text': {'literalString': 'Message'}}}, }, { - "id": "button_2", - "component": { - "Button": { - "child": "button_2_text", - "primary": False, - "action": {"name": "send_message"}, + 'id': 'button_2', + 'component': { + 'Button': { + 'child': 'button_2_text', + 'primary': False, + 'action': {'name': 'send_message'}, } }, }, { - "id": "action_buttons_row", - "component": { - "Row": { - "children": {"explicitList": ["button_1", "button_2"]}, - "distribution": "center", - "alignment": "center", + 'id': 'action_buttons_row', + 'component': { + 'Row': { + 'children': {'explicitList': ['button_1', 'button_2']}, + 'distribution': 'center', + 'alignment': 'center', } }, }, { - "id": "link_text", - "component": { - "Text": { - "text": { - "literalString": "[View Full Profile](/profile)" + 'id': 'link_text', + 'component': { + 'Text': { + 'text': { + 'literalString': '[View Full Profile](/profile)' } } }, }, { - "id": "link_text_wrapper", - "component": { - "Row": { - "children": {"explicitList": ["link_text"]}, - "distribution": "center", - "alignment": "center", + 'id': 'link_text_wrapper', + 'component': { + 'Row': { + 'children': {'explicitList': ['link_text']}, + 'distribution': 'center', + 'alignment': 'center', } }, }, { - "id": "main_column", - "component": { - "Column": { - "children": { - "explicitList": [ - "profile_image", - "description_column", - "div", - "info_rows_column", - "action_buttons_row", - "link_text_wrapper", + 'id': 'main_column', + 'component': { + 'Column': { + 'children': { + 'explicitList': [ + 'profile_image', + 'description_column', + 'div', + 'info_rows_column', + 'action_buttons_row', + 'link_text_wrapper', ] }, - "alignment": "stretch", + 'alignment': 'stretch', } }, }, { - "id": "main_card", - "component": {"Card": {"child": "main_column"}}, + 'id': 'main_card', + 'component': {'Card': {'child': 'main_column'}}, }, ], } }, { - "dataModelUpdate": { - "surfaceId": "contact-card", - "path": "/", - "contents": [ - {"key": "name", "valueString": "Casey Smith"}, - {"key": "title", "valueString": "Digital Marketing Specialist"}, - {"key": "team", "valueString": "Growth Team"}, - {"key": "location", "valueString": "New York"}, - {"key": "email", "valueString": "casey.smith@example.com"}, - {"key": "mobile", "valueString": "+1 (415) 222-3333"}, - {"key": "calendar", "valueString": "In a meeting"}, - { - "key": "imageUrl", - "valueString": "http://localhost:10003/static/profile2.png", - }, - { - "key": "contacts", - "valueMap": [{ - "key": "contact1", - "valueMap": [{"key": "name", "valueString": "Casey Smith"}], + 'dataModelUpdate': { + 'surfaceId': 'contact-card', + 'path': '/', + 'contents': [ + {'key': 'name', 'valueString': 'Casey Smith'}, + {'key': 'title', 'valueString': 'Digital Marketing Specialist'}, + {'key': 'team', 'valueString': 'Growth Team'}, + {'key': 'location', 'valueString': 'New York'}, + {'key': 'email', 'valueString': 'casey.smith@example.com'}, + {'key': 'mobile', 'valueString': '+1 (415) 222-3333'}, + {'key': 'calendar', 'valueString': 'In a meeting'}, + { + 'key': 'imageUrl', + 'valueString': 'http://localhost:10003/static/profile2.png', + }, + { + 'key': 'contacts', + 'valueMap': [{ + 'key': 'contact1', + 'valueMap': [{'key': 'name', 'valueString': 'Casey Smith'}], }], }, ], @@ -394,9 +382,9 @@ def verify(): }, ] catalog.validator.validate(a2ui_message) - print("Validation successful") + print('Validation successful') except Exception as e: - print(f"Failed to load {VERSION_0_8}: {e}") + print(f'Failed to load {VERSION_0_8}: {e}') sys.exit(1) try: @@ -407,209 +395,205 @@ def verify(): ) catalog = manager.get_selected_catalog() catalog_components = catalog.catalog_schema[CATALOG_COMPONENTS_KEY] - print(f"Successfully loaded {VERSION_0_9}: {len(catalog_components)} components") - print(f"Components found: {list(catalog_components.keys())}...") + print(f'Successfully loaded {VERSION_0_9}: {len(catalog_components)} components') + print(f'Components found: {list(catalog_components.keys())}...') a2ui_message = [ { - "version": "v0.9", - "createSurface": { - "surfaceId": "contact_form_1", - "catalogId": "https://a2ui.dev/specification/v0_9/basic_catalog.json", - "fakeProperty": "should be allowed", + 'version': 'v0.9', + 'createSurface': { + 'surfaceId': 'contact_form_1', + 'catalogId': 'https://a2ui.dev/specification/v0_9/basic_catalog.json', + 'fakeProperty': 'should be allowed', }, }, { - "version": "v0.9", - "updateComponents": { - "surfaceId": "contact_form_1", - "components": [ - {"id": "root", "component": "Card", "child": "form_container"}, - { - "id": "form_container", - "component": "Column", - "children": [ - "header_row", - "name_row", - "email_group", - "phone_group", - "pref_group", - "divider_1", - "newsletter_checkbox", - "submit_button", + 'version': 'v0.9', + 'updateComponents': { + 'surfaceId': 'contact_form_1', + 'components': [ + {'id': 'root', 'component': 'Card', 'child': 'form_container'}, + { + 'id': 'form_container', + 'component': 'Column', + 'children': [ + 'header_row', + 'name_row', + 'email_group', + 'phone_group', + 'pref_group', + 'divider_1', + 'newsletter_checkbox', + 'submit_button', ], - "justify": "start", - "align": "stretch", + 'justify': 'start', + 'align': 'stretch', }, { - "id": "header_row", - "component": "Row", - "children": ["header_icon", "header_text"], - "align": "center", + 'id': 'header_row', + 'component': 'Row', + 'children': ['header_icon', 'header_text'], + 'align': 'center', }, - {"id": "header_icon", "component": "Icon", "name": "mail"}, + {'id': 'header_icon', 'component': 'Icon', 'name': 'mail'}, { - "id": "header_text", - "component": "Text", - "text": "# Contact Us", - "variant": "h2", + 'id': 'header_text', + 'component': 'Text', + 'text': '# Contact Us', + 'variant': 'h2', }, { - "id": "name_row", - "component": "Row", - "children": ["first_name_group", "last_name_group"], - "justify": "spaceBetween", + 'id': 'name_row', + 'component': 'Row', + 'children': ['first_name_group', 'last_name_group'], + 'justify': 'spaceBetween', }, { - "id": "first_name_group", - "component": "Column", - "children": ["first_name_label", "first_name_field"], - "weight": 1, + 'id': 'first_name_group', + 'component': 'Column', + 'children': ['first_name_label', 'first_name_field'], + 'weight': 1, }, { - "id": "first_name_label", - "component": "Text", - "text": "First Name", - "variant": "caption", + 'id': 'first_name_label', + 'component': 'Text', + 'text': 'First Name', + 'variant': 'caption', }, { - "id": "first_name_field", - "component": "TextField", - "label": "First Name", - "value": {"path": "/contact/firstName"}, - "variant": "shortText", + 'id': 'first_name_field', + 'component': 'TextField', + 'label': 'First Name', + 'value': {'path': '/contact/firstName'}, + 'variant': 'shortText', }, { - "id": "last_name_group", - "component": "Column", - "children": ["last_name_label", "last_name_field"], - "weight": 1, + 'id': 'last_name_group', + 'component': 'Column', + 'children': ['last_name_label', 'last_name_field'], + 'weight': 1, }, { - "id": "last_name_label", - "component": "Text", - "text": "Last Name", - "variant": "caption", + 'id': 'last_name_label', + 'component': 'Text', + 'text': 'Last Name', + 'variant': 'caption', }, { - "id": "last_name_field", - "component": "TextField", - "label": "Last Name", - "value": {"path": "/contact/lastName"}, - "variant": "shortText", + 'id': 'last_name_field', + 'component': 'TextField', + 'label': 'Last Name', + 'value': {'path': '/contact/lastName'}, + 'variant': 'shortText', }, { - "id": "email_group", - "component": "Column", - "children": ["email_label", "email_field"], + 'id': 'email_group', + 'component': 'Column', + 'children': ['email_label', 'email_field'], }, { - "id": "email_label", - "component": "Text", - "text": "Email Address", - "variant": "caption", + 'id': 'email_label', + 'component': 'Text', + 'text': 'Email Address', + 'variant': 'caption', }, { - "id": "email_field", - "component": "TextField", - "label": "Email", - "value": {"path": "/contact/email"}, - "variant": "shortText", - "checks": [ + 'id': 'email_field', + 'component': 'TextField', + 'label': 'Email', + 'value': {'path': '/contact/email'}, + 'variant': 'shortText', + 'checks': [ { - "condition": { - "call": "required", - "args": {"value": {"path": "/contact/email"}}, + 'condition': { + 'call': 'required', + 'args': {'value': {'path': '/contact/email'}}, }, - "message": "Email is required.", + 'message': 'Email is required.', }, { - "condition": { - "call": "email", - "args": {"value": {"path": "/contact/email"}}, + 'condition': { + 'call': 'email', + 'args': {'value': {'path': '/contact/email'}}, }, - "message": "Please enter a valid email address.", + 'message': 'Please enter a valid email address.', }, ], }, { - "id": "phone_group", - "component": "Column", - "children": ["phone_label", "phone_field"], + 'id': 'phone_group', + 'component': 'Column', + 'children': ['phone_label', 'phone_field'], }, { - "id": "phone_label", - "component": "Text", - "text": "Phone Number", - "variant": "caption", + 'id': 'phone_label', + 'component': 'Text', + 'text': 'Phone Number', + 'variant': 'caption', }, { - "id": "phone_field", - "component": "TextField", - "label": "Phone", - "value": {"path": "/contact/phone"}, - "variant": "shortText", - "checks": [{ - "condition": { - "call": "regex", - "args": { - "value": {"path": "/contact/phone"}, - "pattern": "^\\d{10}$", + 'id': 'phone_field', + 'component': 'TextField', + 'label': 'Phone', + 'value': {'path': '/contact/phone'}, + 'variant': 'shortText', + 'checks': [{ + 'condition': { + 'call': 'regex', + 'args': { + 'value': {'path': '/contact/phone'}, + 'pattern': '^\\d{10}$', }, }, - "message": "Phone number must be 10 digits.", + 'message': 'Phone number must be 10 digits.', }], }, { - "id": "pref_group", - "component": "Column", - "children": ["pref_label", "pref_picker"], + 'id': 'pref_group', + 'component': 'Column', + 'children': ['pref_label', 'pref_picker'], }, { - "id": "pref_label", - "component": "Text", - "text": "Preferred Contact Method", - "variant": "caption", + 'id': 'pref_label', + 'component': 'Text', + 'text': 'Preferred Contact Method', + 'variant': 'caption', }, { - "id": "pref_picker", - "component": "ChoicePicker", - "variant": "mutuallyExclusive", - "options": [ - {"label": "Email", "value": "email"}, - {"label": "Phone", "value": "phone"}, - {"label": "SMS", "value": "sms"}, + 'id': 'pref_picker', + 'component': 'ChoicePicker', + 'variant': 'mutuallyExclusive', + 'options': [ + {'label': 'Email', 'value': 'email'}, + {'label': 'Phone', 'value': 'phone'}, + {'label': 'SMS', 'value': 'sms'}, ], - "value": {"path": "/contact/preference"}, - }, - { - "id": "divider_1", - "component": "Divider", - "axis": "horizontal", + 'value': {'path': '/contact/preference'}, }, + {'id': 'divider_1', 'component': 'Divider', 'axis': 'horizontal'}, { - "id": "newsletter_checkbox", - "component": "CheckBox", - "label": "Subscribe to our newsletter", - "value": {"path": "/contact/subscribe"}, + 'id': 'newsletter_checkbox', + 'component': 'CheckBox', + 'label': 'Subscribe to our newsletter', + 'value': {'path': '/contact/subscribe'}, }, { - "id": "submit_button_label", - "component": "Text", - "text": "Send Message", + 'id': 'submit_button_label', + 'component': 'Text', + 'text': 'Send Message', }, { - "id": "submit_button", - "component": "Button", - "child": "submit_button_label", - "variant": "primary", - "action": { - "event": { - "name": "submitContactForm", - "context": { - "formId": "contact_form_1", - "isNewsletterSubscribed": { - "path": "/contact/subscribe" + 'id': 'submit_button', + 'component': 'Button', + 'child': 'submit_button_label', + 'variant': 'primary', + 'action': { + 'event': { + 'name': 'submitContactForm', + 'context': { + 'formId': 'contact_form_1', + 'isNewsletterSubscribed': { + 'path': '/contact/subscribe' }, }, } @@ -619,28 +603,28 @@ def verify(): }, }, { - "version": "v0.9", - "updateDataModel": { - "surfaceId": "contact_form_1", - "path": "/contact", - "value": { - "firstName": "John", - "lastName": "Doe", - "email": "john.doe@example.com", - "phone": "1234567890", - "preference": ["email"], - "subscribe": True, + 'version': 'v0.9', + 'updateDataModel': { + 'surfaceId': 'contact_form_1', + 'path': '/contact', + 'value': { + 'firstName': 'John', + 'lastName': 'Doe', + 'email': 'john.doe@example.com', + 'phone': '1234567890', + 'preference': ['email'], + 'subscribe': True, }, }, }, - {"version": "v0.9", "deleteSurface": {"surfaceId": "contact_form_1"}}, + {'version': 'v0.9', 'deleteSurface': {'surfaceId': 'contact_form_1'}}, ] catalog.validator.validate(a2ui_message) - print("Validation successful") + print('Validation successful') except Exception as e: - print(f"Failed to load {VERSION_0_9}: {e}") + print(f'Failed to load {VERSION_0_9}: {e}') sys.exit(1) -if __name__ == "__main__": +if __name__ == '__main__': verify() diff --git a/samples/agent/adk/component_gallery/__main__.py b/samples/agent/adk/component_gallery/__main__.py index 234c1e0a1..050c53446 100644 --- a/samples/agent/adk/component_gallery/__main__.py +++ b/samples/agent/adk/component_gallery/__main__.py @@ -48,69 +48,69 @@ @click.option("--host", default="localhost") @click.option("--port", default=10005) def main(host, port): - try: - capabilities = AgentCapabilities( - streaming=True, - extensions=[get_a2ui_agent_extension()], - ) - - # Skill definition - skill = AgentSkill( - id="component_gallery", - name="Component Gallery", - description="Demonstrates A2UI components.", - tags=["gallery", "demo"], - examples=["Show me the gallery"], - ) - - base_url = f"http://{host}:{port}" - - agent_card = AgentCard( - name="Component Gallery Agent", - description="A2UI Component Gallery", - url=base_url, - version="0.0.1", - default_input_modes=["text"], - default_output_modes=["text"], - capabilities=capabilities, - skills=[skill], - ) - - agent_executor = ComponentGalleryExecutor(base_url=base_url) - - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - - server = A2AStarletteApplication( - agent_card=agent_card, http_handler=request_handler - ) - - app = server.build() - - app.add_middleware( - CORSMiddleware, - allow_origins=["http://localhost:5173"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) - - # Mount assets directory - assets_dir = os.path.join(os.path.dirname(__file__), "assets") - if os.path.exists(assets_dir): - app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") - else: - logger.warning(f"Assets directory not found at {assets_dir}") - - print(f"Starting Component Gallery Agent on port {port}...") - uvicorn.run(app, host=host, port=port) - - except Exception as e: - logger.error(f"An error occurred during server startup: {e}") - exit(1) + try: + capabilities = AgentCapabilities( + streaming=True, + extensions=[get_a2ui_agent_extension()], + ) + + # Skill definition + skill = AgentSkill( + id="component_gallery", + name="Component Gallery", + description="Demonstrates A2UI components.", + tags=["gallery", "demo"], + examples=["Show me the gallery"], + ) + + base_url = f"http://{host}:{port}" + + agent_card = AgentCard( + name="Component Gallery Agent", + description="A2UI Component Gallery", + url=base_url, + version="0.0.1", + default_input_modes=["text"], + default_output_modes=["text"], + capabilities=capabilities, + skills=[skill], + ) + + agent_executor = ComponentGalleryExecutor(base_url=base_url) + + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + + server = A2AStarletteApplication( + agent_card=agent_card, http_handler=request_handler + ) + + app = server.build() + + app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:5173"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + # Mount assets directory + assets_dir = os.path.join(os.path.dirname(__file__), "assets") + if os.path.exists(assets_dir): + app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") + else: + logger.warning(f"Assets directory not found at {assets_dir}") + + print(f"Starting Component Gallery Agent on port {port}...") + uvicorn.run(app, host=host, port=port) + + except Exception as e: + logger.error(f"An error occurred during server startup: {e}") + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/component_gallery/agent.py b/samples/agent/adk/component_gallery/agent.py index 4e0d48f51..855d4d935 100644 --- a/samples/agent/adk/component_gallery/agent.py +++ b/samples/agent/adk/component_gallery/agent.py @@ -32,74 +32,68 @@ class ComponentGalleryAgent: - """An agent that displays a component gallery.""" - - def __init__(self, base_url: str): - self.base_url = base_url - - async def stream( - self, query: str, session_id: str - ) -> AsyncIterable[dict[str, Any]]: - """Streams the gallery or responses to actions.""" - - logger.info(f"Stream called with query: {query}") - - # Initial Load or Reset - if ( - "WHO_ARE_YOU" in query or "START" in query - ): # Simple trigger for initial load - gallery_json = get_gallery_json() - yield { - "is_task_complete": True, - "parts": parse_response_to_parts( - "Here is the component" - f" gallery.\n{A2UI_OPEN_TAG}\n{gallery_json}\n{A2UI_CLOSE_TAG}" - ), - } - return - - # Handle Actions - if query.startswith("ACTION:"): - action_name = query - # Create a response update for the second surface - - # Simulate network/processing delay - await asyncio.sleep(0.5) - - timestamp = datetime.datetime.now().strftime("%H:%M:%S") - - response_update = { - "surfaceUpdate": { - "surfaceId": "response-surface", - "components": [ - { - "id": "response-text", - "component": { - "Text": { - "text": { - "literalString": ( - f"Agent Processed Action: {action_name} at" - f" {timestamp}" - ) - } - } - }, - } - ], - } - } - - yield { - "is_task_complete": True, - "parts": [ - Part(root=TextPart(text="Action processed.")), - create_a2ui_part(response_update), - ], - } - return - - # Fallback for text - yield { - "is_task_complete": True, - "parts": [Part(root=TextPart(text="I am the Component Gallery Agent."))], - } + """An agent that displays a component gallery.""" + + def __init__(self, base_url: str): + self.base_url = base_url + + async def stream(self, query: str, session_id: str) -> AsyncIterable[dict[str, Any]]: + """Streams the gallery or responses to actions.""" + + logger.info(f"Stream called with query: {query}") + + # Initial Load or Reset + if "WHO_ARE_YOU" in query or "START" in query: # Simple trigger for initial load + gallery_json = get_gallery_json() + yield { + "is_task_complete": True, + "parts": parse_response_to_parts( + "Here is the component" + f" gallery.\n{A2UI_OPEN_TAG}\n{gallery_json}\n{A2UI_CLOSE_TAG}" + ), + } + return + + # Handle Actions + if query.startswith("ACTION:"): + action_name = query + # Create a response update for the second surface + + # Simulate network/processing delay + await asyncio.sleep(0.5) + + timestamp = datetime.datetime.now().strftime("%H:%M:%S") + + response_update = { + "surfaceUpdate": { + "surfaceId": "response-surface", + "components": [{ + "id": "response-text", + "component": { + "Text": { + "text": { + "literalString": ( + f"Agent Processed Action: {action_name} at" + f" {timestamp}" + ) + } + } + }, + }], + } + } + + yield { + "is_task_complete": True, + "parts": [ + Part(root=TextPart(text="Action processed.")), + create_a2ui_part(response_update), + ], + } + return + + # Fallback for text + yield { + "is_task_complete": True, + "parts": [Part(root=TextPart(text="I am the Component Gallery Agent."))], + } diff --git a/samples/agent/adk/component_gallery/agent_executor.py b/samples/agent/adk/component_gallery/agent_executor.py index 29a3ec66b..d0bed73c7 100644 --- a/samples/agent/adk/component_gallery/agent_executor.py +++ b/samples/agent/adk/component_gallery/agent_executor.py @@ -29,47 +29,47 @@ class ComponentGalleryExecutor(AgentExecutor): - def __init__(self, base_url: str): - self.agent = ComponentGalleryAgent(base_url=base_url) + def __init__(self, base_url: str): + self.agent = ComponentGalleryAgent(base_url=base_url) - async def execute(self, context: RequestContext, event_queue: EventQueue) -> None: - query = "START" # Default start - ui_event_part = None + async def execute(self, context: RequestContext, event_queue: EventQueue) -> None: + query = "START" # Default start + ui_event_part = None - try_activate_a2ui_extension(context) + try_activate_a2ui_extension(context) - if context.message and context.message.parts: - for part in context.message.parts: - if isinstance(part.root, DataPart): - if "userAction" in part.root.data: - ui_event_part = part.root.data["userAction"] - elif "request" in part.root.data: - query = part.root.data["request"] - elif isinstance(part.root, TextPart): - # If user says something, might want to handle it, but for now defaults to START usually for initial connection - if part.root.text: - query = part.root.text + if context.message and context.message.parts: + for part in context.message.parts: + if isinstance(part.root, DataPart): + if "userAction" in part.root.data: + ui_event_part = part.root.data["userAction"] + elif "request" in part.root.data: + query = part.root.data["request"] + elif isinstance(part.root, TextPart): + # If user says something, might want to handle it, but for now defaults to START usually for initial connection + if part.root.text: + query = part.root.text - if ui_event_part: - action = ui_event_part.get("name") - ctx = ui_event_part.get("context", {}) - query = f"ACTION: {action} with {ctx}" + if ui_event_part: + action = ui_event_part.get("name") + ctx = ui_event_part.get("context", {}) + query = f"ACTION: {action} with {ctx}" - task = context.current_task - if not task: - task = new_task(context.message) - await event_queue.enqueue_event(task) + task = context.current_task + if not task: + task = new_task(context.message) + await event_queue.enqueue_event(task) - updater = TaskUpdater(event_queue, task.id, task.context_id) + updater = TaskUpdater(event_queue, task.id, task.context_id) - async for item in self.agent.stream(query, task.context_id): - final_parts = item["parts"] + async for item in self.agent.stream(query, task.context_id): + final_parts = item["parts"] - await updater.update_status( - TaskState.completed, - new_agent_parts_message(final_parts, task.context_id, task.id), - final=True, - ) + await updater.update_status( + TaskState.completed, + new_agent_parts_message(final_parts, task.context_id, task.id), + final=True, + ) - async def cancel(self, request, event_queue): - pass + async def cancel(self, request, event_queue): + pass diff --git a/samples/agent/adk/component_gallery/gallery_examples.py b/samples/agent/adk/component_gallery/gallery_examples.py index 389bcfecb..65e5e788e 100644 --- a/samples/agent/adk/component_gallery/gallery_examples.py +++ b/samples/agent/adk/component_gallery/gallery_examples.py @@ -18,512 +18,474 @@ def get_gallery_json() -> str: - """Returns the JSON structure for the Component Gallery surfaces.""" - - messages = [] - - # Common Data Model - # We use a single global data model for simplicity across all demo surfaces. - # Common Data Model Content - # We define the content here and inject it into EACH surface so they all share the same initial state. - gallery_data_content = { - "key": "galleryData", - "valueMap": [ - {"key": "textField", "valueString": "Hello World"}, - {"key": "checkbox", "valueBoolean": False}, - {"key": "checkboxChecked", "valueBoolean": True}, - {"key": "slider", "valueNumber": 30}, - {"key": "date", "valueString": "2025-10-26"}, - {"key": "favorites", "valueMap": [{"key": "0", "valueString": "A"}]}, - {"key": "favoritesChips", "valueMap": []}, - {"key": "favoritesFilter", "valueMap": []}, - ], - } - - # Helper to create a surface for a single component - def add_demo_surface(surface_id, component_def): - root_id = f"{surface_id}-root" - - components = [] - components.append({"id": root_id, "component": component_def}) - - messages.append({"beginRendering": {"surfaceId": surface_id, "root": root_id}}) - messages.append( - {"surfaceUpdate": {"surfaceId": surface_id, "components": components}} - ) - - # Inject data model for this surface - messages.append( - { - "dataModelUpdate": { - "surfaceId": surface_id, - "contents": [gallery_data_content], - } - } - ) - - # 1. TextField - add_demo_surface( - "demo-text", - { - "TextField": { - "label": {"literalString": "Enter some text"}, - "text": {"path": "galleryData/textField"}, - } - }, - ) - - # 1b. TextField (Regex) - add_demo_surface( - "demo-text-regex", - { - "TextField": { - "label": {"literalString": "Enter exactly 5 digits"}, - "text": {"path": "galleryData/textFieldRegex"}, - "validationRegexp": "^\\d{5}$", - } - }, - ) - - # 2. CheckBox - add_demo_surface( - "demo-checkbox", - { - "CheckBox": { - "label": {"literalString": "Toggle me"}, - "value": {"path": "galleryData/checkbox"}, - } - }, - ) - - # 3. Slider - add_demo_surface( - "demo-slider", - { - "Slider": { - "value": {"path": "galleryData/slider"}, - "minValue": 0, - "maxValue": 100, - } - }, - ) - - # 4. DateTimeInput - add_demo_surface( - "demo-date", - {"DateTimeInput": {"value": {"path": "galleryData/date"}, "enableDate": True}}, - ) - - # 5. MultipleChoice (Default) - add_demo_surface( - "demo-multichoice", - { - "MultipleChoice": { - "selections": {"path": "galleryData/favorites"}, - "options": [ - {"label": {"literalString": "Apple"}, "value": "A"}, - {"label": {"literalString": "Banana"}, "value": "B"}, - {"label": {"literalString": "Cherry"}, "value": "C"}, - ], - } - }, - ) - - # 5b. MultipleChoice (Chips) - add_demo_surface( - "demo-multichoice-chips", - { - "MultipleChoice": { - "selections": {"path": "galleryData/favoritesChips"}, - "description": "Select tags (Chips)", - "variant": "chips", - "options": [ - {"label": {"literalString": "Work"}, "value": "work"}, - {"label": {"literalString": "Home"}, "value": "home"}, - {"label": {"literalString": "Urgent"}, "value": "urgent"}, - {"label": {"literalString": "Later"}, "value": "later"}, - ], - } - }, - ) - - # 5c. MultipleChoice (Filterable) - add_demo_surface( - "demo-multichoice-filter", - { - "MultipleChoice": { - "selections": {"path": "galleryData/favoritesFilter"}, - "description": "Select countries (Filterable)", - "filterable": True, - "options": [ - {"label": {"literalString": "United States"}, "value": "US"}, - {"label": {"literalString": "Canada"}, "value": "CA"}, - {"label": {"literalString": "United Kingdom"}, "value": "UK"}, - {"label": {"literalString": "Australia"}, "value": "AU"}, - {"label": {"literalString": "Germany"}, "value": "DE"}, - {"label": {"literalString": "France"}, "value": "FR"}, - {"label": {"literalString": "Japan"}, "value": "JP"}, - ], - } - }, - ) - - # 6. Image - add_demo_surface( - "demo-image", - { - "Image": { - "url": {"literalString": "http://localhost:10005/assets/a2ui.png"}, - "usageHint": "mediumFeature", - } - }, - ) - - # 7. Button - # Button needs a child Text component. - button_surface_id = "demo-button" - btn_root_id = "demo-button-root" - btn_text_id = "demo-button-text" - - messages.append( - {"beginRendering": {"surfaceId": button_surface_id, "root": btn_root_id}} - ) - messages.append( - { - "surfaceUpdate": { - "surfaceId": button_surface_id, - "components": [ - { - "id": btn_text_id, - "component": { - "Text": {"text": {"literalString": "Trigger Action"}} - }, - }, - { - "id": btn_root_id, - "component": { - "Button": { - "child": btn_text_id, - "primary": True, - "action": { - "name": "custom_action", - "context": [ - { - "key": "info", - "value": { - "literalString": "Custom Button Clicked" - }, - } - ], - }, - } - }, - }, - ], - } - } - ) - - # 8. Tabs - tabs_surface_id = "demo-tabs" - tabs_root_id = "demo-tabs-root" - tab1_id = "tab-1-content" - tab2_id = "tab-2-content" - - messages.append( - {"beginRendering": {"surfaceId": tabs_surface_id, "root": tabs_root_id}} - ) - messages.append( - { - "surfaceUpdate": { - "surfaceId": tabs_surface_id, - "components": [ - { - "id": tab1_id, - "component": { - "Text": {"text": {"literalString": "First Tab Content"}} - }, - }, - { - "id": tab2_id, - "component": { - "Text": {"text": {"literalString": "Second Tab Content"}} - }, - }, - { - "id": tabs_root_id, - "component": { - "Tabs": { - "tabItems": [ - { - "title": {"literalString": "View One"}, - "child": tab1_id, - }, - { - "title": {"literalString": "View Two"}, - "child": tab2_id, - }, - ] - } - }, - }, - ], - } - } - ) - - # 9. Icon - icon_surface_id = "demo-icon" - messages.append( - {"beginRendering": {"surfaceId": icon_surface_id, "root": "icon-root"}} - ) + """Returns the JSON structure for the Component Gallery surfaces.""" + + messages = [] + + # Common Data Model + # We use a single global data model for simplicity across all demo surfaces. + # Common Data Model Content + # We define the content here and inject it into EACH surface so they all share the same initial state. + gallery_data_content = { + "key": "galleryData", + "valueMap": [ + {"key": "textField", "valueString": "Hello World"}, + {"key": "checkbox", "valueBoolean": False}, + {"key": "checkboxChecked", "valueBoolean": True}, + {"key": "slider", "valueNumber": 30}, + {"key": "date", "valueString": "2025-10-26"}, + {"key": "favorites", "valueMap": [{"key": "0", "valueString": "A"}]}, + {"key": "favoritesChips", "valueMap": []}, + {"key": "favoritesFilter", "valueMap": []}, + ], + } + + # Helper to create a surface for a single component + def add_demo_surface(surface_id, component_def): + root_id = f"{surface_id}-root" + + components = [] + components.append({"id": root_id, "component": component_def}) + + messages.append({"beginRendering": {"surfaceId": surface_id, "root": root_id}}) messages.append( - { - "surfaceUpdate": { - "surfaceId": icon_surface_id, - "components": [ - { - "id": "icon-root", - "component": { - "Row": { - "children": { - "explicitList": ["icon-1", "icon-2", "icon-3"] - }, - "distribution": "spaceEvenly", - "alignment": "center", - } - }, - }, - { - "id": "icon-1", - "component": {"Icon": {"name": {"literalString": "star"}}}, - }, - { - "id": "icon-2", - "component": {"Icon": {"name": {"literalString": "home"}}}, - }, - { - "id": "icon-3", - "component": {"Icon": {"name": {"literalString": "settings"}}}, - }, - ], - } - } - ) - - # 10. Divider - div_surface_id = "demo-divider" - messages.append( - {"beginRendering": {"surfaceId": div_surface_id, "root": "div-root"}} - ) - messages.append( - { - "surfaceUpdate": { - "surfaceId": div_surface_id, - "components": [ - { - "id": "div-root", - "component": { - "Column": { - "children": { - "explicitList": [ - "div-text-1", - "div-horiz", - "div-text-2", - ] - }, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "div-text-1", - "component": { - "Text": {"text": {"literalString": "Above Divider"}} - }, - }, - { - "id": "div-horiz", - "component": {"Divider": {"axis": "horizontal"}}, - }, - { - "id": "div-text-2", - "component": { - "Text": {"text": {"literalString": "Below Divider"}} - }, - }, - ], - } - } - ) - - # 11. Card - card_surface_id = "demo-card" - messages.append( - {"beginRendering": {"surfaceId": card_surface_id, "root": "card-root"}} - ) - messages.append( - { - "surfaceUpdate": { - "surfaceId": card_surface_id, - "components": [ - {"id": "card-root", "component": {"Card": {"child": "card-text"}}}, - { - "id": "card-text", - "component": { - "Text": {"text": {"literalString": "I am inside a Card"}} - }, - }, - ], - } - } - ) - - # 12. Video - add_demo_surface( - "demo-video", - { - "Video": { - # Still external as user only provided audio and image - "url": { - "literalString": ( - "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" - ) - } - } - }, - ) - - # 13. Modal - # Modal needs an entry point (Button) and content. - modal_surface_id = "demo-modal" - messages.append( - {"beginRendering": {"surfaceId": modal_surface_id, "root": "modal-root"}} - ) - messages.append( - { - "surfaceUpdate": { - "surfaceId": modal_surface_id, - "components": [ - { - "id": "modal-root", - "component": { - "Modal": { - "entryPointChild": "modal-btn", - "contentChild": "modal-content", - } - }, - }, - { - "id": "modal-btn", - "component": { - "Button": { - "child": "modal-btn-text", - "primary": False, - "action": {"name": "noop"}, - } - }, - }, - { - "id": "modal-btn-text", - "component": { - "Text": {"text": {"literalString": "Open Modal"}} - }, - }, - { - "id": "modal-content", - "component": { - "Text": { - "text": {"literalString": "This is the modal content!"} - } - }, - }, - ], - } - } + {"surfaceUpdate": {"surfaceId": surface_id, "components": components}} ) - # 14. List - list_surface_id = "demo-list" - messages.append( - {"beginRendering": {"surfaceId": list_surface_id, "root": "list-root"}} - ) - messages.append( - { - "surfaceUpdate": { - "surfaceId": list_surface_id, - "components": [ - { - "id": "list-root", - "component": { - "List": { - "children": { - "explicitList": [ - "list-item-1", - "list-item-2", - "list-item-3", - ] - }, - "direction": "vertical", - "alignment": "stretch", - } - }, - }, - { - "id": "list-item-1", - "component": {"Text": {"text": {"literalString": "Item 1"}}}, - }, - { - "id": "list-item-2", - "component": {"Text": {"text": {"literalString": "Item 2"}}}, - }, - { - "id": "list-item-3", - "component": {"Text": {"text": {"literalString": "Item 3"}}}, - }, - ], - } + # Inject data model for this surface + messages.append({ + "dataModelUpdate": { + "surfaceId": surface_id, + "contents": [gallery_data_content], } - ) - - # 15. AudioPlayer - add_demo_surface( - "demo-audio", - { - "AudioPlayer": { - "url": {"literalString": "http://localhost:10005/assets/audio.mp3"}, - "description": {"literalString": "Local Audio Sample"}, - } - }, - ) - - # Response Surface - messages.append( - {"beginRendering": {"surfaceId": "response-surface", "root": "response-text"}} - ) - messages.append( - { - "surfaceUpdate": { - "surfaceId": "response-surface", - "components": [ - { - "id": "response-text", - "component": { - "Text": { - "text": { - "literalString": ( - "Interact with the gallery to see responses. This view is" - " updated by the agent by relaying the raw action" - " commands it received from the client" - ) - } - } - }, - } - ], - } - } - ) - - return json.dumps(messages, indent=2) + }) + + # 1. TextField + add_demo_surface( + "demo-text", + { + "TextField": { + "label": {"literalString": "Enter some text"}, + "text": {"path": "galleryData/textField"}, + } + }, + ) + + # 1b. TextField (Regex) + add_demo_surface( + "demo-text-regex", + { + "TextField": { + "label": {"literalString": "Enter exactly 5 digits"}, + "text": {"path": "galleryData/textFieldRegex"}, + "validationRegexp": "^\\d{5}$", + } + }, + ) + + # 2. CheckBox + add_demo_surface( + "demo-checkbox", + { + "CheckBox": { + "label": {"literalString": "Toggle me"}, + "value": {"path": "galleryData/checkbox"}, + } + }, + ) + + # 3. Slider + add_demo_surface( + "demo-slider", + { + "Slider": { + "value": {"path": "galleryData/slider"}, + "minValue": 0, + "maxValue": 100, + } + }, + ) + + # 4. DateTimeInput + add_demo_surface( + "demo-date", + {"DateTimeInput": {"value": {"path": "galleryData/date"}, "enableDate": True}}, + ) + + # 5. MultipleChoice (Default) + add_demo_surface( + "demo-multichoice", + { + "MultipleChoice": { + "selections": {"path": "galleryData/favorites"}, + "options": [ + {"label": {"literalString": "Apple"}, "value": "A"}, + {"label": {"literalString": "Banana"}, "value": "B"}, + {"label": {"literalString": "Cherry"}, "value": "C"}, + ], + } + }, + ) + + # 5b. MultipleChoice (Chips) + add_demo_surface( + "demo-multichoice-chips", + { + "MultipleChoice": { + "selections": {"path": "galleryData/favoritesChips"}, + "description": "Select tags (Chips)", + "variant": "chips", + "options": [ + {"label": {"literalString": "Work"}, "value": "work"}, + {"label": {"literalString": "Home"}, "value": "home"}, + {"label": {"literalString": "Urgent"}, "value": "urgent"}, + {"label": {"literalString": "Later"}, "value": "later"}, + ], + } + }, + ) + + # 5c. MultipleChoice (Filterable) + add_demo_surface( + "demo-multichoice-filter", + { + "MultipleChoice": { + "selections": {"path": "galleryData/favoritesFilter"}, + "description": "Select countries (Filterable)", + "filterable": True, + "options": [ + {"label": {"literalString": "United States"}, "value": "US"}, + {"label": {"literalString": "Canada"}, "value": "CA"}, + {"label": {"literalString": "United Kingdom"}, "value": "UK"}, + {"label": {"literalString": "Australia"}, "value": "AU"}, + {"label": {"literalString": "Germany"}, "value": "DE"}, + {"label": {"literalString": "France"}, "value": "FR"}, + {"label": {"literalString": "Japan"}, "value": "JP"}, + ], + } + }, + ) + + # 6. Image + add_demo_surface( + "demo-image", + { + "Image": { + "url": {"literalString": "http://localhost:10005/assets/a2ui.png"}, + "usageHint": "mediumFeature", + } + }, + ) + + # 7. Button + # Button needs a child Text component. + button_surface_id = "demo-button" + btn_root_id = "demo-button-root" + btn_text_id = "demo-button-text" + + messages.append( + {"beginRendering": {"surfaceId": button_surface_id, "root": btn_root_id}} + ) + messages.append({ + "surfaceUpdate": { + "surfaceId": button_surface_id, + "components": [ + { + "id": btn_text_id, + "component": {"Text": {"text": {"literalString": "Trigger Action"}}}, + }, + { + "id": btn_root_id, + "component": { + "Button": { + "child": btn_text_id, + "primary": True, + "action": { + "name": "custom_action", + "context": [{ + "key": "info", + "value": {"literalString": "Custom Button Clicked"}, + }], + }, + } + }, + }, + ], + } + }) + + # 8. Tabs + tabs_surface_id = "demo-tabs" + tabs_root_id = "demo-tabs-root" + tab1_id = "tab-1-content" + tab2_id = "tab-2-content" + + messages.append( + {"beginRendering": {"surfaceId": tabs_surface_id, "root": tabs_root_id}} + ) + messages.append({ + "surfaceUpdate": { + "surfaceId": tabs_surface_id, + "components": [ + { + "id": tab1_id, + "component": { + "Text": {"text": {"literalString": "First Tab Content"}} + }, + }, + { + "id": tab2_id, + "component": { + "Text": {"text": {"literalString": "Second Tab Content"}} + }, + }, + { + "id": tabs_root_id, + "component": { + "Tabs": { + "tabItems": [ + { + "title": {"literalString": "View One"}, + "child": tab1_id, + }, + { + "title": {"literalString": "View Two"}, + "child": tab2_id, + }, + ] + } + }, + }, + ], + } + }) + + # 9. Icon + icon_surface_id = "demo-icon" + messages.append( + {"beginRendering": {"surfaceId": icon_surface_id, "root": "icon-root"}} + ) + messages.append({ + "surfaceUpdate": { + "surfaceId": icon_surface_id, + "components": [ + { + "id": "icon-root", + "component": { + "Row": { + "children": {"explicitList": ["icon-1", "icon-2", "icon-3"]}, + "distribution": "spaceEvenly", + "alignment": "center", + } + }, + }, + { + "id": "icon-1", + "component": {"Icon": {"name": {"literalString": "star"}}}, + }, + { + "id": "icon-2", + "component": {"Icon": {"name": {"literalString": "home"}}}, + }, + { + "id": "icon-3", + "component": {"Icon": {"name": {"literalString": "settings"}}}, + }, + ], + } + }) + + # 10. Divider + div_surface_id = "demo-divider" + messages.append({"beginRendering": {"surfaceId": div_surface_id, "root": "div-root"}}) + messages.append({ + "surfaceUpdate": { + "surfaceId": div_surface_id, + "components": [ + { + "id": "div-root", + "component": { + "Column": { + "children": { + "explicitList": [ + "div-text-1", + "div-horiz", + "div-text-2", + ] + }, + "distribution": "start", + "alignment": "stretch", + } + }, + }, + { + "id": "div-text-1", + "component": {"Text": {"text": {"literalString": "Above Divider"}}}, + }, + { + "id": "div-horiz", + "component": {"Divider": {"axis": "horizontal"}}, + }, + { + "id": "div-text-2", + "component": {"Text": {"text": {"literalString": "Below Divider"}}}, + }, + ], + } + }) + + # 11. Card + card_surface_id = "demo-card" + messages.append( + {"beginRendering": {"surfaceId": card_surface_id, "root": "card-root"}} + ) + messages.append({ + "surfaceUpdate": { + "surfaceId": card_surface_id, + "components": [ + {"id": "card-root", "component": {"Card": {"child": "card-text"}}}, + { + "id": "card-text", + "component": { + "Text": {"text": {"literalString": "I am inside a Card"}} + }, + }, + ], + } + }) + + # 12. Video + add_demo_surface( + "demo-video", + { + "Video": { + # Still external as user only provided audio and image + "url": { + "literalString": ( + "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" + ) + } + } + }, + ) + + # 13. Modal + # Modal needs an entry point (Button) and content. + modal_surface_id = "demo-modal" + messages.append( + {"beginRendering": {"surfaceId": modal_surface_id, "root": "modal-root"}} + ) + messages.append({ + "surfaceUpdate": { + "surfaceId": modal_surface_id, + "components": [ + { + "id": "modal-root", + "component": { + "Modal": { + "entryPointChild": "modal-btn", + "contentChild": "modal-content", + } + }, + }, + { + "id": "modal-btn", + "component": { + "Button": { + "child": "modal-btn-text", + "primary": False, + "action": {"name": "noop"}, + } + }, + }, + { + "id": "modal-btn-text", + "component": {"Text": {"text": {"literalString": "Open Modal"}}}, + }, + { + "id": "modal-content", + "component": { + "Text": {"text": {"literalString": "This is the modal content!"}} + }, + }, + ], + } + }) + + # 14. List + list_surface_id = "demo-list" + messages.append( + {"beginRendering": {"surfaceId": list_surface_id, "root": "list-root"}} + ) + messages.append({ + "surfaceUpdate": { + "surfaceId": list_surface_id, + "components": [ + { + "id": "list-root", + "component": { + "List": { + "children": { + "explicitList": [ + "list-item-1", + "list-item-2", + "list-item-3", + ] + }, + "direction": "vertical", + "alignment": "stretch", + } + }, + }, + { + "id": "list-item-1", + "component": {"Text": {"text": {"literalString": "Item 1"}}}, + }, + { + "id": "list-item-2", + "component": {"Text": {"text": {"literalString": "Item 2"}}}, + }, + { + "id": "list-item-3", + "component": {"Text": {"text": {"literalString": "Item 3"}}}, + }, + ], + } + }) + + # 15. AudioPlayer + add_demo_surface( + "demo-audio", + { + "AudioPlayer": { + "url": {"literalString": "http://localhost:10005/assets/audio.mp3"}, + "description": {"literalString": "Local Audio Sample"}, + } + }, + ) + + # Response Surface + messages.append( + {"beginRendering": {"surfaceId": "response-surface", "root": "response-text"}} + ) + messages.append({ + "surfaceUpdate": { + "surfaceId": "response-surface", + "components": [{ + "id": "response-text", + "component": { + "Text": { + "text": { + "literalString": ( + "Interact with the gallery to see responses. This view is" + " updated by the agent by relaying the raw action" + " commands it received from the client" + ) + } + } + }, + }], + } + }) + + return json.dumps(messages, indent=2) diff --git a/samples/agent/adk/contact_lookup/__main__.py b/samples/agent/adk/contact_lookup/__main__.py index 622ce1ae5..69ac07eb0 100644 --- a/samples/agent/adk/contact_lookup/__main__.py +++ b/samples/agent/adk/contact_lookup/__main__.py @@ -32,57 +32,57 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @click.option("--host", default="localhost") @click.option("--port", default=10003) def main(host, port): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." - ) - - base_url = f"http://{host}:{port}" - ui_agent = ContactAgent(base_url=base_url, use_ui=True) - text_agent = ContactAgent(base_url=base_url, use_ui=False) - - agent_executor = ContactAgentExecutor(ui_agent=ui_agent, text_agent=text_agent) - - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." ) - server = A2AStarletteApplication( - agent_card=ui_agent.get_agent_card(), http_handler=request_handler - ) - import uvicorn - app = server.build() + base_url = f"http://{host}:{port}" + ui_agent = ContactAgent(base_url=base_url, use_ui=True) + text_agent = ContactAgent(base_url=base_url, use_ui=False) - app.add_middleware( - CORSMiddleware, - allow_origin_regex=r"http://localhost:\d+", - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) + agent_executor = ContactAgentExecutor(ui_agent=ui_agent, text_agent=text_agent) + + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + server = A2AStarletteApplication( + agent_card=ui_agent.get_agent_card(), http_handler=request_handler + ) + import uvicorn + + app = server.build() + + app.add_middleware( + CORSMiddleware, + allow_origin_regex=r"http://localhost:\d+", + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) - app.mount("/static", StaticFiles(directory="images"), name="static") + app.mount("/static", StaticFiles(directory="images"), name="static") - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e}") - exit(1) - except Exception as e: - logger.error(f"An error occurred during server startup: {e}") - exit(1) + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e}") + exit(1) + except Exception as e: + logger.error(f"An error occurred during server startup: {e}") + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/contact_lookup/agent.py b/samples/agent/adk/contact_lookup/agent.py index b4514232f..2193d0c37 100644 --- a/samples/agent/adk/contact_lookup/agent.py +++ b/samples/agent/adk/contact_lookup/agent.py @@ -49,299 +49,295 @@ class ContactAgent: - """An agent that finds contact info for colleagues.""" - - SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] - - def __init__(self, base_url: str, use_ui: bool = False): - self.base_url = base_url - self.use_ui = use_ui - self._schema_manager = ( - A2uiSchemaManager( - version=VERSION_0_8, - catalogs=[ - BasicCatalog.get_config( - version=VERSION_0_8, examples_path="examples" - ) - ], - ) - if use_ui - else None - ) - self._agent = self._build_agent(use_ui) - self._user_id = "remote_agent" - self._runner = Runner( - app_name=self._agent.name, - agent=self._agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - def get_agent_card(self) -> AgentCard: - capabilities = AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - self._schema_manager.accepts_inline_catalogs, - self._schema_manager.supported_catalog_ids, - ) + """An agent that finds contact info for colleagues.""" + + SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] + + def __init__(self, base_url: str, use_ui: bool = False): + self.base_url = base_url + self.use_ui = use_ui + self._schema_manager = ( + A2uiSchemaManager( + version=VERSION_0_8, + catalogs=[ + BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") ], ) - skill = AgentSkill( - id="find_contact", - name="Find Contact Tool", - description=( - "Helps find contact information for colleagues (e.g., email, location," - " team)." - ), - tags=["contact", "directory", "people", "finder"], - examples=[ - "Who is David Chen in marketing?", - "Find Sarah Lee from engineering", - ], - ) - - return AgentCard( - name="Contact Lookup Agent", - description=( - "This agent helps find contact info for people in your organization." - ), - url=self.base_url, - version="1.0.0", - default_input_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, - capabilities=capabilities, - skills=[skill], + if use_ui + else None + ) + self._agent = self._build_agent(use_ui) + self._user_id = "remote_agent" + self._runner = Runner( + app_name=self._agent.name, + agent=self._agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), + ) + + def get_agent_card(self) -> AgentCard: + capabilities = AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + self._schema_manager.accepts_inline_catalogs, + self._schema_manager.supported_catalog_ids, + ) + ], + ) + skill = AgentSkill( + id="find_contact", + name="Find Contact Tool", + description=( + "Helps find contact information for colleagues (e.g., email, location," + " team)." + ), + tags=["contact", "directory", "people", "finder"], + examples=[ + "Who is David Chen in marketing?", + "Find Sarah Lee from engineering", + ], + ) + + return AgentCard( + name="Contact Lookup Agent", + description=( + "This agent helps find contact info for people in your organization." + ), + url=self.base_url, + version="1.0.0", + default_input_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=ContactAgent.SUPPORTED_CONTENT_TYPES, + capabilities=capabilities, + skills=[skill], + ) + + def get_processing_message(self) -> str: + return "Looking up contact information..." + + def _build_agent(self, use_ui: bool) -> LlmAgent: + """Builds the LLM agent for the contact agent.""" + LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + + instruction = ( + self._schema_manager.generate_system_prompt( + role_description=ROLE_DESCRIPTION, + workflow_description=WORKFLOW_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=False, # Use invalid examples to test retry logic ) - - def get_processing_message(self) -> str: - return "Looking up contact information..." - - def _build_agent(self, use_ui: bool) -> LlmAgent: - """Builds the LLM agent for the contact agent.""" - LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - - instruction = ( - self._schema_manager.generate_system_prompt( - role_description=ROLE_DESCRIPTION, - workflow_description=WORKFLOW_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=False, # Use invalid examples to test retry logic + if use_ui + else get_text_prompt() + ) + + return LlmAgent( + model=LiteLlm(model=LITELLM_MODEL), + name="contact_agent", + description="An agent that finds colleague contact info.", + instruction=instruction, + tools=[get_contact_info], + ) + + async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: + session_state = {"base_url": self.base_url} + + session = await self._runner.session_service.get_session( + app_name=self._agent.name, + user_id=self._user_id, + session_id=session_id, + ) + if session is None: + session = await self._runner.session_service.create_session( + app_name=self._agent.name, + user_id=self._user_id, + state=session_state, + session_id=session_id, + ) + elif "base_url" not in session.state: + session.state["base_url"] = self.base_url + + # --- Begin: UI Validation and Retry Logic --- + max_retries = 1 # Total 2 attempts + attempt = 0 + current_query_text = query + + # Ensure catalog schema was loaded + selected_catalog = self._schema_manager.get_selected_catalog() + if self.use_ui and not selected_catalog.catalog_schema: + logger.error( + "--- ContactAgent.stream: A2UI_SCHEMA is not loaded. " + "Cannot perform UI validation. ---" + ) + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm facing an internal configuration error with" + " my UI components. Please contact support." + ) + ) + ) + ], + } + return + + while attempt <= max_retries: + attempt += 1 + logger.info( + f"--- ContactAgent.stream: Attempt {attempt}/{max_retries + 1} " + f"for session {session_id} ---" + ) + + current_message = types.Content( + role="user", parts=[types.Part.from_text(text=current_query_text)] + ) + final_response_content = None + + async for event in self._runner.run_async( + user_id=self._user_id, + session_id=session.id, + new_message=current_message, + ): + logger.info(f"Event from runner: {event}") + if event.is_final_response(): + if event.content and event.content.parts and event.content.parts[0].text: + final_response_content = "\n".join( + [p.text for p in event.content.parts if p.text] ) - if use_ui - else get_text_prompt() + break # Got the final response, stop consuming events + else: + logger.info(f"Intermediate event: {event}") + # Yield intermediate updates on every attempt + yield { + "is_task_complete": False, + "updates": self.get_processing_message(), + } + + if final_response_content is None: + logger.warning( + "--- ContactAgent.stream: Received no final response content from runner " + f"(Attempt {attempt}). ---" ) - - return LlmAgent( - model=LiteLlm(model=LITELLM_MODEL), - name="contact_agent", - description="An agent that finds colleague contact info.", - instruction=instruction, - tools=[get_contact_info], + if attempt <= max_retries: + current_query_text = ( + "I received no response. Please try again." + f"Please retry the original request: '{query}'" + ) + continue # Go to next retry + else: + # Retries exhausted on no-response + final_response_content = ( + "I'm sorry, I encountered an error and couldn't process your request." + ) + # Fall through to send this as a text-only error + + is_valid = False + error_message = "" + + if self.use_ui: + logger.info( + "--- ContactAgent.stream: Validating UI response (Attempt" + f" {attempt})... ---" ) - - async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: - session_state = {"base_url": self.base_url} - - session = await self._runner.session_service.get_session( - app_name=self._agent.name, - user_id=self._user_id, - session_id=session_id, + try: + response_parts = parse_response(final_response_content) + + for part in response_parts: + if not part.a2ui_json: + continue + + parsed_json_data = part.a2ui_json + + # Handle the "no results found" or empty JSON case + if parsed_json_data == []: + logger.info( + "--- ContactAgent.stream: Empty JSON list found. " + "Assuming valid (e.g., 'no results'). ---" + ) + is_valid = True + else: + # --- Validation Steps --- + # Check if it validates against the A2UI_SCHEMA + # This will raise jsonschema.exceptions.ValidationError if it fails + logger.info( + "--- ContactAgent.stream: Validating against A2UI_SCHEMA... ---" + ) + selected_catalog.validator.validate(parsed_json_data) + # --- End Validation Steps --- + + logger.info( + "--- ContactAgent.stream: UI JSON successfully parsed AND validated" + f" against schema. Validation OK (Attempt {attempt}). ---" + ) + is_valid = True + except ( + ValueError, + json.JSONDecodeError, + jsonschema.exceptions.ValidationError, + ) as e: + logger.warning( + f"--- ContactAgent.stream: A2UI validation failed: {e} (Attempt" + f" {attempt}) ---" + ) + logger.warning( + f"--- Failed response content: {final_response_content[:500]}... ---" + ) + error_message = f"Validation failed: {e}." + + else: # Not using UI, so text is always "valid" + is_valid = True + + if is_valid: + logger.info( + "--- ContactAgent.stream: Response is valid. Sending final response" + f" (Attempt {attempt}). ---" + ) + final_parts = parse_response_to_parts( + final_response_content, fallback_text="OK." ) - if session is None: - session = await self._runner.session_service.create_session( - app_name=self._agent.name, - user_id=self._user_id, - state=session_state, - session_id=session_id, - ) - elif "base_url" not in session.state: - session.state["base_url"] = self.base_url - - # --- Begin: UI Validation and Retry Logic --- - max_retries = 1 # Total 2 attempts - attempt = 0 - current_query_text = query - - # Ensure catalog schema was loaded - selected_catalog = self._schema_manager.get_selected_catalog() - if self.use_ui and not selected_catalog.catalog_schema: - logger.error( - "--- ContactAgent.stream: A2UI_SCHEMA is not loaded. " - "Cannot perform UI validation. ---" - ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm facing an internal configuration error with" - " my UI components. Please contact support." - ) - ) - ) - ], - } - return - - while attempt <= max_retries: - attempt += 1 - logger.info( - f"--- ContactAgent.stream: Attempt {attempt}/{max_retries + 1} " - f"for session {session_id} ---" - ) - - current_message = types.Content( - role="user", parts=[types.Part.from_text(text=current_query_text)] - ) - final_response_content = None - - async for event in self._runner.run_async( - user_id=self._user_id, - session_id=session.id, - new_message=current_message, - ): - logger.info(f"Event from runner: {event}") - if event.is_final_response(): - if ( - event.content - and event.content.parts - and event.content.parts[0].text - ): - final_response_content = "\n".join( - [p.text for p in event.content.parts if p.text] - ) - break # Got the final response, stop consuming events - else: - logger.info(f"Intermediate event: {event}") - # Yield intermediate updates on every attempt - yield { - "is_task_complete": False, - "updates": self.get_processing_message(), - } - - if final_response_content is None: - logger.warning( - "--- ContactAgent.stream: Received no final response content from runner " - f"(Attempt {attempt}). ---" - ) - if attempt <= max_retries: - current_query_text = ( - "I received no response. Please try again." - f"Please retry the original request: '{query}'" - ) - continue # Go to next retry - else: - # Retries exhausted on no-response - final_response_content = "I'm sorry, I encountered an error and couldn't process your request." - # Fall through to send this as a text-only error - - is_valid = False - error_message = "" - - if self.use_ui: - logger.info( - "--- ContactAgent.stream: Validating UI response (Attempt" - f" {attempt})... ---" - ) - try: - response_parts = parse_response(final_response_content) - - for part in response_parts: - if not part.a2ui_json: - continue - - parsed_json_data = part.a2ui_json - - # Handle the "no results found" or empty JSON case - if parsed_json_data == []: - logger.info( - "--- ContactAgent.stream: Empty JSON list found. " - "Assuming valid (e.g., 'no results'). ---" - ) - is_valid = True - else: - # --- Validation Steps --- - # Check if it validates against the A2UI_SCHEMA - # This will raise jsonschema.exceptions.ValidationError if it fails - logger.info( - "--- ContactAgent.stream: Validating against A2UI_SCHEMA... ---" - ) - selected_catalog.validator.validate(parsed_json_data) - # --- End Validation Steps --- - - logger.info( - "--- ContactAgent.stream: UI JSON successfully parsed AND validated" - f" against schema. Validation OK (Attempt {attempt}). ---" - ) - is_valid = True - except ( - ValueError, - json.JSONDecodeError, - jsonschema.exceptions.ValidationError, - ) as e: - logger.warning( - f"--- ContactAgent.stream: A2UI validation failed: {e} (Attempt" - f" {attempt}) ---" - ) - logger.warning( - f"--- Failed response content: {final_response_content[:500]}... ---" - ) - error_message = f"Validation failed: {e}." - - else: # Not using UI, so text is always "valid" - is_valid = True - - if is_valid: - logger.info( - "--- ContactAgent.stream: Response is valid. Sending final response" - f" (Attempt {attempt}). ---" - ) - final_parts = parse_response_to_parts( - final_response_content, fallback_text="OK." - ) - - yield { - "is_task_complete": True, - "parts": final_parts, - } - return # We're done, exit the generator - # --- If we're here, it means validation failed --- + yield { + "is_task_complete": True, + "parts": final_parts, + } + return # We're done, exit the generator - if attempt <= max_retries: - logger.warning( - f"--- ContactAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" - ) - # Prepare the query for the retry - current_query_text = ( - f"Your previous response was invalid. {error_message} You MUST generate a" - " valid response that strictly follows the A2UI JSON SCHEMA. The response" - " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" - f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" - f" original request: '{query}'" - ) - # Loop continues... + # --- If we're here, it means validation failed --- - # --- If we're here, it means we've exhausted retries --- - logger.error( - "--- ContactAgent.stream: Max retries exhausted. Sending text-only error. ---" + if attempt <= max_retries: + logger.warning( + f"--- ContactAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm having trouble generating the interface for" - " that request right now. Please try again in a moment." - ) + # Prepare the query for the retry + current_query_text = ( + f"Your previous response was invalid. {error_message} You MUST generate a" + " valid response that strictly follows the A2UI JSON SCHEMA. The response" + " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" + f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" + f" original request: '{query}'" + ) + # Loop continues... + + # --- If we're here, it means we've exhausted retries --- + logger.error( + "--- ContactAgent.stream: Max retries exhausted. Sending text-only error. ---" + ) + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm having trouble generating the interface for" + " that request right now. Please try again in a moment." ) ) - ], - } - # --- End: UI Validation and Retry Logic --- + ) + ], + } + # --- End: UI Validation and Retry Logic --- diff --git a/samples/agent/adk/contact_lookup/agent_executor.py b/samples/agent/adk/contact_lookup/agent_executor.py index 245dbf123..f4e49aea5 100644 --- a/samples/agent/adk/contact_lookup/agent_executor.py +++ b/samples/agent/adk/contact_lookup/agent_executor.py @@ -38,131 +38,127 @@ class ContactAgentExecutor(AgentExecutor): - """Contact AgentExecutor Example.""" - - def __init__(self, ui_agent: ContactAgent, text_agent: ContactAgent): - # Instantiate two agents: one for UI and one for text-only. - # The appropriate one will be chosen at execution time. - self.ui_agent = ui_agent - self.text_agent = text_agent - - async def execute( - self, - context: RequestContext, - event_queue: EventQueue, - ) -> None: - query = "" - ui_event_part = None - action = None - - logger.info( - f"--- Client requested extensions: {context.requested_extensions} ---" - ) - use_ui = try_activate_a2ui_extension(context) - - # Determine which agent to use based on whether the a2ui extension is active. - if use_ui: - agent = self.ui_agent - logger.info( - "--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---" - ) - else: - agent = self.text_agent - logger.info( - "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" - ) - - if context.message and context.message.parts: - logger.info( - f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" - " parts ---" - ) - for i, part in enumerate(context.message.parts): - if isinstance(part.root, DataPart): - if "userAction" in part.root.data: - logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") - ui_event_part = part.root.data["userAction"] - else: - logger.info(f" Part {i}: DataPart (data: {part.root.data})") - elif isinstance(part.root, TextPart): - logger.info(f" Part {i}: TextPart (text: {part.root.text})") - else: - logger.info(f" Part {i}: Unknown part type ({type(part.root)})") - - if ui_event_part: - logger.info(f"Received a2ui ClientEvent: {ui_event_part}") - # Fix: Check both 'actionName' and 'name' - action = ui_event_part.get("name") - ctx = ui_event_part.get("context", {}) - - if action == "view_profile": - contact_name = ctx.get("contactName", "Unknown") - department = ctx.get("department", "") - query = f"WHO_IS: {contact_name} from {department}" - - elif action == "send_email": - contact_name = ctx.get("contactName", "Unknown") - email = ctx.get("email", "Unknown") - query = f"USER_WANTS_TO_EMAIL: {contact_name} at {email}" - - elif action == "send_message": - contact_name = ctx.get("contactName", "Unknown") - query = f"USER_WANTS_TO_MESSAGE: {contact_name}" - - elif action == "follow_contact": - query = "ACTION: follow_contact" - - elif action == "view_full_profile": - contact_name = ctx.get("contactName", "Unknown") - query = f"USER_WANTS_FULL_PROFILE: {contact_name}" - - else: - query = f"User submitted an event: {action} with data: {ctx}" + """Contact AgentExecutor Example.""" + + def __init__(self, ui_agent: ContactAgent, text_agent: ContactAgent): + # Instantiate two agents: one for UI and one for text-only. + # The appropriate one will be chosen at execution time. + self.ui_agent = ui_agent + self.text_agent = text_agent + + async def execute( + self, + context: RequestContext, + event_queue: EventQueue, + ) -> None: + query = "" + ui_event_part = None + action = None + + logger.info(f"--- Client requested extensions: {context.requested_extensions} ---") + use_ui = try_activate_a2ui_extension(context) + + # Determine which agent to use based on whether the a2ui extension is active. + if use_ui: + agent = self.ui_agent + logger.info("--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---") + else: + agent = self.text_agent + logger.info( + "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" + ) + + if context.message and context.message.parts: + logger.info( + f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" + " parts ---" + ) + for i, part in enumerate(context.message.parts): + if isinstance(part.root, DataPart): + if "userAction" in part.root.data: + logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") + ui_event_part = part.root.data["userAction"] + else: + logger.info(f" Part {i}: DataPart (data: {part.root.data})") + elif isinstance(part.root, TextPart): + logger.info(f" Part {i}: TextPart (text: {part.root.text})") else: - logger.info("No a2ui UI event part found. Falling back to text input.") - query = context.get_user_input() - - logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") - - task = context.current_task - - if not task: - task = new_task(context.message) - await event_queue.enqueue_event(task) - updater = TaskUpdater(event_queue, task.id, task.context_id) - - async for item in agent.stream(query, task.context_id): - is_task_complete = item["is_task_complete"] - if not is_task_complete: - await updater.update_status( - TaskState.working, - new_agent_text_message(item["updates"], task.context_id, task.id), - ) - continue - - final_state = TaskState.input_required # Default - if action in ["send_email", "send_message", "view_full_profile"]: - final_state = TaskState.completed - - final_parts = item["parts"] - - logger.info("--- FINAL PARTS TO BE SENT ---") - for i, part in enumerate(final_parts): - logger.info(f" - Part {i}: Type = {type(part.root)}") - if isinstance(part.root, TextPart): - logger.info(f" - Text: {part.root.text[:200]}...") - elif isinstance(part.root, DataPart): - logger.info(f" - Data: {str(part.root.data)[:200]}...") - logger.info("-----------------------------") - - await updater.update_status( - final_state, - new_agent_parts_message(final_parts, task.context_id, task.id), - final=(final_state == TaskState.completed), - ) - break - - async def cancel( - self, request: RequestContext, event_queue: EventQueue - ) -> Task | None: - raise ServerError(error=UnsupportedOperationError()) + logger.info(f" Part {i}: Unknown part type ({type(part.root)})") + + if ui_event_part: + logger.info(f"Received a2ui ClientEvent: {ui_event_part}") + # Fix: Check both 'actionName' and 'name' + action = ui_event_part.get("name") + ctx = ui_event_part.get("context", {}) + + if action == "view_profile": + contact_name = ctx.get("contactName", "Unknown") + department = ctx.get("department", "") + query = f"WHO_IS: {contact_name} from {department}" + + elif action == "send_email": + contact_name = ctx.get("contactName", "Unknown") + email = ctx.get("email", "Unknown") + query = f"USER_WANTS_TO_EMAIL: {contact_name} at {email}" + + elif action == "send_message": + contact_name = ctx.get("contactName", "Unknown") + query = f"USER_WANTS_TO_MESSAGE: {contact_name}" + + elif action == "follow_contact": + query = "ACTION: follow_contact" + + elif action == "view_full_profile": + contact_name = ctx.get("contactName", "Unknown") + query = f"USER_WANTS_FULL_PROFILE: {contact_name}" + + else: + query = f"User submitted an event: {action} with data: {ctx}" + else: + logger.info("No a2ui UI event part found. Falling back to text input.") + query = context.get_user_input() + + logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") + + task = context.current_task + + if not task: + task = new_task(context.message) + await event_queue.enqueue_event(task) + updater = TaskUpdater(event_queue, task.id, task.context_id) + + async for item in agent.stream(query, task.context_id): + is_task_complete = item["is_task_complete"] + if not is_task_complete: + await updater.update_status( + TaskState.working, + new_agent_text_message(item["updates"], task.context_id, task.id), + ) + continue + + final_state = TaskState.input_required # Default + if action in ["send_email", "send_message", "view_full_profile"]: + final_state = TaskState.completed + + final_parts = item["parts"] + + logger.info("--- FINAL PARTS TO BE SENT ---") + for i, part in enumerate(final_parts): + logger.info(f" - Part {i}: Type = {type(part.root)}") + if isinstance(part.root, TextPart): + logger.info(f" - Text: {part.root.text[:200]}...") + elif isinstance(part.root, DataPart): + logger.info(f" - Data: {str(part.root.data)[:200]}...") + logger.info("-----------------------------") + + await updater.update_status( + final_state, + new_agent_parts_message(final_parts, task.context_id, task.id), + final=(final_state == TaskState.completed), + ) + break + + async def cancel( + self, request: RequestContext, event_queue: EventQueue + ) -> Task | None: + raise ServerError(error=UnsupportedOperationError()) diff --git a/samples/agent/adk/contact_lookup/prompt_builder.py b/samples/agent/adk/contact_lookup/prompt_builder.py index 63128161f..8fc94b641 100644 --- a/samples/agent/adk/contact_lookup/prompt_builder.py +++ b/samples/agent/adk/contact_lookup/prompt_builder.py @@ -44,10 +44,10 @@ def get_text_prompt() -> str: - """ - Constructs the prompt for a text-only agent. - """ - return """ + """ + Constructs the prompt for a text-only agent. + """ + return """ You are a helpful contact lookup assistant. Your final output MUST be a text response. To generate the response, you MUST follow these rules: @@ -63,21 +63,19 @@ def get_text_prompt() -> str: if __name__ == "__main__": - # Example of how to use the A2UI Schema Manager to generate a system prompt - contact_prompt = A2uiSchemaManager( - VERSION_0_8, - catalogs=[ - BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") - ], - ).generate_system_prompt( - role_description=ROLE_DESCRIPTION, - workflow_description=WORKFLOW_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=False, - ) - print(contact_prompt) - with open("generated_prompt.txt", "w") as f: - f.write(contact_prompt) - print("\nGenerated prompt saved to generated_prompt.txt") + # Example of how to use the A2UI Schema Manager to generate a system prompt + contact_prompt = A2uiSchemaManager( + VERSION_0_8, + catalogs=[BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples")], + ).generate_system_prompt( + role_description=ROLE_DESCRIPTION, + workflow_description=WORKFLOW_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=False, + ) + print(contact_prompt) + with open("generated_prompt.txt", "w") as f: + f.write(contact_prompt) + print("\nGenerated prompt saved to generated_prompt.txt") diff --git a/samples/agent/adk/contact_lookup/tools.py b/samples/agent/adk/contact_lookup/tools.py index de8e38748..3bf8989eb 100644 --- a/samples/agent/adk/contact_lookup/tools.py +++ b/samples/agent/adk/contact_lookup/tools.py @@ -22,49 +22,45 @@ def get_contact_info(name: str, tool_context: ToolContext, department: str = "") -> str: - """Call this tool to get a list of contacts based on a name and optional department. - 'name' is the person's name to search for. - 'department' is the optional department to filter by. - """ - logger.info("--- TOOL CALLED: get_contact_info ---") - logger.info(f" - Name: {name}") - logger.info(f" - Department: {department}") + """Call this tool to get a list of contacts based on a name and optional department. + 'name' is the person's name to search for. + 'department' is the optional department to filter by. + """ + logger.info("--- TOOL CALLED: get_contact_info ---") + logger.info(f" - Name: {name}") + logger.info(f" - Department: {department}") - results = [] - try: - script_dir = os.path.dirname(__file__) - file_path = os.path.join(script_dir, "contact_data.json") - with open(file_path) as f: - contact_data_str = f.read() - if base_url := tool_context.state.get("base_url"): - contact_data_str = contact_data_str.replace( - "http://localhost:10002", base_url - ) - logger.info(f"Updated base URL from tool context: {base_url}") - all_contacts = json.loads(contact_data_str) + results = [] + try: + script_dir = os.path.dirname(__file__) + file_path = os.path.join(script_dir, "contact_data.json") + with open(file_path) as f: + contact_data_str = f.read() + if base_url := tool_context.state.get("base_url"): + contact_data_str = contact_data_str.replace("http://localhost:10002", base_url) + logger.info(f"Updated base URL from tool context: {base_url}") + all_contacts = json.loads(contact_data_str) - name_lower = name.lower() + name_lower = name.lower() - dept_lower = department.lower() if department else "" + dept_lower = department.lower() if department else "" - # Filter by name - results = [ - contact for contact in all_contacts if name_lower in contact["name"].lower() - ] + # Filter by name + results = [ + contact for contact in all_contacts if name_lower in contact["name"].lower() + ] - # If department is provided, filter results further - if dept_lower: - results = [ - contact - for contact in results - if dept_lower in contact["department"].lower() - ] + # If department is provided, filter results further + if dept_lower: + results = [ + contact for contact in results if dept_lower in contact["department"].lower() + ] - logger.info(f" - Success: Found {len(results)} matching contacts.") + logger.info(f" - Success: Found {len(results)} matching contacts.") - except FileNotFoundError: - logger.error(f" - Error: contact_data.json not found at {file_path}") - except json.JSONDecodeError: - logger.error(f" - Error: Failed to decode JSON from {file_path}") + except FileNotFoundError: + logger.error(f" - Error: contact_data.json not found at {file_path}") + except json.JSONDecodeError: + logger.error(f" - Error: Failed to decode JSON from {file_path}") - return json.dumps(results) + return json.dumps(results) diff --git a/samples/agent/adk/orchestrator/__main__.py b/samples/agent/adk/orchestrator/__main__.py index a0af560fb..f7fa23cb9 100644 --- a/samples/agent/adk/orchestrator/__main__.py +++ b/samples/agent/adk/orchestrator/__main__.py @@ -32,7 +32,7 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @@ -40,53 +40,51 @@ class MissingAPIKeyError(Exception): @click.option("--port", default=10002, type=int) @click.option("--subagent_urls", multiple=True, type=str, required=True) def main(host, port, subagent_urls): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." - ) + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." + ) - base_url = f"http://{host}:{port}" + base_url = f"http://{host}:{port}" - orchestrator_agent, agent_card = asyncio.run( - OrchestratorAgent.build_agent( - base_url=base_url, subagent_urls=subagent_urls - ) - ) - agent_executor = OrchestratorAgentExecutor(agent=orchestrator_agent) + orchestrator_agent, agent_card = asyncio.run( + OrchestratorAgent.build_agent(base_url=base_url, subagent_urls=subagent_urls) + ) + agent_executor = OrchestratorAgentExecutor(agent=orchestrator_agent) - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - server = A2AStarletteApplication( - agent_card=agent_card, http_handler=request_handler - ) - import uvicorn + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + server = A2AStarletteApplication( + agent_card=agent_card, http_handler=request_handler + ) + import uvicorn - app = server.build() + app = server.build() - app.add_middleware( - CORSMiddleware, - allow_origins=["http://localhost:5173"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) + app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:5173"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e} {traceback.format_exc()}") - exit(1) - except Exception as e: - logger.error( - f"An error occurred during server startup: {e} {traceback.format_exc()}" - ) - exit(1) + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e} {traceback.format_exc()}") + exit(1) + except Exception as e: + logger.error( + f"An error occurred during server startup: {e} {traceback.format_exc()}" + ) + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/orchestrator/agent.py b/samples/agent/adk/orchestrator/agent.py index 7687db46c..383dbcdfb 100644 --- a/samples/agent/adk/orchestrator/agent.py +++ b/samples/agent/adk/orchestrator/agent.py @@ -45,227 +45,222 @@ class A2UIMetadataInterceptor(ClientCallInterceptor): - @override - async def intercept( - self, - method_name: str, - request_payload: dict[str, Any], - http_kwargs: dict[str, Any], - agent_card: AgentCard | None, - context: ClientCallContext | None, - ) -> tuple[dict[str, Any], dict[str, Any]]: - """Enables the A2UI extension header and adds A2UI client capabilities to remote agent message metadata.""" - logger.info( - "Intercepting client call to method: " - + method_name - + " and payload " - + json.dumps(request_payload) - ) + @override + async def intercept( + self, + method_name: str, + request_payload: dict[str, Any], + http_kwargs: dict[str, Any], + agent_card: AgentCard | None, + context: ClientCallContext | None, + ) -> tuple[dict[str, Any], dict[str, Any]]: + """Enables the A2UI extension header and adds A2UI client capabilities to remote agent message metadata.""" + logger.info( + "Intercepting client call to method: " + + method_name + + " and payload " + + json.dumps(request_payload) + ) - if context and context.state and context.state.get("use_ui"): - # Add A2UI extension header - http_kwargs["headers"] = {HTTP_EXTENSION_HEADER: A2UI_EXTENSION_URI} + if context and context.state and context.state.get("use_ui"): + # Add A2UI extension header + http_kwargs["headers"] = {HTTP_EXTENSION_HEADER: A2UI_EXTENSION_URI} - # Add A2UI client capabilities (supported catalogs, etc) to message metadata - if (params := request_payload.get("params")) and ( - message := params.get("message") - ): - client_capabilities = context.state.get("client_capabilities") - if "metadata" not in message: - message["metadata"] = {} - message["metadata"][A2UI_CLIENT_CAPABILITIES_KEY] = client_capabilities - logger.info( - "Added client capabilities to remote agent message metadata:" - f" {client_capabilities}" - ) + # Add A2UI client capabilities (supported catalogs, etc) to message metadata + if (params := request_payload.get("params")) and ( + message := params.get("message") + ): + client_capabilities = context.state.get("client_capabilities") + if "metadata" not in message: + message["metadata"] = {} + message["metadata"][A2UI_CLIENT_CAPABILITIES_KEY] = client_capabilities + logger.info( + "Added client capabilities to remote agent message metadata:" + f" {client_capabilities}" + ) - return request_payload, http_kwargs + return request_payload, http_kwargs class A2AClientFactoryWithA2UIMetadata(A2AClientFactory): - @override - def create( - self, - card: AgentCard, - consumers: list[Consumer] | None = None, - interceptors: list[ClientCallInterceptor] | None = None, - ) -> Client: - # Add A2UI metadata interceptor - return super().create( - card, consumers, (interceptors or []) + [A2UIMetadataInterceptor()] - ) + @override + def create( + self, + card: AgentCard, + consumers: list[Consumer] | None = None, + interceptors: list[ClientCallInterceptor] | None = None, + ) -> Client: + # Add A2UI metadata interceptor + return super().create( + card, consumers, (interceptors or []) + [A2UIMetadataInterceptor()] + ) class OrchestratorAgent: - """An agent that runs an ecommerce dashboard""" + """An agent that runs an ecommerce dashboard""" - SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] + SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] - @classmethod - async def programmtically_route_user_action_to_subagent( - cls, - callback_context: CallbackContext, - llm_request: LlmRequest, - ) -> LlmResponse: - if ( - llm_request.contents - and (last_content := llm_request.contents[-1]).parts - and ( - a2a_part := part_converters.convert_genai_part_to_a2a_part( - last_content.parts[-1] - ) - ) - and is_a2ui_part(a2a_part) - and (user_action := a2a_part.root.data.get("userAction")) - and (surface_id := user_action.get("surfaceId")) - and ( - target_agent := await SubagentRouteManager.get_route_to_subagent_name( - surface_id, callback_context.state - ) + @classmethod + async def programmtically_route_user_action_to_subagent( + cls, + callback_context: CallbackContext, + llm_request: LlmRequest, + ) -> LlmResponse: + if ( + llm_request.contents + and (last_content := llm_request.contents[-1]).parts + and ( + a2a_part := part_converters.convert_genai_part_to_a2a_part( + last_content.parts[-1] ) - ): - logger.info( - f"Programmatically routing userAction for surfaceId '{surface_id}' to" - f" subagent '{target_agent}'" - ) - return LlmResponse( - content=genai_types.Content( - parts=[ - genai_types.Part( - function_call=genai_types.FunctionCall( - name="transfer_to_agent", - args={"agent_name": target_agent}, - ) - ) - ] - ) + ) + and is_a2ui_part(a2a_part) + and (user_action := a2a_part.root.data.get("userAction")) + and (surface_id := user_action.get("surfaceId")) + and ( + target_agent := await SubagentRouteManager.get_route_to_subagent_name( + surface_id, callback_context.state ) + ) + ): + logger.info( + f"Programmatically routing userAction for surfaceId '{surface_id}' to" + f" subagent '{target_agent}'" + ) + return LlmResponse( + content=genai_types.Content( + parts=[ + genai_types.Part( + function_call=genai_types.FunctionCall( + name="transfer_to_agent", + args={"agent_name": target_agent}, + ) + ) + ] + ) + ) - return None + return None - @classmethod - async def build_agent( - cls, base_url: str, subagent_urls: List[str] - ) -> (LlmAgent, AgentCard): - """Builds the LLM agent for the orchestrator_agent agent.""" + @classmethod + async def build_agent( + cls, base_url: str, subagent_urls: List[str] + ) -> (LlmAgent, AgentCard): + """Builds the LLM agent for the orchestrator_agent agent.""" - subagents = [] - supported_catalog_ids = set() - skills = [] - accepts_inline_catalogs = False - for subagent_url in subagent_urls: - async with httpx.AsyncClient() as httpx_client: - resolver = A2ACardResolver( - httpx_client=httpx_client, - base_url=subagent_url, - ) + subagents = [] + supported_catalog_ids = set() + skills = [] + accepts_inline_catalogs = False + for subagent_url in subagent_urls: + async with httpx.AsyncClient() as httpx_client: + resolver = A2ACardResolver( + httpx_client=httpx_client, + base_url=subagent_url, + ) - subagent_card = await resolver.get_agent_card() - for extension in subagent_card.capabilities.extensions or []: - if extension.uri == A2UI_EXTENSION_URI and extension.params: - supported_catalog_ids.update( - extension.params.get( - AGENT_EXTENSION_SUPPORTED_CATALOG_IDS_KEY - ) - or [] - ) - accepts_inline_catalogs |= bool( - extension.params.get( - AGENT_EXTENSION_ACCEPTS_INLINE_CATALOGS_KEY - ) - ) + subagent_card = await resolver.get_agent_card() + for extension in subagent_card.capabilities.extensions or []: + if extension.uri == A2UI_EXTENSION_URI and extension.params: + supported_catalog_ids.update( + extension.params.get(AGENT_EXTENSION_SUPPORTED_CATALOG_IDS_KEY) or [] + ) + accepts_inline_catalogs |= bool( + extension.params.get(AGENT_EXTENSION_ACCEPTS_INLINE_CATALOGS_KEY) + ) - skills.extend(subagent_card.skills) + skills.extend(subagent_card.skills) - logger.info( - "Successfully fetched public agent card:" - + subagent_card.model_dump_json(indent=2, exclude_none=True) - ) + logger.info( + "Successfully fetched public agent card:" + + subagent_card.model_dump_json(indent=2, exclude_none=True) + ) - # clean name for adk - clean_name = re.sub(r"[^0-9a-zA-Z_]+", "_", subagent_card.name) - if clean_name == "": - clean_name = "_" - if clean_name[0].isdigit(): - clean_name = f"_{clean_name}" + # clean name for adk + clean_name = re.sub(r"[^0-9a-zA-Z_]+", "_", subagent_card.name) + if clean_name == "": + clean_name = "_" + if clean_name[0].isdigit(): + clean_name = f"_{clean_name}" - # make remote agent - description = json.dumps( + # make remote agent + description = json.dumps( + { + "id": clean_name, + "name": subagent_card.name, + "description": subagent_card.description, + "skills": [ { - "id": clean_name, - "name": subagent_card.name, - "description": subagent_card.description, - "skills": [ - { - "name": skill.name, - "description": skill.description, - "examples": skill.examples, - "tags": skill.tags, - } - for skill in subagent_card.skills - ], - }, - indent=2, - ) - remote_a2a_agent = RemoteA2aAgent( - clean_name, - subagent_card, - description=description, # This will be appended to system instructions - a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, - genai_part_converter=part_converters.convert_genai_part_to_a2a_part, - a2a_client_factory=A2AClientFactoryWithA2UIMetadata( - config=A2AClientConfig( - httpx_client=httpx.AsyncClient( - timeout=httpx.Timeout(timeout=DEFAULT_TIMEOUT), - ), - streaming=False, - polling=False, - supported_transports=[A2ATransport.jsonrpc], - ) + "name": skill.name, + "description": skill.description, + "examples": skill.examples, + "tags": skill.tags, + } + for skill in subagent_card.skills + ], + }, + indent=2, + ) + remote_a2a_agent = RemoteA2aAgent( + clean_name, + subagent_card, + description=description, # This will be appended to system instructions + a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, + genai_part_converter=part_converters.convert_genai_part_to_a2a_part, + a2a_client_factory=A2AClientFactoryWithA2UIMetadata( + config=A2AClientConfig( + httpx_client=httpx.AsyncClient( + timeout=httpx.Timeout(timeout=DEFAULT_TIMEOUT), ), + streaming=False, + polling=False, + supported_transports=[A2ATransport.jsonrpc], ) - subagents.append(remote_a2a_agent) - - logger.info(f"Created remote agent with description: {description}") - - LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - agent = LlmAgent( - model=LiteLlm(model=LITELLM_MODEL), - name="orchestrator_agent", - description="An agent that orchestrates requests to multiple other agents", - instruction=( - "You are an orchestrator agent. Your sole responsibility is to analyze the" - " incoming user request, determine the user's intent, and route the task to" - " exactly one of your expert subagents" ), - tools=[], - planner=BuiltInPlanner( - thinking_config=genai_types.ThinkingConfig( - include_thoughts=True, - ) - ), - sub_agents=subagents, - before_model_callback=cls.programmtically_route_user_action_to_subagent, ) + subagents.append(remote_a2a_agent) - agent_card = AgentCard( - name="Orchestrator Agent", - description="This agent orchestrates requests to multiple subagents.", - url=base_url, - version="1.0.0", - default_input_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, - capabilities=AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - accepts_inline_catalogs=accepts_inline_catalogs, - supported_catalog_ids=list(supported_catalog_ids), - ) - ], - ), - skills=skills, - ) + logger.info(f"Created remote agent with description: {description}") + + LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + agent = LlmAgent( + model=LiteLlm(model=LITELLM_MODEL), + name="orchestrator_agent", + description="An agent that orchestrates requests to multiple other agents", + instruction=( + "You are an orchestrator agent. Your sole responsibility is to analyze the" + " incoming user request, determine the user's intent, and route the task to" + " exactly one of your expert subagents" + ), + tools=[], + planner=BuiltInPlanner( + thinking_config=genai_types.ThinkingConfig( + include_thoughts=True, + ) + ), + sub_agents=subagents, + before_model_callback=cls.programmtically_route_user_action_to_subagent, + ) + + agent_card = AgentCard( + name="Orchestrator Agent", + description="This agent orchestrates requests to multiple subagents.", + url=base_url, + version="1.0.0", + default_input_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=OrchestratorAgent.SUPPORTED_CONTENT_TYPES, + capabilities=AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + accepts_inline_catalogs=accepts_inline_catalogs, + supported_catalog_ids=list(supported_catalog_ids), + ) + ], + ), + skills=skills, + ) - return agent, agent_card + return agent, agent_card diff --git a/samples/agent/adk/orchestrator/agent_executor.py b/samples/agent/adk/orchestrator/agent_executor.py index d9c62b4be..f2a3a29f2 100644 --- a/samples/agent/adk/orchestrator/agent_executor.py +++ b/samples/agent/adk/orchestrator/agent_executor.py @@ -47,113 +47,113 @@ class OrchestratorAgentExecutor(A2aAgentExecutor): - """Contact AgentExecutor Example.""" - - def __init__(self, agent: LlmAgent): - config = A2aAgentExecutorConfig( - gen_ai_part_converter=part_converters.convert_genai_part_to_a2a_part, - a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, - event_converter=self.convert_event_to_a2a_events_and_save_surface_id_to_subagent_name, - ) - - runner = Runner( - app_name=agent.name, - agent=agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - super().__init__(runner=runner, config=config) - - @classmethod - def convert_event_to_a2a_events_and_save_surface_id_to_subagent_name( - cls, - event: Event, - invocation_context: InvocationContext, - task_id: Optional[str] = None, - context_id: Optional[str] = None, - part_converter: part_converter.GenAIPartToA2APartConverter = part_converter.convert_genai_part_to_a2a_part, - ) -> List[A2AEvent]: - a2a_events = event_converter.convert_event_to_a2a_events( - event, - invocation_context, - task_id, - context_id, - part_converter, - ) - - for a2a_event in a2a_events: - # Try to populate subagent agent card if available. - subagent_card = None - if active_subagent_name := event.author: - # We need to find the subagent by name - if subagent := next( - ( - sub - for sub in invocation_context.agent.sub_agents - if sub.name == active_subagent_name - ), - None, - ): - try: - subagent_card = json.loads(subagent.description) - except Exception: - logger.warning( - f"Failed to parse agent description for {active_subagent_name}" - ) - if subagent_card: - if a2a_event.metadata is None: - a2a_event.metadata = {} - a2a_event.metadata["a2a_subagent"] = subagent_card - - for a2a_part in a2a_event.status.message.parts: - if ( - is_a2ui_part(a2a_part) - and (begin_rendering := a2a_part.root.data.get("beginRendering")) - and (surface_id := begin_rendering.get("surfaceId")) - ): - asyncio.run_coroutine_threadsafe( - SubagentRouteManager.set_route_to_subagent_name( - surface_id, - event.author, - invocation_context.session_service, - invocation_context.session, - ), - asyncio.get_event_loop(), - ) - - return a2a_events - - @override - async def _prepare_session( - self, - context: RequestContext, - run_request: AgentRunRequest, - runner: Runner, - ): - session = await super()._prepare_session(context, run_request, runner) - - if try_activate_a2ui_extension(context): - client_capabilities = ( - context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) - if context.message and context.message.metadata - else None + """Contact AgentExecutor Example.""" + + def __init__(self, agent: LlmAgent): + config = A2aAgentExecutorConfig( + gen_ai_part_converter=part_converters.convert_genai_part_to_a2a_part, + a2a_part_converter=part_converters.convert_a2a_part_to_genai_part, + event_converter=self.convert_event_to_a2a_events_and_save_surface_id_to_subagent_name, + ) + + runner = Runner( + app_name=agent.name, + agent=agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), + ) + + super().__init__(runner=runner, config=config) + + @classmethod + def convert_event_to_a2a_events_and_save_surface_id_to_subagent_name( + cls, + event: Event, + invocation_context: InvocationContext, + task_id: Optional[str] = None, + context_id: Optional[str] = None, + part_converter: part_converter.GenAIPartToA2APartConverter = part_converter.convert_genai_part_to_a2a_part, + ) -> List[A2AEvent]: + a2a_events = event_converter.convert_event_to_a2a_events( + event, + invocation_context, + task_id, + context_id, + part_converter, + ) + + for a2a_event in a2a_events: + # Try to populate subagent agent card if available. + subagent_card = None + if active_subagent_name := event.author: + # We need to find the subagent by name + if subagent := next( + ( + sub + for sub in invocation_context.agent.sub_agents + if sub.name == active_subagent_name + ), + None, + ): + try: + subagent_card = json.loads(subagent.description) + except Exception: + logger.warning( + f"Failed to parse agent description for {active_subagent_name}" ) - - await runner.session_service.append_event( - session, - Event( - invocation_id=new_invocation_context_id(), - author="system", - actions=EventActions( - state_delta={ - # These values are used to configure A2UI messages to remote agent calls - "use_ui": True, - "client_capabilities": client_capabilities, - } - ), - ), - ) - - return session + if subagent_card: + if a2a_event.metadata is None: + a2a_event.metadata = {} + a2a_event.metadata["a2a_subagent"] = subagent_card + + for a2a_part in a2a_event.status.message.parts: + if ( + is_a2ui_part(a2a_part) + and (begin_rendering := a2a_part.root.data.get("beginRendering")) + and (surface_id := begin_rendering.get("surfaceId")) + ): + asyncio.run_coroutine_threadsafe( + SubagentRouteManager.set_route_to_subagent_name( + surface_id, + event.author, + invocation_context.session_service, + invocation_context.session, + ), + asyncio.get_event_loop(), + ) + + return a2a_events + + @override + async def _prepare_session( + self, + context: RequestContext, + run_request: AgentRunRequest, + runner: Runner, + ): + session = await super()._prepare_session(context, run_request, runner) + + if try_activate_a2ui_extension(context): + client_capabilities = ( + context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) + if context.message and context.message.metadata + else None + ) + + await runner.session_service.append_event( + session, + Event( + invocation_id=new_invocation_context_id(), + author="system", + actions=EventActions( + state_delta={ + # These values are used to configure A2UI messages to remote agent calls + "use_ui": True, + "client_capabilities": client_capabilities, + } + ), + ), + ) + + return session diff --git a/samples/agent/adk/orchestrator/part_converters.py b/samples/agent/adk/orchestrator/part_converters.py index 6d3111335..8c74656a0 100644 --- a/samples/agent/adk/orchestrator/part_converters.py +++ b/samples/agent/adk/orchestrator/part_converters.py @@ -29,35 +29,35 @@ def convert_a2a_part_to_genai_part( a2a_part: a2a_types.Part, ) -> Optional[genai_types.Part]: - if is_a2ui_part(a2a_part): - genai_part = genai_types.Part(text=a2a_part.model_dump_json()) - logger.info( - f"Converted A2UI part from A2A: {a2a_part.model_dump_json(exclude_none=True)} to GenAI: {genai_part.model_dump_json(exclude_none=True)}"[ - :200 - ] - + "..." - ) - return genai_part + if is_a2ui_part(a2a_part): + genai_part = genai_types.Part(text=a2a_part.model_dump_json()) + logger.info( + f"Converted A2UI part from A2A: {a2a_part.model_dump_json(exclude_none=True)} to GenAI: {genai_part.model_dump_json(exclude_none=True)}"[ + :200 + ] + + "..." + ) + return genai_part - return part_converter.convert_a2a_part_to_genai_part(a2a_part) + return part_converter.convert_a2a_part_to_genai_part(a2a_part) def convert_genai_part_to_a2a_part( part: genai_types.Part, ) -> Optional[a2a_types.Part]: - if part.text: - try: - a2a_part = a2a_types.Part.model_validate_json(part.text) - if is_a2ui_part(a2a_part): - logger.info( - f"Converted A2UI part from GenAI: {part.model_dump_json(exclude_none=True)} to A2A: {a2a_part.model_dump_json(exclude_none=True)}"[ - :200 - ] - + "..." - ) - return a2a_part - except pydantic.ValidationError: - # Expected for normal text input - pass - - return part_converter.convert_genai_part_to_a2a_part(part) + if part.text: + try: + a2a_part = a2a_types.Part.model_validate_json(part.text) + if is_a2ui_part(a2a_part): + logger.info( + f"Converted A2UI part from GenAI: {part.model_dump_json(exclude_none=True)} to A2A: {a2a_part.model_dump_json(exclude_none=True)}"[ + :200 + ] + + "..." + ) + return a2a_part + except pydantic.ValidationError: + # Expected for normal text input + pass + + return part_converter.convert_genai_part_to_a2a_part(part) diff --git a/samples/agent/adk/orchestrator/subagent_route_manager.py b/samples/agent/adk/orchestrator/subagent_route_manager.py index 88e603783..bd6dae9c7 100644 --- a/samples/agent/adk/orchestrator/subagent_route_manager.py +++ b/samples/agent/adk/orchestrator/subagent_route_manager.py @@ -23,50 +23,50 @@ class SubagentRouteManager: - """Manages routing of tasks to sub-agents.""" + """Manages routing of tasks to sub-agents.""" - ROUTING_KEY_PREFIX = "route_to_subagent_name_for_surface_id_" + ROUTING_KEY_PREFIX = "route_to_subagent_name_for_surface_id_" - @classmethod - def _get_routing_key(cls, surface_id: str) -> str: - return cls.ROUTING_KEY_PREFIX + surface_id + @classmethod + def _get_routing_key(cls, surface_id: str) -> str: + return cls.ROUTING_KEY_PREFIX + surface_id - @classmethod - async def get_route_to_subagent_name( - cls, surface_id: str, state: State - ) -> Optional[str]: - """Gets the subagent route for the given tool call id.""" - subagent_name = state.get(cls._get_routing_key(surface_id), None) - logging.info( - "Got subagent route for surface_id %s to subagent_name %s", - surface_id, - subagent_name, - ) - return subagent_name + @classmethod + async def get_route_to_subagent_name( + cls, surface_id: str, state: State + ) -> Optional[str]: + """Gets the subagent route for the given tool call id.""" + subagent_name = state.get(cls._get_routing_key(surface_id), None) + logging.info( + "Got subagent route for surface_id %s to subagent_name %s", + surface_id, + subagent_name, + ) + return subagent_name - @classmethod - async def set_route_to_subagent_name( - cls, - surface_id: str, - subagent_name: str, - session_service: BaseSessionService, - session: Session, - ): - """Sets the subagent route for the given tool call id.""" - key = cls._get_routing_key(surface_id) + @classmethod + async def set_route_to_subagent_name( + cls, + surface_id: str, + subagent_name: str, + session_service: BaseSessionService, + session: Session, + ): + """Sets the subagent route for the given tool call id.""" + key = cls._get_routing_key(surface_id) - if session.state.get(key) != subagent_name: - await session_service.append_event( - session, - Event( - invocation_id=new_invocation_context_id(), - author="system", - actions=EventActions(state_delta={key: subagent_name}), - ), - ) + if session.state.get(key) != subagent_name: + await session_service.append_event( + session, + Event( + invocation_id=new_invocation_context_id(), + author="system", + actions=EventActions(state_delta={key: subagent_name}), + ), + ) - logging.info( - "Set subagent route for surface_id %s to subagent_name %s", - surface_id, - subagent_name, - ) + logging.info( + "Set subagent route for surface_id %s to subagent_name %s", + surface_id, + subagent_name, + ) diff --git a/samples/agent/adk/restaurant_finder/__main__.py b/samples/agent/adk/restaurant_finder/__main__.py index c28339da2..f816cf6d8 100644 --- a/samples/agent/adk/restaurant_finder/__main__.py +++ b/samples/agent/adk/restaurant_finder/__main__.py @@ -32,58 +32,58 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @click.option("--host", default="localhost") @click.option("--port", default=10002) def main(host, port): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." - ) + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." + ) - base_url = f"http://{host}:{port}" + base_url = f"http://{host}:{port}" - ui_agent = RestaurantAgent(base_url=base_url, use_ui=True) - text_agent = RestaurantAgent(base_url=base_url, use_ui=False) + ui_agent = RestaurantAgent(base_url=base_url, use_ui=True) + text_agent = RestaurantAgent(base_url=base_url, use_ui=False) - agent_executor = RestaurantAgentExecutor(ui_agent, text_agent) + agent_executor = RestaurantAgentExecutor(ui_agent, text_agent) - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - server = A2AStarletteApplication( - agent_card=ui_agent.get_agent_card(), http_handler=request_handler - ) - import uvicorn + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + server = A2AStarletteApplication( + agent_card=ui_agent.get_agent_card(), http_handler=request_handler + ) + import uvicorn - app = server.build() + app = server.build() - app.add_middleware( - CORSMiddleware, - allow_origin_regex=r"http://localhost:\d+", - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) + app.add_middleware( + CORSMiddleware, + allow_origin_regex=r"http://localhost:\d+", + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) - app.mount("/static", StaticFiles(directory="images"), name="static") + app.mount("/static", StaticFiles(directory="images"), name="static") - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e}") - exit(1) - except Exception as e: - logger.error(f"An error occurred during server startup: {e}") - exit(1) + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e}") + exit(1) + except Exception as e: + logger.error(f"An error occurred during server startup: {e}") + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/restaurant_finder/agent.py b/samples/agent/adk/restaurant_finder/agent.py index dd36c379a..e5239c5fd 100644 --- a/samples/agent/adk/restaurant_finder/agent.py +++ b/samples/agent/adk/restaurant_finder/agent.py @@ -51,287 +51,283 @@ class RestaurantAgent: - """An agent that finds restaurants based on user criteria.""" - - SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] - - def __init__(self, base_url: str, use_ui: bool = False): - self.base_url = base_url - self.use_ui = use_ui - self._schema_manager = ( - A2uiSchemaManager( - VERSION_0_8, - catalogs=[ - BasicCatalog.get_config( - version=VERSION_0_8, examples_path="examples" - ) - ], - schema_modifiers=[remove_strict_validation], - ) - if use_ui - else None - ) - self._agent = self._build_agent(use_ui) - self._user_id = "remote_agent" - self._runner = Runner( - app_name=self._agent.name, - agent=self._agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - def get_agent_card(self) -> AgentCard: - capabilities = AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - self._schema_manager.accepts_inline_catalogs, - self._schema_manager.supported_catalog_ids, - ) + """An agent that finds restaurants based on user criteria.""" + + SUPPORTED_CONTENT_TYPES = ["text", "text/plain"] + + def __init__(self, base_url: str, use_ui: bool = False): + self.base_url = base_url + self.use_ui = use_ui + self._schema_manager = ( + A2uiSchemaManager( + VERSION_0_8, + catalogs=[ + BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") ], + schema_modifiers=[remove_strict_validation], ) - skill = AgentSkill( - id="find_restaurants", - name="Find Restaurants Tool", - description=( - "Helps find restaurants based on user criteria (e.g., cuisine, location)." - ), - tags=["restaurant", "finder"], - examples=["Find me the top 10 chinese restaurants in the US"], - ) - - return AgentCard( - name="Restaurant Agent", - description="This agent helps find restaurants based on user criteria.", - url=self.base_url, - version="1.0.0", - default_input_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, - capabilities=capabilities, - skills=[skill], + if use_ui + else None + ) + self._agent = self._build_agent(use_ui) + self._user_id = "remote_agent" + self._runner = Runner( + app_name=self._agent.name, + agent=self._agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), + ) + + def get_agent_card(self) -> AgentCard: + capabilities = AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + self._schema_manager.accepts_inline_catalogs, + self._schema_manager.supported_catalog_ids, + ) + ], + ) + skill = AgentSkill( + id="find_restaurants", + name="Find Restaurants Tool", + description=( + "Helps find restaurants based on user criteria (e.g., cuisine, location)." + ), + tags=["restaurant", "finder"], + examples=["Find me the top 10 chinese restaurants in the US"], + ) + + return AgentCard( + name="Restaurant Agent", + description="This agent helps find restaurants based on user criteria.", + url=self.base_url, + version="1.0.0", + default_input_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=RestaurantAgent.SUPPORTED_CONTENT_TYPES, + capabilities=capabilities, + skills=[skill], + ) + + def get_processing_message(self) -> str: + return "Finding restaurants that match your criteria..." + + def _build_agent(self, use_ui: bool) -> LlmAgent: + """Builds the LLM agent for the restaurant agent.""" + LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + + instruction = ( + self._schema_manager.generate_system_prompt( + role_description=ROLE_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=True, ) - - def get_processing_message(self) -> str: - return "Finding restaurants that match your criteria..." - - def _build_agent(self, use_ui: bool) -> LlmAgent: - """Builds the LLM agent for the restaurant agent.""" - LITELLM_MODEL = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - - instruction = ( - self._schema_manager.generate_system_prompt( - role_description=ROLE_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=True, + if use_ui + else get_text_prompt() + ) + + return LlmAgent( + model=LiteLlm(model=LITELLM_MODEL), + name="restaurant_agent", + description="An agent that finds restaurants and helps book tables.", + instruction=instruction, + tools=[get_restaurants], + ) + + async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: + session_state = {"base_url": self.base_url} + + session = await self._runner.session_service.get_session( + app_name=self._agent.name, + user_id=self._user_id, + session_id=session_id, + ) + if session is None: + session = await self._runner.session_service.create_session( + app_name=self._agent.name, + user_id=self._user_id, + state=session_state, + session_id=session_id, + ) + elif "base_url" not in session.state: + session.state["base_url"] = self.base_url + + # --- Begin: UI Validation and Retry Logic --- + max_retries = 1 # Total 2 attempts + attempt = 0 + current_query_text = query + + # Ensure schema was loaded + selected_catalog = self._schema_manager.get_selected_catalog() + if self.use_ui and not selected_catalog.catalog_schema: + logger.error( + "--- RestaurantAgent.stream: A2UI_SCHEMA is not loaded. " + "Cannot perform UI validation. ---" + ) + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm facing an internal configuration error with" + " my UI components. Please contact support." + ) + ) + ) + ], + } + return + + while attempt <= max_retries: + attempt += 1 + logger.info( + f"--- RestaurantAgent.stream: Attempt {attempt}/{max_retries + 1} " + f"for session {session_id} ---" + ) + + current_message = types.Content( + role="user", parts=[types.Part.from_text(text=current_query_text)] + ) + final_response_content = None + + async for event in self._runner.run_async( + user_id=self._user_id, + session_id=session.id, + new_message=current_message, + ): + logger.info(f"Event from runner: {event}") + if event.is_final_response(): + if event.content and event.content.parts and event.content.parts[0].text: + final_response_content = "\n".join( + [p.text for p in event.content.parts if p.text] ) - if use_ui - else get_text_prompt() + break # Got the final response, stop consuming events + else: + logger.info(f"Intermediate event: {event}") + # Yield intermediate updates on every attempt + yield { + "is_task_complete": False, + "updates": self.get_processing_message(), + } + + if final_response_content is None: + logger.warning( + "--- RestaurantAgent.stream: Received no final response content from" + f" runner (Attempt {attempt}). ---" ) - - return LlmAgent( - model=LiteLlm(model=LITELLM_MODEL), - name="restaurant_agent", - description="An agent that finds restaurants and helps book tables.", - instruction=instruction, - tools=[get_restaurants], + if attempt <= max_retries: + current_query_text = ( + "I received no response. Please try again." + f"Please retry the original request: '{query}'" + ) + continue # Go to next retry + else: + # Retries exhausted on no-response + final_response_content = ( + "I'm sorry, I encountered an error and couldn't process your request." + ) + # Fall through to send this as a text-only error + + is_valid = False + error_message = "" + + if self.use_ui: + logger.info( + "--- RestaurantAgent.stream: Validating UI response (Attempt" + f" {attempt})... ---" ) + try: + response_parts = parse_response(final_response_content) - async def stream(self, query, session_id) -> AsyncIterable[dict[str, Any]]: - session_state = {"base_url": self.base_url} + for part in response_parts: + if not part.a2ui_json: + continue - session = await self._runner.session_service.get_session( - app_name=self._agent.name, - user_id=self._user_id, - session_id=session_id, - ) - if session is None: - session = await self._runner.session_service.create_session( - app_name=self._agent.name, - user_id=self._user_id, - state=session_state, - session_id=session_id, - ) - elif "base_url" not in session.state: - session.state["base_url"] = self.base_url - - # --- Begin: UI Validation and Retry Logic --- - max_retries = 1 # Total 2 attempts - attempt = 0 - current_query_text = query - - # Ensure schema was loaded - selected_catalog = self._schema_manager.get_selected_catalog() - if self.use_ui and not selected_catalog.catalog_schema: - logger.error( - "--- RestaurantAgent.stream: A2UI_SCHEMA is not loaded. " - "Cannot perform UI validation. ---" - ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm facing an internal configuration error with" - " my UI components. Please contact support." - ) - ) - ) - ], - } - return + parsed_json_data = part.a2ui_json - while attempt <= max_retries: - attempt += 1 + # --- Validation Steps --- + # Check if it validates against the A2UI_SCHEMA + # This will raise jsonschema.exceptions.ValidationError if it fails logger.info( - f"--- RestaurantAgent.stream: Attempt {attempt}/{max_retries + 1} " - f"for session {session_id} ---" + "--- RestaurantAgent.stream: Validating against A2UI_SCHEMA... ---" ) + selected_catalog.validator.validate(parsed_json_data) + # --- End Validation Steps --- - current_message = types.Content( - role="user", parts=[types.Part.from_text(text=current_query_text)] + logger.info( + "--- RestaurantAgent.stream: UI JSON successfully parsed AND validated" + f" against schema. Validation OK (Attempt {attempt}). ---" ) - final_response_content = None - - async for event in self._runner.run_async( - user_id=self._user_id, - session_id=session.id, - new_message=current_message, - ): - logger.info(f"Event from runner: {event}") - if event.is_final_response(): - if ( - event.content - and event.content.parts - and event.content.parts[0].text - ): - final_response_content = "\n".join( - [p.text for p in event.content.parts if p.text] - ) - break # Got the final response, stop consuming events - else: - logger.info(f"Intermediate event: {event}") - # Yield intermediate updates on every attempt - yield { - "is_task_complete": False, - "updates": self.get_processing_message(), - } - - if final_response_content is None: - logger.warning( - "--- RestaurantAgent.stream: Received no final response content from" - f" runner (Attempt {attempt}). ---" - ) - if attempt <= max_retries: - current_query_text = ( - "I received no response. Please try again." - f"Please retry the original request: '{query}'" - ) - continue # Go to next retry - else: - # Retries exhausted on no-response - final_response_content = "I'm sorry, I encountered an error and couldn't process your request." - # Fall through to send this as a text-only error - - is_valid = False - error_message = "" - - if self.use_ui: - logger.info( - "--- RestaurantAgent.stream: Validating UI response (Attempt" - f" {attempt})... ---" - ) - try: - response_parts = parse_response(final_response_content) - - for part in response_parts: - if not part.a2ui_json: - continue - - parsed_json_data = part.a2ui_json - - # --- Validation Steps --- - # Check if it validates against the A2UI_SCHEMA - # This will raise jsonschema.exceptions.ValidationError if it fails - logger.info( - "--- RestaurantAgent.stream: Validating against A2UI_SCHEMA... ---" - ) - selected_catalog.validator.validate(parsed_json_data) - # --- End Validation Steps --- - - logger.info( - "--- RestaurantAgent.stream: UI JSON successfully parsed AND validated" - f" against schema. Validation OK (Attempt {attempt}). ---" - ) - is_valid = True - - except ( - ValueError, - json.JSONDecodeError, - jsonschema.exceptions.ValidationError, - ) as e: - logger.warning( - f"--- RestaurantAgent.stream: A2UI validation failed: {e} (Attempt" - f" {attempt}) ---" - ) - logger.warning( - f"--- Failed response content: {final_response_content[:500]}... ---" - ) - error_message = f"Validation failed: {e}." - - else: # Not using UI, so text is always "valid" - is_valid = True - - if is_valid: - logger.info( - "--- RestaurantAgent.stream: Response is valid. Sending final response" - f" (Attempt {attempt}). ---" - ) - final_parts = parse_response_to_parts( - final_response_content, fallback_text="OK." - ) - - yield { - "is_task_complete": True, - "parts": final_parts, - } - return # We're done, exit the generator + is_valid = True + + except ( + ValueError, + json.JSONDecodeError, + jsonschema.exceptions.ValidationError, + ) as e: + logger.warning( + f"--- RestaurantAgent.stream: A2UI validation failed: {e} (Attempt" + f" {attempt}) ---" + ) + logger.warning( + f"--- Failed response content: {final_response_content[:500]}... ---" + ) + error_message = f"Validation failed: {e}." + + else: # Not using UI, so text is always "valid" + is_valid = True + + if is_valid: + logger.info( + "--- RestaurantAgent.stream: Response is valid. Sending final response" + f" (Attempt {attempt}). ---" + ) + final_parts = parse_response_to_parts( + final_response_content, fallback_text="OK." + ) - # --- If we're here, it means validation failed --- + yield { + "is_task_complete": True, + "parts": final_parts, + } + return # We're done, exit the generator - if attempt <= max_retries: - logger.warning( - f"--- RestaurantAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" - ) - # Prepare the query for the retry - current_query_text = ( - f"Your previous response was invalid. {error_message} You MUST generate a" - " valid response that strictly follows the A2UI JSON SCHEMA. The response" - " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" - f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" - f" original request: '{query}'" - ) - # Loop continues... + # --- If we're here, it means validation failed --- - # --- If we're here, it means we've exhausted retries --- - logger.error( - "--- RestaurantAgent.stream: Max retries exhausted. Sending text-only" - " error. ---" + if attempt <= max_retries: + logger.warning( + f"--- RestaurantAgent.stream: Retrying... ({attempt}/{max_retries + 1}) ---" ) - yield { - "is_task_complete": True, - "parts": [ - Part( - root=TextPart( - text=( - "I'm sorry, I'm having trouble generating the interface for" - " that request right now. Please try again in a moment." - ) + # Prepare the query for the retry + current_query_text = ( + f"Your previous response was invalid. {error_message} You MUST generate a" + " valid response that strictly follows the A2UI JSON SCHEMA. The response" + " MUST be a JSON list of A2UI messages. Ensure each JSON part is wrapped in" + f" '{A2UI_OPEN_TAG}' and '{A2UI_CLOSE_TAG}' tags. Please retry the" + f" original request: '{query}'" + ) + # Loop continues... + + # --- If we're here, it means we've exhausted retries --- + logger.error( + "--- RestaurantAgent.stream: Max retries exhausted. Sending text-only" + " error. ---" + ) + yield { + "is_task_complete": True, + "parts": [ + Part( + root=TextPart( + text=( + "I'm sorry, I'm having trouble generating the interface for" + " that request right now. Please try again in a moment." ) ) - ], - } - # --- End: UI Validation and Retry Logic --- + ) + ], + } + # --- End: UI Validation and Retry Logic --- diff --git a/samples/agent/adk/restaurant_finder/agent_executor.py b/samples/agent/adk/restaurant_finder/agent_executor.py index 54cf3682b..f552b407d 100644 --- a/samples/agent/adk/restaurant_finder/agent_executor.py +++ b/samples/agent/adk/restaurant_finder/agent_executor.py @@ -38,132 +38,128 @@ class RestaurantAgentExecutor(AgentExecutor): - """Restaurant AgentExecutor Example.""" - - def __init__(self, ui_agent: RestaurantAgent, text_agent: RestaurantAgent): - # Instantiate two agents: one for UI and one for text-only. - # The appropriate one will be chosen at execution time. - self.ui_agent = ui_agent - self.text_agent = text_agent - - async def execute( - self, - context: RequestContext, - event_queue: EventQueue, - ) -> None: - query = "" - ui_event_part = None - action = None - - logger.info( - f"--- Client requested extensions: {context.requested_extensions} ---" - ) - use_ui = try_activate_a2ui_extension(context) - - # Determine which agent to use based on whether the a2ui extension is active. - if use_ui: - agent = self.ui_agent - logger.info( - "--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---" - ) - else: - agent = self.text_agent - logger.info( - "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" - ) - - if context.message and context.message.parts: - logger.info( - f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" - " parts ---" - ) - for i, part in enumerate(context.message.parts): - if isinstance(part.root, DataPart): - if "userAction" in part.root.data: - logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") - ui_event_part = part.root.data["userAction"] - else: - logger.info(f" Part {i}: DataPart (data: {part.root.data})") - elif isinstance(part.root, TextPart): - logger.info(f" Part {i}: TextPart (text: {part.root.text})") - else: - logger.info(f" Part {i}: Unknown part type ({type(part.root)})") - - if ui_event_part: - logger.info(f"Received a2ui ClientEvent: {ui_event_part}") - action = ui_event_part.get("actionName") - ctx = ui_event_part.get("context", {}) - - if action == "book_restaurant": - restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") - address = ctx.get("address", "Address not provided") - image_url = ctx.get("imageUrl", "") - query = ( - f"USER_WANTS_TO_BOOK: {restaurant_name}, Address: {address}, ImageURL:" - f" {image_url}" - ) - - elif action == "submit_booking": - restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") - party_size = ctx.get("partySize", "Unknown Size") - reservation_time = ctx.get("reservationTime", "Unknown Time") - dietary_reqs = ctx.get("dietary", "None") - image_url = ctx.get("imageUrl", "") - query = ( - f"User submitted a booking for {restaurant_name} for {party_size} people at" - f" {reservation_time} with dietary requirements: {dietary_reqs}. The image" - f" URL is {image_url}" - ) - - else: - query = f"User submitted an event: {action} with data: {ctx}" + """Restaurant AgentExecutor Example.""" + + def __init__(self, ui_agent: RestaurantAgent, text_agent: RestaurantAgent): + # Instantiate two agents: one for UI and one for text-only. + # The appropriate one will be chosen at execution time. + self.ui_agent = ui_agent + self.text_agent = text_agent + + async def execute( + self, + context: RequestContext, + event_queue: EventQueue, + ) -> None: + query = "" + ui_event_part = None + action = None + + logger.info(f"--- Client requested extensions: {context.requested_extensions} ---") + use_ui = try_activate_a2ui_extension(context) + + # Determine which agent to use based on whether the a2ui extension is active. + if use_ui: + agent = self.ui_agent + logger.info("--- AGENT_EXECUTOR: A2UI extension is active. Using UI agent. ---") + else: + agent = self.text_agent + logger.info( + "--- AGENT_EXECUTOR: A2UI extension is not active. Using text agent. ---" + ) + + if context.message and context.message.parts: + logger.info( + f"--- AGENT_EXECUTOR: Processing {len(context.message.parts)} message" + " parts ---" + ) + for i, part in enumerate(context.message.parts): + if isinstance(part.root, DataPart): + if "userAction" in part.root.data: + logger.info(f" Part {i}: Found a2ui UI ClientEvent payload.") + ui_event_part = part.root.data["userAction"] + else: + logger.info(f" Part {i}: DataPart (data: {part.root.data})") + elif isinstance(part.root, TextPart): + logger.info(f" Part {i}: TextPart (text: {part.root.text})") else: - logger.info("No a2ui UI event part found. Falling back to text input.") - query = context.get_user_input() - - logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") - - task = context.current_task - - if not task: - task = new_task(context.message) - await event_queue.enqueue_event(task) - updater = TaskUpdater(event_queue, task.id, task.context_id) - - async for item in agent.stream(query, task.context_id): - is_task_complete = item["is_task_complete"] - if not is_task_complete: - await updater.update_status( - TaskState.working, - new_agent_text_message(item["updates"], task.context_id, task.id), - ) - continue - - final_state = ( - TaskState.completed - if action == "submit_booking" - else TaskState.input_required - ) - - final_parts = item["parts"] - - logger.info("--- FINAL PARTS TO BE SENT ---") - for i, part in enumerate(final_parts): - logger.info(f" - Part {i}: Type = {type(part.root)}") - if isinstance(part.root, TextPart): - logger.info(f" - Text: {part.root.text[:200]}...") - elif isinstance(part.root, DataPart): - logger.info(f" - Data: {str(part.root.data)[:200]}...") - logger.info("-----------------------------") - - await updater.update_status( - final_state, - new_agent_parts_message(final_parts, task.context_id, task.id), - final=(final_state == TaskState.completed), - ) - break - - async def cancel( - self, request: RequestContext, event_queue: EventQueue - ) -> Task | None: - raise ServerError(error=UnsupportedOperationError()) + logger.info(f" Part {i}: Unknown part type ({type(part.root)})") + + if ui_event_part: + logger.info(f"Received a2ui ClientEvent: {ui_event_part}") + action = ui_event_part.get("actionName") + ctx = ui_event_part.get("context", {}) + + if action == "book_restaurant": + restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") + address = ctx.get("address", "Address not provided") + image_url = ctx.get("imageUrl", "") + query = ( + f"USER_WANTS_TO_BOOK: {restaurant_name}, Address: {address}, ImageURL:" + f" {image_url}" + ) + + elif action == "submit_booking": + restaurant_name = ctx.get("restaurantName", "Unknown Restaurant") + party_size = ctx.get("partySize", "Unknown Size") + reservation_time = ctx.get("reservationTime", "Unknown Time") + dietary_reqs = ctx.get("dietary", "None") + image_url = ctx.get("imageUrl", "") + query = ( + f"User submitted a booking for {restaurant_name} for {party_size} people at" + f" {reservation_time} with dietary requirements: {dietary_reqs}. The image" + f" URL is {image_url}" + ) + + else: + query = f"User submitted an event: {action} with data: {ctx}" + else: + logger.info("No a2ui UI event part found. Falling back to text input.") + query = context.get_user_input() + + logger.info(f"--- AGENT_EXECUTOR: Final query for LLM: '{query}' ---") + + task = context.current_task + + if not task: + task = new_task(context.message) + await event_queue.enqueue_event(task) + updater = TaskUpdater(event_queue, task.id, task.context_id) + + async for item in agent.stream(query, task.context_id): + is_task_complete = item["is_task_complete"] + if not is_task_complete: + await updater.update_status( + TaskState.working, + new_agent_text_message(item["updates"], task.context_id, task.id), + ) + continue + + final_state = ( + TaskState.completed + if action == "submit_booking" + else TaskState.input_required + ) + + final_parts = item["parts"] + + logger.info("--- FINAL PARTS TO BE SENT ---") + for i, part in enumerate(final_parts): + logger.info(f" - Part {i}: Type = {type(part.root)}") + if isinstance(part.root, TextPart): + logger.info(f" - Text: {part.root.text[:200]}...") + elif isinstance(part.root, DataPart): + logger.info(f" - Data: {str(part.root.data)[:200]}...") + logger.info("-----------------------------") + + await updater.update_status( + final_state, + new_agent_parts_message(final_parts, task.context_id, task.id), + final=(final_state == TaskState.completed), + ) + break + + async def cancel( + self, request: RequestContext, event_queue: EventQueue + ) -> Task | None: + raise ServerError(error=UnsupportedOperationError()) diff --git a/samples/agent/adk/restaurant_finder/prompt_builder.py b/samples/agent/adk/restaurant_finder/prompt_builder.py index 96b3c505c..0d4a2619d 100644 --- a/samples/agent/adk/restaurant_finder/prompt_builder.py +++ b/samples/agent/adk/restaurant_finder/prompt_builder.py @@ -32,10 +32,10 @@ def get_text_prompt() -> str: - """ - Constructs the prompt for a text-only agent. - """ - return """ + """ + Constructs the prompt for a text-only agent. + """ + return """ You are a helpful restaurant finding assistant. Your final output MUST be a text response. To generate the response, you MUST follow these rules: @@ -52,29 +52,27 @@ def get_text_prompt() -> str: if __name__ == "__main__": - # Example of how to use the A2UI Schema Manager to generate a system prompt - # In your actual application, you would call this from your main agent logic. + # Example of how to use the A2UI Schema Manager to generate a system prompt + # In your actual application, you would call this from your main agent logic. - # You can now easily construct a prompt with the relevant examples. - # For a different agent (e.g., a flight booker), you would pass in - # different examples but use the same `get_ui_prompt` function. - restaurant_prompt = A2uiSchemaManager( - VERSION_0_8, - catalogs=[ - BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples") - ], - schema_modifiers=[remove_strict_validation], - ).generate_system_prompt( - role_description=ROLE_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=True, - include_examples=True, - validate_examples=True, - ) + # You can now easily construct a prompt with the relevant examples. + # For a different agent (e.g., a flight booker), you would pass in + # different examples but use the same `get_ui_prompt` function. + restaurant_prompt = A2uiSchemaManager( + VERSION_0_8, + catalogs=[BasicCatalog.get_config(version=VERSION_0_8, examples_path="examples")], + schema_modifiers=[remove_strict_validation], + ).generate_system_prompt( + role_description=ROLE_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=True, + include_examples=True, + validate_examples=True, + ) - print(restaurant_prompt) + print(restaurant_prompt) - # This demonstrates how you could save the prompt to a file for inspection - with open("generated_prompt.txt", "w") as f: - f.write(restaurant_prompt) - print("\nGenerated prompt saved to generated_prompt.txt") + # This demonstrates how you could save the prompt to a file for inspection + with open("generated_prompt.txt", "w") as f: + f.write(restaurant_prompt) + print("\nGenerated prompt saved to generated_prompt.txt") diff --git a/samples/agent/adk/restaurant_finder/tools.py b/samples/agent/adk/restaurant_finder/tools.py index 0263dd40e..da0e48e52 100644 --- a/samples/agent/adk/restaurant_finder/tools.py +++ b/samples/agent/adk/restaurant_finder/tools.py @@ -24,36 +24,36 @@ def get_restaurants( cuisine: str, location: str, tool_context: ToolContext, count: int = 5 ) -> str: - """Call this tool to get a list of restaurants based on a cuisine and location. - 'count' is the number of restaurants to return. - """ - logger.info(f"--- TOOL CALLED: get_restaurants (count: {count}) ---") - logger.info(f" - Cuisine: {cuisine}") - logger.info(f" - Location: {location}") - - items = [] - if "new york" in location.lower() or "ny" in location.lower(): - try: - script_dir = os.path.dirname(__file__) - file_path = os.path.join(script_dir, "restaurant_data.json") - with open(file_path) as f: - restaurant_data_str = f.read() - if base_url := tool_context.state.get("base_url"): - restaurant_data_str = restaurant_data_str.replace( - "http://localhost:10002", base_url - ) - logger.info(f"Updated base URL from tool context: {base_url}") - all_items = json.loads(restaurant_data_str) - - # Slice the list to return only the requested number of items - items = all_items[:count] - logger.info( - f" - Success: Found {len(all_items)} restaurants, returning {len(items)}." - ) - - except FileNotFoundError: - logger.error(f" - Error: restaurant_data.json not found at {file_path}") - except json.JSONDecodeError: - logger.error(f" - Error: Failed to decode JSON from {file_path}") - - return json.dumps(items) + """Call this tool to get a list of restaurants based on a cuisine and location. + 'count' is the number of restaurants to return. + """ + logger.info(f"--- TOOL CALLED: get_restaurants (count: {count}) ---") + logger.info(f" - Cuisine: {cuisine}") + logger.info(f" - Location: {location}") + + items = [] + if "new york" in location.lower() or "ny" in location.lower(): + try: + script_dir = os.path.dirname(__file__) + file_path = os.path.join(script_dir, "restaurant_data.json") + with open(file_path) as f: + restaurant_data_str = f.read() + if base_url := tool_context.state.get("base_url"): + restaurant_data_str = restaurant_data_str.replace( + "http://localhost:10002", base_url + ) + logger.info(f"Updated base URL from tool context: {base_url}") + all_items = json.loads(restaurant_data_str) + + # Slice the list to return only the requested number of items + items = all_items[:count] + logger.info( + f" - Success: Found {len(all_items)} restaurants, returning {len(items)}." + ) + + except FileNotFoundError: + logger.error(f" - Error: restaurant_data.json not found at {file_path}") + except json.JSONDecodeError: + logger.error(f" - Error: Failed to decode JSON from {file_path}") + + return json.dumps(items) diff --git a/samples/agent/adk/rizzcharts/__main__.py b/samples/agent/adk/rizzcharts/__main__.py index edfb8b0b8..9c988f102 100644 --- a/samples/agent/adk/rizzcharts/__main__.py +++ b/samples/agent/adk/rizzcharts/__main__.py @@ -41,93 +41,93 @@ class MissingAPIKeyError(Exception): - """Exception for missing API key.""" + """Exception for missing API key.""" @click.command() @click.option("--host", default="localhost") @click.option("--port", default=10002) def main(host, port): - try: - # Check for API key only if Vertex AI is not configured - if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": - if not os.getenv("GEMINI_API_KEY"): - raise MissingAPIKeyError( - "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" - " is not TRUE." - ) - - lite_llm_model = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") - - base_url = f"http://{host}:{port}" - - schema_manager = A2uiSchemaManager( - VERSION_0_8, - catalogs=[ - CatalogConfig.from_path( - name="rizzcharts", - catalog_path="rizzcharts_catalog_definition.json", - examples_path="examples/rizzcharts_catalog", - ), - BasicCatalog.get_config( - version=VERSION_0_8, - examples_path="examples/standard_catalog", - ), - ], - accepts_inline_catalogs=True, + try: + # Check for API key only if Vertex AI is not configured + if not os.getenv("GOOGLE_GENAI_USE_VERTEXAI") == "TRUE": + if not os.getenv("GEMINI_API_KEY"): + raise MissingAPIKeyError( + "GEMINI_API_KEY environment variable not set and GOOGLE_GENAI_USE_VERTEXAI" + " is not TRUE." ) - agent = RizzchartsAgent( - base_url=base_url, - model=LiteLlm(model=lite_llm_model), - schema_manager=schema_manager, - a2ui_enabled_provider=get_a2ui_enabled, - a2ui_catalog_provider=get_a2ui_catalog, - a2ui_examples_provider=get_a2ui_examples, - ) - runner = Runner( - app_name=agent.name, - agent=agent, - artifact_service=InMemoryArtifactService(), - session_service=InMemorySessionService(), - memory_service=InMemoryMemoryService(), - ) - - agent_executor = RizzchartsAgentExecutor( - base_url=base_url, - runner=runner, - schema_manager=schema_manager, - ) - - request_handler = DefaultRequestHandler( - agent_executor=agent_executor, - task_store=InMemoryTaskStore(), - ) - server = A2AStarletteApplication( - agent_card=agent.get_agent_card(), http_handler=request_handler - ) - import uvicorn - - app = server.build() - - app.add_middleware( - CORSMiddleware, - allow_origins=["http://localhost:5173"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) - - uvicorn.run(app, host=host, port=port) - except MissingAPIKeyError as e: - logger.error(f"Error: {e} {traceback.format_exc()}") - exit(1) - except Exception as e: - logger.error( - f"An error occurred during server startup: {e} {traceback.format_exc()}" - ) - exit(1) + lite_llm_model = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash") + + base_url = f"http://{host}:{port}" + + schema_manager = A2uiSchemaManager( + VERSION_0_8, + catalogs=[ + CatalogConfig.from_path( + name="rizzcharts", + catalog_path="rizzcharts_catalog_definition.json", + examples_path="examples/rizzcharts_catalog", + ), + BasicCatalog.get_config( + version=VERSION_0_8, + examples_path="examples/standard_catalog", + ), + ], + accepts_inline_catalogs=True, + ) + + agent = RizzchartsAgent( + base_url=base_url, + model=LiteLlm(model=lite_llm_model), + schema_manager=schema_manager, + a2ui_enabled_provider=get_a2ui_enabled, + a2ui_catalog_provider=get_a2ui_catalog, + a2ui_examples_provider=get_a2ui_examples, + ) + runner = Runner( + app_name=agent.name, + agent=agent, + artifact_service=InMemoryArtifactService(), + session_service=InMemorySessionService(), + memory_service=InMemoryMemoryService(), + ) + + agent_executor = RizzchartsAgentExecutor( + base_url=base_url, + runner=runner, + schema_manager=schema_manager, + ) + + request_handler = DefaultRequestHandler( + agent_executor=agent_executor, + task_store=InMemoryTaskStore(), + ) + server = A2AStarletteApplication( + agent_card=agent.get_agent_card(), http_handler=request_handler + ) + import uvicorn + + app = server.build() + + app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:5173"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + uvicorn.run(app, host=host, port=port) + except MissingAPIKeyError as e: + logger.error(f"Error: {e} {traceback.format_exc()}") + exit(1) + except Exception as e: + logger.error( + f"An error occurred during server startup: {e} {traceback.format_exc()}" + ) + exit(1) if __name__ == "__main__": - main() + main() diff --git a/samples/agent/adk/rizzcharts/agent.py b/samples/agent/adk/rizzcharts/agent.py index 78b7fdf2b..26f92c738 100644 --- a/samples/agent/adk/rizzcharts/agent.py +++ b/samples/agent/adk/rizzcharts/agent.py @@ -28,9 +28,9 @@ from pydantic import PrivateAttr try: - from .tools import get_sales_data, get_store_sales + from .tools import get_sales_data, get_store_sales except ImportError: - from tools import get_sales_data, get_store_sales + from tools import get_sales_data, get_store_sales logger = logging.getLogger(__name__) @@ -83,129 +83,129 @@ class RizzchartsAgent(LlmAgent): - """An agent that runs an ecommerce dashboard""" - - SUPPORTED_CONTENT_TYPES: ClassVar[list[str]] = ["text", "text/plain"] - base_url: str = "" - schema_manager: A2uiSchemaManager = None - _a2ui_enabled_provider: A2uiEnabledProvider = PrivateAttr() - _a2ui_catalog_provider: A2uiCatalogProvider = PrivateAttr() - _a2ui_examples_provider: A2uiExamplesProvider = PrivateAttr() - - def __init__( - self, - model: Any, - base_url: str, - schema_manager: A2uiSchemaManager, - a2ui_enabled_provider: A2uiEnabledProvider, - a2ui_catalog_provider: A2uiCatalogProvider, - a2ui_examples_provider: A2uiExamplesProvider, - ): - """Initializes the RizzchartsAgent. - - Args: - model: The LLM model to use. - base_url: The base URL for the agent. - schema_manager: The A2UI schema manager. - a2ui_enabled_provider: A provider to check if A2UI is enabled. - a2ui_catalog_provider: A provider to retrieve the A2UI catalog (A2uiCatalog object). - a2ui_examples_provider: A provider to retrieve the A2UI examples (str). - """ - - system_instructions = schema_manager.generate_system_prompt( - role_description=ROLE_DESCRIPTION, - workflow_description=WORKFLOW_DESCRIPTION, - ui_description=UI_DESCRIPTION, - include_schema=False, - include_examples=False, - validate_examples=False, - ) - super().__init__( - model=model, - name="rizzcharts_agent", - description="An agent that lets sales managers request sales data.", - instruction=system_instructions, - tools=[ - get_store_sales, - get_sales_data, - SendA2uiToClientToolset( - a2ui_catalog=a2ui_catalog_provider, - a2ui_enabled=a2ui_enabled_provider, - a2ui_examples=a2ui_examples_provider, - ), - ], - planner=BuiltInPlanner( - thinking_config=types.ThinkingConfig( - include_thoughts=True, - ) + """An agent that runs an ecommerce dashboard""" + + SUPPORTED_CONTENT_TYPES: ClassVar[list[str]] = ["text", "text/plain"] + base_url: str = "" + schema_manager: A2uiSchemaManager = None + _a2ui_enabled_provider: A2uiEnabledProvider = PrivateAttr() + _a2ui_catalog_provider: A2uiCatalogProvider = PrivateAttr() + _a2ui_examples_provider: A2uiExamplesProvider = PrivateAttr() + + def __init__( + self, + model: Any, + base_url: str, + schema_manager: A2uiSchemaManager, + a2ui_enabled_provider: A2uiEnabledProvider, + a2ui_catalog_provider: A2uiCatalogProvider, + a2ui_examples_provider: A2uiExamplesProvider, + ): + """Initializes the RizzchartsAgent. + + Args: + model: The LLM model to use. + base_url: The base URL for the agent. + schema_manager: The A2UI schema manager. + a2ui_enabled_provider: A provider to check if A2UI is enabled. + a2ui_catalog_provider: A provider to retrieve the A2UI catalog (A2uiCatalog object). + a2ui_examples_provider: A provider to retrieve the A2UI examples (str). + """ + + system_instructions = schema_manager.generate_system_prompt( + role_description=ROLE_DESCRIPTION, + workflow_description=WORKFLOW_DESCRIPTION, + ui_description=UI_DESCRIPTION, + include_schema=False, + include_examples=False, + validate_examples=False, + ) + super().__init__( + model=model, + name="rizzcharts_agent", + description="An agent that lets sales managers request sales data.", + instruction=system_instructions, + tools=[ + get_store_sales, + get_sales_data, + SendA2uiToClientToolset( + a2ui_catalog=a2ui_catalog_provider, + a2ui_enabled=a2ui_enabled_provider, + a2ui_examples=a2ui_examples_provider, ), - disallow_transfer_to_peers=True, - base_url=base_url, - schema_manager=schema_manager, - ) - - self._a2ui_enabled_provider = a2ui_enabled_provider - self._a2ui_catalog_provider = a2ui_catalog_provider - self._a2ui_examples_provider = a2ui_examples_provider - - def get_agent_card(self) -> AgentCard: - """Returns the AgentCard defining this agent's metadata and skills. - - Returns: - An AgentCard object. - """ - return AgentCard( - name="Ecommerce Dashboard Agent", - description=( - "This agent visualizes ecommerce data, showing sales breakdowns, YOY" - " revenue performance, and regional sales outliers." - ), - url=self.base_url, - version="1.0.0", - default_input_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, - default_output_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, - capabilities=AgentCapabilities( - streaming=True, - extensions=[ - get_a2ui_agent_extension( - self.schema_manager.accepts_inline_catalogs, - self.schema_manager.supported_catalog_ids, - ) + ], + planner=BuiltInPlanner( + thinking_config=types.ThinkingConfig( + include_thoughts=True, + ) + ), + disallow_transfer_to_peers=True, + base_url=base_url, + schema_manager=schema_manager, + ) + + self._a2ui_enabled_provider = a2ui_enabled_provider + self._a2ui_catalog_provider = a2ui_catalog_provider + self._a2ui_examples_provider = a2ui_examples_provider + + def get_agent_card(self) -> AgentCard: + """Returns the AgentCard defining this agent's metadata and skills. + + Returns: + An AgentCard object. + """ + return AgentCard( + name="Ecommerce Dashboard Agent", + description=( + "This agent visualizes ecommerce data, showing sales breakdowns, YOY" + " revenue performance, and regional sales outliers." + ), + url=self.base_url, + version="1.0.0", + default_input_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, + default_output_modes=RizzchartsAgent.SUPPORTED_CONTENT_TYPES, + capabilities=AgentCapabilities( + streaming=True, + extensions=[ + get_a2ui_agent_extension( + self.schema_manager.accepts_inline_catalogs, + self.schema_manager.supported_catalog_ids, + ) + ], + ), + skills=[ + AgentSkill( + id="view_sales_by_category", + name="View Sales by Category", + description=( + "Displays a pie chart of sales broken down by product category for" + " a given time period." + ), + tags=["sales", "breakdown", "category", "pie chart", "revenue"], + examples=[ + "show my sales breakdown by product category for q3", + "What's the sales breakdown for last month?", ], ), - skills=[ - AgentSkill( - id="view_sales_by_category", - name="View Sales by Category", - description=( - "Displays a pie chart of sales broken down by product category for" - " a given time period." - ), - tags=["sales", "breakdown", "category", "pie chart", "revenue"], - examples=[ - "show my sales breakdown by product category for q3", - "What's the sales breakdown for last month?", - ], - ), - AgentSkill( - id="view_regional_outliers", - name="View Regional Sales Outliers", - description=( - "Displays a map showing regional sales outliers or store-level" - " performance." - ), - tags=[ - "sales", - "regional", - "outliers", - "stores", - "map", - "performance", - ], - examples=[ - "interesting. were there any outlier stores", - "show me a map of store performance", - ], + AgentSkill( + id="view_regional_outliers", + name="View Regional Sales Outliers", + description=( + "Displays a map showing regional sales outliers or store-level" + " performance." ), - ], - ) + tags=[ + "sales", + "regional", + "outliers", + "stores", + "map", + "performance", + ], + examples=[ + "interesting. were there any outlier stores", + "show me a map of store performance", + ], + ), + ], + ) diff --git a/samples/agent/adk/rizzcharts/agent_executor.py b/samples/agent/adk/rizzcharts/agent_executor.py index 6ea59d2c8..5892eea94 100644 --- a/samples/agent/adk/rizzcharts/agent_executor.py +++ b/samples/agent/adk/rizzcharts/agent_executor.py @@ -44,96 +44,96 @@ def get_a2ui_catalog(ctx: ReadonlyContext): - """Retrieves the A2UI catalog from the session state. + """Retrieves the A2UI catalog from the session state. - Args: - ctx: The ReadonlyContext for resolving the catalog. + Args: + ctx: The ReadonlyContext for resolving the catalog. - Returns: - The A2UI catalog or None if not found. - """ - return ctx.state.get(_A2UI_CATALOG_KEY) + Returns: + The A2UI catalog or None if not found. + """ + return ctx.state.get(_A2UI_CATALOG_KEY) def get_a2ui_examples(ctx: ReadonlyContext): - """Retrieves the A2UI examples from the session state. + """Retrieves the A2UI examples from the session state. - Args: - ctx: The ReadonlyContext for resolving the examples. + Args: + ctx: The ReadonlyContext for resolving the examples. - Returns: - The A2UI examples or None if not found. - """ - return ctx.state.get(_A2UI_EXAMPLES_KEY) + Returns: + The A2UI examples or None if not found. + """ + return ctx.state.get(_A2UI_EXAMPLES_KEY) def get_a2ui_enabled(ctx: ReadonlyContext): - """Checks if A2UI is enabled in the current session. + """Checks if A2UI is enabled in the current session. - Args: - ctx: The ReadonlyContext for resolving enablement. + Args: + ctx: The ReadonlyContext for resolving enablement. - Returns: - True if A2UI is enabled, False otherwise. - """ - return ctx.state.get(_A2UI_ENABLED_KEY, False) + Returns: + True if A2UI is enabled, False otherwise. + """ + return ctx.state.get(_A2UI_ENABLED_KEY, False) class RizzchartsAgentExecutor(A2aAgentExecutor): - """Executor for the Rizzcharts agent that handles A2UI session setup.""" - - def __init__( - self, - base_url: str, - runner: Runner, - schema_manager: A2uiSchemaManager, - ): - self._base_url = base_url - self.schema_manager = schema_manager - - config = A2aAgentExecutorConfig(event_converter=A2uiEventConverter()) - super().__init__(runner=runner, config=config) - - @override - async def _prepare_session( - self, - context: RequestContext, - run_request: AgentRunRequest, - runner: Runner, - ): - logger.info(f"Loading session for message {context.message}") - - session = await super()._prepare_session(context, run_request, runner) - - if "base_url" not in session.state: - session.state["base_url"] = self._base_url - - use_ui = try_activate_a2ui_extension(context) - if use_ui: - capabilities = ( - context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) - if context.message and context.message.metadata - else None - ) - a2ui_catalog = self.schema_manager.get_selected_catalog( - client_ui_capabilities=capabilities - ) - - examples = self.schema_manager.load_examples(a2ui_catalog, validate=True) - - await runner.session_service.append_event( - session, - Event( - invocation_id=new_invocation_context_id(), - author="system", - actions=EventActions( - state_delta={ - _A2UI_ENABLED_KEY: True, - _A2UI_CATALOG_KEY: a2ui_catalog, - _A2UI_EXAMPLES_KEY: examples, - } - ), - ), - ) - - return session + """Executor for the Rizzcharts agent that handles A2UI session setup.""" + + def __init__( + self, + base_url: str, + runner: Runner, + schema_manager: A2uiSchemaManager, + ): + self._base_url = base_url + self.schema_manager = schema_manager + + config = A2aAgentExecutorConfig(event_converter=A2uiEventConverter()) + super().__init__(runner=runner, config=config) + + @override + async def _prepare_session( + self, + context: RequestContext, + run_request: AgentRunRequest, + runner: Runner, + ): + logger.info(f"Loading session for message {context.message}") + + session = await super()._prepare_session(context, run_request, runner) + + if "base_url" not in session.state: + session.state["base_url"] = self._base_url + + use_ui = try_activate_a2ui_extension(context) + if use_ui: + capabilities = ( + context.message.metadata.get(A2UI_CLIENT_CAPABILITIES_KEY) + if context.message and context.message.metadata + else None + ) + a2ui_catalog = self.schema_manager.get_selected_catalog( + client_ui_capabilities=capabilities + ) + + examples = self.schema_manager.load_examples(a2ui_catalog, validate=True) + + await runner.session_service.append_event( + session, + Event( + invocation_id=new_invocation_context_id(), + author="system", + actions=EventActions( + state_delta={ + _A2UI_ENABLED_KEY: True, + _A2UI_CATALOG_KEY: a2ui_catalog, + _A2UI_EXAMPLES_KEY: examples, + } + ), + ), + ) + + return session diff --git a/samples/agent/adk/rizzcharts/tools.py b/samples/agent/adk/rizzcharts/tools.py index 61424872e..9acca87a0 100644 --- a/samples/agent/adk/rizzcharts/tools.py +++ b/samples/agent/adk/rizzcharts/tools.py @@ -19,89 +19,89 @@ def get_store_sales(region: str = "all", **kwargs: Any) -> dict[str, Any]: - """ - Gets individual store sales + """ + Gets individual store sales - Args: - region: The region to get store sales for. - **kwargs: Additional arguments. + Args: + region: The region to get store sales for. + **kwargs: Additional arguments. - Returns: - A dict containing the stores with locations and their sales, and with outlier stores highlighted - """ - logger.info("get_store_sales called with region=%s, kwargs=%s", region, kwargs) + Returns: + A dict containing the stores with locations and their sales, and with outlier stores highlighted + """ + logger.info("get_store_sales called with region=%s, kwargs=%s", region, kwargs) - return { - "center": {"lat": 34, "lng": -118.2437}, - "zoom": 10, - "locations": [ - { - "lat": 34.0195, - "lng": -118.4912, - "name": "Santa Monica Branch", - "description": "High traffic coastal location.", - "outlier_reason": "Yes, 15% sales over baseline", - "background": "#4285F4", - "borderColor": "#FFFFFF", - "glyphColor": "#FFFFFF", - }, - {"lat": 34.0488, "lng": -118.2518, "name": "Downtown Flagship"}, - {"lat": 34.1016, "lng": -118.3287, "name": "Hollywood Boulevard Store"}, - {"lat": 34.1478, "lng": -118.1445, "name": "Pasadena Location"}, - {"lat": 33.7701, "lng": -118.1937, "name": "Long Beach Outlet"}, - {"lat": 34.0736, "lng": -118.4004, "name": "Beverly Hills Boutique"}, - ], - } + return { + "center": {"lat": 34, "lng": -118.2437}, + "zoom": 10, + "locations": [ + { + "lat": 34.0195, + "lng": -118.4912, + "name": "Santa Monica Branch", + "description": "High traffic coastal location.", + "outlier_reason": "Yes, 15% sales over baseline", + "background": "#4285F4", + "borderColor": "#FFFFFF", + "glyphColor": "#FFFFFF", + }, + {"lat": 34.0488, "lng": -118.2518, "name": "Downtown Flagship"}, + {"lat": 34.1016, "lng": -118.3287, "name": "Hollywood Boulevard Store"}, + {"lat": 34.1478, "lng": -118.1445, "name": "Pasadena Location"}, + {"lat": 33.7701, "lng": -118.1937, "name": "Long Beach Outlet"}, + {"lat": 34.0736, "lng": -118.4004, "name": "Beverly Hills Boutique"}, + ], + } def get_sales_data(time_period: str = "year", **kwargs: Any) -> dict[str, Any]: - """ - Gets the sales data. + """ + Gets the sales data. - Args: - time_period: The time period to get sales data for (e.g. 'Q1', 'year'). Defaults to 'year'. - **kwargs: Additional arguments. + Args: + time_period: The time period to get sales data for (e.g. 'Q1', 'year'). Defaults to 'year'. + **kwargs: Additional arguments. - Returns: - A dict containing the sales breakdown by product category. - """ - logger.info( - "get_sales_data called with time_period=%s, kwargs=%s", time_period, kwargs - ) + Returns: + A dict containing the sales breakdown by product category. + """ + logger.info( + "get_sales_data called with time_period=%s, kwargs=%s", time_period, kwargs + ) - return { - "sales_data": [ - { - "label": "Apparel", - "value": 41, - "drillDown": [ - {"label": "Tops", "value": 31}, - {"label": "Bottoms", "value": 38}, - {"label": "Outerwear", "value": 20}, - {"label": "Footwear", "value": 11}, - ], - }, - { - "label": "Home Goods", - "value": 15, - "drillDown": [ - {"label": "Pillow", "value": 8}, - {"label": "Coffee Maker", "value": 16}, - {"label": "Area Rug", "value": 3}, - {"label": "Bath Towels", "value": 14}, - ], - }, - { - "label": "Electronics", - "value": 28, - "drillDown": [ - {"label": "Phones", "value": 25}, - {"label": "Laptops", "value": 27}, - {"label": "TVs", "value": 21}, - {"label": "Other", "value": 27}, - ], - }, - {"label": "Health & Beauty", "value": 10}, - {"label": "Other", "value": 6}, - ] - } + return { + "sales_data": [ + { + "label": "Apparel", + "value": 41, + "drillDown": [ + {"label": "Tops", "value": 31}, + {"label": "Bottoms", "value": 38}, + {"label": "Outerwear", "value": 20}, + {"label": "Footwear", "value": 11}, + ], + }, + { + "label": "Home Goods", + "value": 15, + "drillDown": [ + {"label": "Pillow", "value": 8}, + {"label": "Coffee Maker", "value": 16}, + {"label": "Area Rug", "value": 3}, + {"label": "Bath Towels", "value": 14}, + ], + }, + { + "label": "Electronics", + "value": 28, + "drillDown": [ + {"label": "Phones", "value": 25}, + {"label": "Laptops", "value": 27}, + {"label": "TVs", "value": 21}, + {"label": "Other", "value": 27}, + ], + }, + {"label": "Health & Beauty", "value": 10}, + {"label": "Other", "value": 6}, + ] + } diff --git a/samples/client/lit/package-lock.json b/samples/client/lit/package-lock.json index 44dff6601..d6d5a3b19 100644 --- a/samples/client/lit/package-lock.json +++ b/samples/client/lit/package-lock.json @@ -103,9 +103,9 @@ } }, "node_modules/@a2a-js/sdk": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@a2a-js/sdk/-/sdk-0.3.8.tgz", - "integrity": "sha512-vAg6JQbhOnHTzApsB7nGzCQ9r7PuY4GMr8gt88dIR8Wc8G8RSqVTyTmFeMurgzcYrtHYXS3ru2rnDoGj9UDeSw==", + "version": "0.3.12", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@a2a-js/sdk/-/sdk-0.3.12.tgz", + "integrity": "sha512-iYV4rkOrAiGGN0ID54NiszHmgtBI0zJwgY3ZfsGOxwfz5CC8ERSSG1te5pwXApyqlZM+GxENad9gvmTk9oS1vQ==", "license": "Apache-2.0", "dependencies": { "uuid": "^11.1.0" @@ -114,9 +114,17 @@ "node": ">=18" }, "peerDependencies": { + "@bufbuild/protobuf": "^2.10.2", + "@grpc/grpc-js": "^1.11.0", "express": "^4.21.2 || ^5.1.0" }, "peerDependenciesMeta": { + "@bufbuild/protobuf": { + "optional": true + }, + "@grpc/grpc-js": { + "optional": true + }, "express": { "optional": true } @@ -124,7 +132,7 @@ }, "node_modules/@a2a-js/sdk/node_modules/uuid": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/uuid/-/uuid-11.1.0.tgz", "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "funding": [ "https://github.com/sponsors/broofa", @@ -156,9 +164,9 @@ "link": true }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", "cpu": [ "ppc64" ], @@ -173,9 +181,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", "cpu": [ "arm" ], @@ -190,9 +198,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", "cpu": [ "arm64" ], @@ -207,9 +215,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", "cpu": [ "x64" ], @@ -224,9 +232,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", "cpu": [ "arm64" ], @@ -241,9 +249,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", "cpu": [ "x64" ], @@ -258,9 +266,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", "cpu": [ "arm64" ], @@ -275,9 +283,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", "cpu": [ "x64" ], @@ -292,9 +300,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", "cpu": [ "arm" ], @@ -309,9 +317,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", "cpu": [ "arm64" ], @@ -326,9 +334,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", "cpu": [ "ia32" ], @@ -343,9 +351,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", "cpu": [ "loong64" ], @@ -360,9 +368,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", "cpu": [ "mips64el" ], @@ -377,9 +385,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", "cpu": [ "ppc64" ], @@ -394,9 +402,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", "cpu": [ "riscv64" ], @@ -411,9 +419,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", "cpu": [ "s390x" ], @@ -428,9 +436,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", "cpu": [ "x64" ], @@ -445,9 +453,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", "cpu": [ "arm64" ], @@ -462,9 +470,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", "cpu": [ "x64" ], @@ -479,9 +487,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", "cpu": [ "arm64" ], @@ -496,9 +504,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", "cpu": [ "x64" ], @@ -513,9 +521,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", "cpu": [ "arm64" ], @@ -530,9 +538,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", "cpu": [ "x64" ], @@ -547,9 +555,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", "cpu": [ "arm64" ], @@ -564,9 +572,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", "cpu": [ "ia32" ], @@ -581,9 +589,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", "cpu": [ "x64" ], @@ -598,12 +606,13 @@ } }, "node_modules/@google/genai": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.38.0.tgz", - "integrity": "sha512-V/4CQVQGovvGHuS73lwJwHKR9x33kCij3zz/ReEQ4A7RJaV0U7m4k1mvYhFk55cGZdF5JLKu2S9BTaFuEs5xTA==", + "version": "1.45.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@google/genai/-/genai-1.45.0.tgz", + "integrity": "sha512-+sNRWhKiRibVgc4OKi7aBJJ0A7RcoVD8tGG+eFkqxAWRjASDW+ktS9lLwTDnAxZICzCVoeAdu8dYLJVTX60N9w==", "license": "Apache-2.0", "dependencies": { "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, @@ -620,9 +629,9 @@ } }, "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "version": "1.19.11", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@hono/node-server/-/node-server-1.19.11.tgz", + "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", "license": "MIT", "peer": true, "engines": { @@ -634,7 +643,7 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "license": "ISC", "dependencies": { @@ -649,88 +658,9 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@lit-labs/signals": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@lit-labs/signals/-/signals-0.1.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit-labs/signals/-/signals-0.1.3.tgz", "integrity": "sha512-P0yWgH5blwVyEwBg+WFspLzeu1i0ypJP1QB0l1Omr9qZLIPsUu0p4Fy2jshOg7oQyha5n163K3GJGeUhQQ682Q==", "license": "BSD-3-Clause", "dependencies": { @@ -740,13 +670,13 @@ }, "node_modules/@lit-labs/ssr-dom-shim": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.5.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.5.1.tgz", "integrity": "sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==", "license": "BSD-3-Clause" }, "node_modules/@lit/context": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.6.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit/context/-/context-1.1.6.tgz", "integrity": "sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==", "license": "BSD-3-Clause", "dependencies": { @@ -755,7 +685,7 @@ }, "node_modules/@lit/reactive-element": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit/reactive-element/-/reactive-element-2.1.2.tgz", "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", "license": "BSD-3-Clause", "dependencies": { @@ -763,32 +693,15 @@ } }, "node_modules/@modelcontextprotocol/ext-apps": { - "version": "1.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@modelcontextprotocol/ext-apps/-/ext-apps-1.1.2.tgz", - "integrity": "sha512-Gx4TEo3/F8yq1Ix6LdgLwMrKqfZqD7++eakZdbMUewrYtHeeJn3nKpeNhgEfO7nYRwonqWYomOAszWZWJS0IbA==", - "hasInstallScript": true, + "version": "1.2.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@modelcontextprotocol/ext-apps/-/ext-apps-1.2.2.tgz", + "integrity": "sha512-qMnhIKb8tyPesl+kZU76Xz9Bi9putCO+LcgvBJ00fDdIniiLZsnQbAeTKoq+sTiYH1rba2Fvj8NPAFxij+gyxw==", "license": "MIT", "workspaces": [ "examples/*" ], - "optionalDependencies": { - "@oven/bun-darwin-aarch64": "^1.2.21", - "@oven/bun-darwin-x64": "^1.2.21", - "@oven/bun-darwin-x64-baseline": "^1.2.21", - "@oven/bun-linux-aarch64": "^1.2.21", - "@oven/bun-linux-aarch64-musl": "^1.2.21", - "@oven/bun-linux-x64": "^1.2.21", - "@oven/bun-linux-x64-baseline": "^1.2.21", - "@oven/bun-linux-x64-musl": "^1.2.21", - "@oven/bun-linux-x64-musl-baseline": "^1.2.21", - "@oven/bun-windows-x64": "^1.2.21", - "@oven/bun-windows-x64-baseline": "^1.2.21", - "@rollup/rollup-darwin-arm64": "^4.53.3", - "@rollup/rollup-darwin-x64": "^4.53.3", - "@rollup/rollup-linux-arm64-gnu": "^4.53.3", - "@rollup/rollup-linux-x64-gnu": "^4.53.3", - "@rollup/rollup-win32-arm64-msvc": "^4.53.3", - "@rollup/rollup-win32-x64-msvc": "^4.53.3" + "engines": { + "node": ">=20" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.24.0", @@ -848,7 +761,7 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", @@ -862,7 +775,7 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", @@ -872,7 +785,7 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", @@ -884,152 +797,9 @@ "node": ">= 8" } }, - "node_modules/@oven/bun-darwin-aarch64": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.3.10.tgz", - "integrity": "sha512-PXgg5gqcS/rHwa1hF0JdM1y5TiyejVrMHoBmWY/DjtfYZoFTXie1RCFOkoG0b5diOOmUcuYarMpH7CSNTqwj+w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@oven/bun-darwin-x64": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-darwin-x64/-/bun-darwin-x64-1.3.10.tgz", - "integrity": "sha512-Nhssuh7GBpP5PiDSOl3+qnoIG7PJo+ec2oomDevnl9pRY6x6aD2gRt0JE+uf+A8Om2D6gjeHCxjEdrw5ZHE8mA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@oven/bun-darwin-x64-baseline": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.3.10.tgz", - "integrity": "sha512-w1gaTlqU0IJCmJ1X+PGHkdNU1n8Gemx5YKkjhkJIguvFINXEBB5U1KG82QsT65Tk4KyNMfbLTlmy4giAvUoKfA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@oven/bun-linux-aarch64": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.3.10.tgz", - "integrity": "sha512-OUgPHfL6+PM2Q+tFZjcaycN3D7gdQdYlWnwMI31DXZKY1r4HINWk9aEz9t/rNaHg65edwNrt7dsv9TF7xK8xIA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oven/bun-linux-aarch64-musl": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-aarch64-musl/-/bun-linux-aarch64-musl-1.3.10.tgz", - "integrity": "sha512-Ui5pAgM7JE9MzHokF0VglRMkbak3lTisY4Mf1AZutPACXWgKJC5aGrgnHBfkl7QS6fEeYb0juy1q4eRznRHOsw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oven/bun-linux-x64": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64/-/bun-linux-x64-1.3.10.tgz", - "integrity": "sha512-bzUgYj/PIZziB/ZesIP9HUyfvh6Vlf3od+TrbTTyVEuCSMKzDPQVW/yEbRp0tcHO3alwiEXwJDrWrHAguXlgiQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oven/bun-linux-x64-baseline": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.3.10.tgz", - "integrity": "sha512-oqvMDYpX6dGJO03HgO5bXuccEsH3qbdO3MaAiAlO4CfkBPLUXz3N0DDElg5hz0L6ktdDVKbQVE5lfe+LAUISQg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oven/bun-linux-x64-musl": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64-musl/-/bun-linux-x64-musl-1.3.10.tgz", - "integrity": "sha512-poVXvOShekbexHq45b4MH/mRjQKwACAC8lHp3Tz/hEDuz0/20oncqScnmKwzhBPEpqJvydXficXfBYuSim8opw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oven/bun-linux-x64-musl-baseline": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-linux-x64-musl-baseline/-/bun-linux-x64-musl-baseline-1.3.10.tgz", - "integrity": "sha512-/hOZ6S1VsTX6vtbhWVL9aAnOrdpuO54mAGUWpTdMz7dFG5UBZ/VUEiK0pBkq9A1rlBk0GeD/6Y4NBFl8Ha7cRA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oven/bun-windows-x64": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-windows-x64/-/bun-windows-x64-1.3.10.tgz", - "integrity": "sha512-qaS1In3yfC/Z/IGQriVmF8GWwKuNqiw7feTSJWaQhH5IbL6ENR+4wGNPniZSJFaM/SKUO0e/YCRdoVBvgU4C1g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@oven/bun-windows-x64-baseline": { - "version": "1.3.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@oven/bun-windows-x64-baseline/-/bun-windows-x64-baseline-1.3.10.tgz", - "integrity": "sha512-gh3UAHbUdDUG6fhLc1Csa4IGdtghue6U8oAIXWnUqawp6lwb3gOCRvp25IUnLF5vUHtgfMxuEUYV7YA2WxVutw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "license": "MIT", "optional": true, @@ -1039,31 +809,31 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "license": "BSD-3-Clause", "dependencies": { @@ -1073,38 +843,38 @@ }, "node_modules/@protobufjs/float": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "license": "BSD-3-Clause" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.3.tgz", - "integrity": "sha512-qyX8+93kK/7R5BEXPC2PjUt0+fS/VO2BVHjEHyIEWiYn88rcRBHmdLgoJjktBltgAf+NY7RfCGB1SoyKS/p9kg==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -1116,9 +886,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.3.tgz", - "integrity": "sha512-6sHrL42bjt5dHQzJ12Q4vMKfN+kUnZ0atHHnv4V0Wd9JMTk7FDzSY35+7qbz3ypQYMBPANbpGK7JpnWNnhGt8g==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -1130,12 +900,13 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.3.tgz", - "integrity": "sha512-1ht2SpGIjEl2igJ9AbNpPIKzb1B5goXOcmtD0RFxnwNuMxqkR6AUaaErZz+4o+FKmzxcSNBOLrzsICZVNYa1Rw==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1143,12 +914,13 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.3.tgz", - "integrity": "sha512-FYZ4iVunXxtT+CZqQoPVwPhH7549e/Gy7PIRRtq4t5f/vt54pX6eG9ebttRH6QSH7r/zxAFA4EZGlQ0h0FvXiA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1156,9 +928,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.3.tgz", - "integrity": "sha512-M/mwDCJ4wLsIgyxv2Lj7Len+UMHd4zAXu4GQ2UaCdksStglWhP61U3uowkaYBQBhVoNpwx5Hputo8eSqM7K82Q==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -1170,9 +942,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.3.tgz", - "integrity": "sha512-5jZT2c7jBCrMegKYTYTpni8mg8y3uY8gzeq2ndFOANwNuC/xJbVAoGKR9LhMDA0H3nIhvaqUoBEuJoICBudFrA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -1184,9 +956,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.3.tgz", - "integrity": "sha512-YeGUhkN1oA+iSPzzhEjVPS29YbViOr8s4lSsFaZKLHswgqP911xx25fPOyE9+khmN6W4VeM0aevbDp4kkEoHiA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -1198,9 +970,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.3.tgz", - "integrity": "sha512-eo0iOIOvcAlWB3Z3eh8pVM8hZ0oVkK3AjEM9nSrkSug2l15qHzF3TOwT0747omI6+CJJvl7drwZepT+re6Fy/w==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -1212,12 +984,13 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.3.tgz", - "integrity": "sha512-DJay3ep76bKUDImmn//W5SvpjRN5LmK/ntWyeJs/dcnwiiHESd3N4uteK9FDLf0S0W8E6Y0sVRXpOCoQclQqNg==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1225,9 +998,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.3.tgz", - "integrity": "sha512-BKKWQkY2WgJ5MC/ayvIJTHjy0JUGb5efaHCUiG/39sSUvAYRBaO3+/EK0AZT1RF3pSj86O24GLLik9mAYu0IJg==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -1239,9 +1012,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.3.tgz", - "integrity": "sha512-Q9nVlWtKAG7ISW80OiZGxTr6rYtyDSkauHUtvkQI6TNOJjFvpj4gcH+KaJihqYInnAzEEUetPQubRwHef4exVg==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", "cpu": [ "loong64" ], @@ -1253,9 +1026,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.3.tgz", - "integrity": "sha512-2H5LmhzrpC4fFRNwknzmmTvvyJPHwESoJgyReXeFoYYuIDfBhP29TEXOkCJE/KxHi27mj7wDUClNq78ue3QEBQ==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -1267,9 +1040,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.3.tgz", - "integrity": "sha512-9S542V0ie9LCTznPYlvaeySwBeIEa7rDBgLHKZ5S9DBgcqdJYburabm8TqiqG6mrdTzfV5uttQRHcbKff9lWtA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", "cpu": [ "ppc64" ], @@ -1281,9 +1054,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.3.tgz", - "integrity": "sha512-ukxw+YH3XXpcezLgbJeasgxyTbdpnNAkrIlFGDl7t+pgCxZ89/6n1a+MxlY7CegU+nDgrgdqDelPRNQ/47zs0g==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -1295,9 +1068,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.3.tgz", - "integrity": "sha512-Iauw9UsTTvlF++FhghFJjqYxyXdggXsOqGpFBylaRopVpcbfyIIsNvkf9oGwfgIcf57z3m8+/oSYTo6HutBFNw==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -1309,9 +1082,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.3.tgz", - "integrity": "sha512-3OqKAHSEQXKdq9mQ4eajqUgNIK27VZPW3I26EP8miIzuKzCJ3aW3oEn2pzF+4/Hj/Moc0YDsOtBgT5bZ56/vcA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -1323,9 +1096,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.3.tgz", - "integrity": "sha512-0CM8dSVzVIaqMcXIFej8zZrSFLnGrAE8qlNbbHfTw1EEPnFTg1U1ekI0JdzjPyzSfUsHWtodilQQG/RA55berA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -1337,12 +1110,13 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.3.tgz", - "integrity": "sha512-+fgJE12FZMIgBaKIAGd45rxf+5ftcycANJRWk8Vz0NnMTM5rADPGuRFTYar+Mqs560xuART7XsX2lSACa1iOmQ==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1350,9 +1124,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.3.tgz", - "integrity": "sha512-tMD7NnbAolWPzQlJQJjVFh/fNH3K/KnA7K8gv2dJWCwwnaK6DFCYST1QXYWfu5V0cDwarWC8Sf/cfMHniNq21A==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -1364,9 +1138,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.3.tgz", - "integrity": "sha512-u5KsqxOxjEeIbn7bUK1MPM34jrnPwjeqgyin4/N6e/KzXKfpE9Mi0nCxcQjaM9lLmPcHmn/xx1yOjgTMtu1jWQ==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", "cpu": [ "x64" ], @@ -1378,9 +1152,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.3.tgz", - "integrity": "sha512-vo54aXwjpTtsAnb3ca7Yxs9t2INZg7QdXN/7yaoG7nPGbOBXYXQY41Km+S1Ov26vzOAzLcAjmMdjyEqS1JkVhw==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -1392,12 +1166,13 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.3.tgz", - "integrity": "sha512-HI+PIVZ+m+9AgpnY3pt6rinUdRYrGHvmVdsNQ4odNqQ/eRF78DVpMR7mOq7nW06QxpczibwBmeQzB68wJ+4W4A==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1405,9 +1180,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.3.tgz", - "integrity": "sha512-vRByotbdMo3Wdi+8oC2nVxtc3RkkFKrGaok+a62AT8lz/YBuQjaVYAS5Zcs3tPzW43Vsf9J0wehJbUY5xRSekA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -1419,9 +1194,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.3.tgz", - "integrity": "sha512-POZHq7UeuzMJljC5NjKi8vKMFN6/5EOqcX1yGntNLp7rUTpBAXQ1hW8kWPFxYLv07QMcNM75xqVLGPWQq6TKFA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -1433,12 +1208,13 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.3.tgz", - "integrity": "sha512-aPFONczE4fUFKNXszdvnd2GqKEYQdV5oEsIbKPujJmWlCI9zEsv1Otig8RKK+X9bed9gFUN6LAeN4ZcNuu4zjg==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1447,23 +1223,29 @@ }, "node_modules/@types/estree": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", - "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "version": "24.12.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" } }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, "node_modules/@types/trusted-types": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT" }, @@ -1483,7 +1265,7 @@ }, "node_modules/agent-base": { "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { @@ -1526,17 +1308,20 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.2.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { @@ -1551,7 +1336,7 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", @@ -1565,7 +1350,7 @@ }, "node_modules/anymatch/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", @@ -1578,13 +1363,13 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { @@ -1604,7 +1389,7 @@ }, "node_modules/bignumber.js": { "version": "9.3.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/bignumber.js/-/bignumber.js-9.3.1.tgz", "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", "license": "MIT", "engines": { @@ -1613,7 +1398,7 @@ }, "node_modules/binary-extensions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", @@ -1651,7 +1436,7 @@ }, "node_modules/brace-expansion": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { @@ -1660,7 +1445,7 @@ }, "node_modules/braces": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", @@ -1673,7 +1458,7 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, @@ -1720,7 +1505,7 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", @@ -1737,7 +1522,7 @@ }, "node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", @@ -1750,7 +1535,7 @@ }, "node_modules/chokidar": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", @@ -1775,7 +1560,7 @@ }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", @@ -1788,9 +1573,72 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { @@ -1802,13 +1650,13 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/concurrently": { "version": "9.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/concurrently/-/concurrently-9.2.1.tgz", "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", "dev": true, "license": "MIT", @@ -1895,7 +1743,7 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { @@ -1909,7 +1757,7 @@ }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "license": "MIT", "engines": { @@ -1918,7 +1766,7 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { @@ -1944,9 +1792,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "version": "17.3.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1973,13 +1821,13 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", "dependencies": { @@ -1994,9 +1842,9 @@ "peer": true }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "9.2.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, "node_modules/encodeurl": { @@ -2043,9 +1891,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "version": "0.27.4", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2056,37 +1904,37 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" } }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", @@ -2179,13 +2027,13 @@ } }, "node_modules/express-rate-limit": { - "version": "8.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/express-rate-limit/-/express-rate-limit-8.2.1.tgz", - "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "version": "8.3.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/express-rate-limit/-/express-rate-limit-8.3.1.tgz", + "integrity": "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==", "license": "MIT", "peer": true, "dependencies": { - "ip-address": "10.0.1" + "ip-address": "10.1.0" }, "engines": { "node": ">= 16" @@ -2199,7 +2047,7 @@ }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, @@ -2212,7 +2060,7 @@ }, "node_modules/fast-glob": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", @@ -2246,7 +2094,7 @@ }, "node_modules/fastq": { "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fastq/-/fastq-1.20.1.tgz", "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", @@ -2256,7 +2104,7 @@ }, "node_modules/fdir": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", @@ -2274,7 +2122,7 @@ }, "node_modules/fetch-blob": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fetch-blob/-/fetch-blob-3.2.0.tgz", "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", "funding": [ { @@ -2297,7 +2145,7 @@ }, "node_modules/fill-range": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", @@ -2332,7 +2180,7 @@ }, "node_modules/foreground-child": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { @@ -2348,7 +2196,7 @@ }, "node_modules/formdata-polyfill": { "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "license": "MIT", "dependencies": { @@ -2380,7 +2228,7 @@ }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, @@ -2405,7 +2253,7 @@ }, "node_modules/gaxios": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/gaxios/-/gaxios-7.1.3.tgz", "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", "license": "Apache-2.0", "dependencies": { @@ -2420,7 +2268,7 @@ }, "node_modules/gcp-metadata": { "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/gcp-metadata/-/gcp-metadata-8.1.2.tgz", "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", "license": "Apache-2.0", "dependencies": { @@ -2434,7 +2282,7 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, "license": "ISC", @@ -2483,8 +2331,9 @@ }, "node_modules/glob": { "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -2503,7 +2352,7 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", @@ -2515,17 +2364,16 @@ } }, "node_modules/google-auth-library": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz", - "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==", + "version": "10.6.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/google-auth-library/-/google-auth-library-10.6.1.tgz", + "integrity": "sha512-5awwuLrzNol+pFDmKJd0dKtZ0fPLAtoA5p7YO4ODsDu6ONJUVqbYwvv8y2ZBO5MBNp9TJXigB19710kYpBPdtA==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^7.0.0", - "gcp-metadata": "^8.0.0", - "google-logging-utils": "^1.0.0", - "gtoken": "^8.0.0", + "gaxios": "7.1.3", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", "jws": "^4.0.0" }, "engines": { @@ -2534,7 +2382,7 @@ }, "node_modules/google-logging-utils": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/google-logging-utils/-/google-logging-utils-1.1.3.tgz", "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", "license": "Apache-2.0", "engines": { @@ -2556,27 +2404,14 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "license": "ISC" }, - "node_modules/gtoken": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", - "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", - "license": "MIT", - "dependencies": { - "gaxios": "^7.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", @@ -2611,9 +2446,9 @@ } }, "node_modules/hono": { - "version": "4.12.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/hono/-/hono-4.12.3.tgz", - "integrity": "sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==", + "version": "4.12.7", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/hono/-/hono-4.12.7.tgz", + "integrity": "sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw==", "license": "MIT", "peer": true, "engines": { @@ -2643,7 +2478,7 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { @@ -2679,9 +2514,9 @@ "peer": true }, "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "version": "10.1.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "peer": true, "engines": { @@ -2700,7 +2535,7 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", @@ -2713,7 +2548,7 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", @@ -2723,7 +2558,7 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { @@ -2732,7 +2567,7 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", @@ -2745,7 +2580,7 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", @@ -2762,13 +2597,13 @@ }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "license": "BlueOak-1.0.0", "dependencies": { @@ -2782,9 +2617,9 @@ } }, "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "version": "6.2.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jose/-/jose-6.2.1.tgz", + "integrity": "sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==", "license": "MIT", "peer": true, "funding": { @@ -2793,7 +2628,7 @@ }, "node_modules/json-bigint": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "license": "MIT", "dependencies": { @@ -2816,14 +2651,14 @@ }, "node_modules/jsonc-parser": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jsonc-parser/-/jsonc-parser-3.3.1.tgz", "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "dev": true, "license": "MIT" }, "node_modules/jwa": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jwa/-/jwa-2.0.1.tgz", "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { @@ -2834,7 +2669,7 @@ }, "node_modules/jws": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jws/-/jws-4.0.1.tgz", "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { @@ -2844,7 +2679,7 @@ }, "node_modules/lit": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lit/-/lit-3.3.2.tgz", "integrity": "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==", "license": "BSD-3-Clause", "dependencies": { @@ -2855,7 +2690,7 @@ }, "node_modules/lit-element": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lit-element/-/lit-element-4.2.2.tgz", "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", "license": "BSD-3-Clause", "dependencies": { @@ -2866,7 +2701,7 @@ }, "node_modules/lit-html": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lit-html/-/lit-html-3.3.2.tgz", "integrity": "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==", "license": "BSD-3-Clause", "dependencies": { @@ -2875,13 +2710,13 @@ }, "node_modules/long": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/long/-/long-5.3.2.tgz", "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, "node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, @@ -2920,7 +2755,7 @@ }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", @@ -2930,7 +2765,7 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", @@ -2944,7 +2779,7 @@ }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", @@ -2983,12 +2818,12 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2998,23 +2833,23 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", + "version": "7.1.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ @@ -3043,7 +2878,7 @@ }, "node_modules/node-domexception": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/node-domexception/-/node-domexception-1.0.0.tgz", "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "deprecated": "Use your platform's native DOMException instead", "funding": [ @@ -3063,7 +2898,7 @@ }, "node_modules/node-fetch": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/node-fetch/-/node-fetch-3.3.2.tgz", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", "dependencies": { @@ -3081,7 +2916,7 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", @@ -3135,9 +2970,22 @@ "wrappy": "1" } }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, @@ -3153,7 +3001,7 @@ }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { @@ -3162,7 +3010,7 @@ }, "node_modules/path-scurry": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "license": "BlueOak-1.0.0", "dependencies": { @@ -3189,14 +3037,14 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", @@ -3218,9 +3066,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -3248,7 +3096,7 @@ }, "node_modules/proper-lockfile": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/proper-lockfile/-/proper-lockfile-4.1.2.tgz", "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", "dev": true, "license": "MIT", @@ -3258,16 +3106,26 @@ "signal-exit": "^3.0.2" } }, + "node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/proper-lockfile/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, "license": "ISC" }, "node_modules/protobufjs": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/protobufjs/-/protobufjs-7.5.4.tgz", "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", "hasInstallScript": true, "license": "BSD-3-Clause", @@ -3321,7 +3179,7 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ @@ -3368,7 +3226,7 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", @@ -3381,7 +3239,7 @@ }, "node_modules/readdirp/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", @@ -3394,7 +3252,7 @@ }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", @@ -3413,10 +3271,9 @@ } }, "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, + "version": "0.13.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", "engines": { "node": ">= 4" @@ -3424,7 +3281,7 @@ }, "node_modules/reusify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", @@ -3435,7 +3292,7 @@ }, "node_modules/rimraf": { "version": "5.0.10", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "license": "ISC", "dependencies": { @@ -3449,9 +3306,9 @@ } }, "node_modules/rollup": { - "version": "4.55.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.3.tgz", - "integrity": "sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA==", + "version": "4.59.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -3465,31 +3322,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.3", - "@rollup/rollup-android-arm64": "4.55.3", - "@rollup/rollup-darwin-arm64": "4.55.3", - "@rollup/rollup-darwin-x64": "4.55.3", - "@rollup/rollup-freebsd-arm64": "4.55.3", - "@rollup/rollup-freebsd-x64": "4.55.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.3", - "@rollup/rollup-linux-arm-musleabihf": "4.55.3", - "@rollup/rollup-linux-arm64-gnu": "4.55.3", - "@rollup/rollup-linux-arm64-musl": "4.55.3", - "@rollup/rollup-linux-loong64-gnu": "4.55.3", - "@rollup/rollup-linux-loong64-musl": "4.55.3", - "@rollup/rollup-linux-ppc64-gnu": "4.55.3", - "@rollup/rollup-linux-ppc64-musl": "4.55.3", - "@rollup/rollup-linux-riscv64-gnu": "4.55.3", - "@rollup/rollup-linux-riscv64-musl": "4.55.3", - "@rollup/rollup-linux-s390x-gnu": "4.55.3", - "@rollup/rollup-linux-x64-gnu": "4.55.3", - "@rollup/rollup-linux-x64-musl": "4.55.3", - "@rollup/rollup-openbsd-x64": "4.55.3", - "@rollup/rollup-openharmony-arm64": "4.55.3", - "@rollup/rollup-win32-arm64-msvc": "4.55.3", - "@rollup/rollup-win32-ia32-msvc": "4.55.3", - "@rollup/rollup-win32-x64-gnu": "4.55.3", - "@rollup/rollup-win32-x64-msvc": "4.55.3", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, @@ -3512,7 +3369,7 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ @@ -3536,7 +3393,7 @@ }, "node_modules/rxjs": { "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "dev": true, "license": "Apache-2.0", @@ -3546,7 +3403,7 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { @@ -3627,7 +3484,7 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { @@ -3639,7 +3496,7 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { @@ -3648,7 +3505,7 @@ }, "node_modules/shell-quote": { "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/shell-quote/-/shell-quote-1.8.3.tgz", "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, "license": "MIT", @@ -3737,7 +3594,7 @@ }, "node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { @@ -3749,13 +3606,13 @@ }, "node_modules/signal-polyfill": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/signal-polyfill/-/signal-polyfill-0.2.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/signal-polyfill/-/signal-polyfill-0.2.2.tgz", "integrity": "sha512-p63Y4Er5/eMQ9RHg0M0Y64NlsQKpiu6MDdhBXpyywRuWiPywhJTpKJ1iB5K2hJEbFZ0BnDS7ZkJ+0AfTuL37Rg==", "license": "Apache-2.0" }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", @@ -3774,23 +3631,26 @@ } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "5.1.2", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { @@ -3802,9 +3662,24 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { @@ -3814,10 +3689,25 @@ "node": ">=8" } }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { @@ -3827,9 +3717,18 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", @@ -3845,7 +3744,7 @@ }, "node_modules/tinyglobby": { "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", @@ -3862,7 +3761,7 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", @@ -3885,7 +3784,7 @@ }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, "license": "MIT", @@ -3895,7 +3794,7 @@ }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" @@ -3917,7 +3816,7 @@ }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", @@ -3931,7 +3830,7 @@ }, "node_modules/undici-types": { "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, @@ -3947,7 +3846,7 @@ }, "node_modules/uuid": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/uuid/-/uuid-13.0.0.tgz", "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", "dev": true, "funding": [ @@ -3971,7 +3870,7 @@ }, "node_modules/vite": { "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/vite/-/vite-7.3.1.tgz", "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", @@ -4046,7 +3945,7 @@ }, "node_modules/web-streams-polyfill": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "license": "MIT", "engines": { @@ -4055,7 +3954,7 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { @@ -4070,7 +3969,7 @@ }, "node_modules/wireit": { "version": "0.15.0-pre.2", - "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.15.0-pre.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wireit/-/wireit-0.15.0-pre.2.tgz", "integrity": "sha512-pXOTR56btrL7STFOPQgtq8MjAFWagSqs188E2FflCgcxk5uc0Xbn8CuLIR9FbqK97U3Jw6AK8zDEu/M/9ENqgA==", "dev": true, "license": "Apache-2.0", @@ -4094,7 +3993,7 @@ }, "node_modules/wireit/node_modules/balanced-match": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/balanced-match/-/balanced-match-3.0.1.tgz", "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", "dev": true, "license": "MIT", @@ -4104,7 +4003,7 @@ }, "node_modules/wireit/node_modules/brace-expansion": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-4.0.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/brace-expansion/-/brace-expansion-4.0.1.tgz", "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", "dev": true, "license": "MIT", @@ -4116,18 +4015,17 @@ } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "version": "8.1.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -4136,7 +4034,7 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", "dependencies": { @@ -4151,6 +4049,59 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrappy/-/wrappy-1.0.2.tgz", @@ -4160,7 +4111,7 @@ }, "node_modules/ws": { "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ws/-/ws-8.19.0.tgz", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", "engines": { @@ -4181,7 +4132,7 @@ }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "license": "ISC", @@ -4191,7 +4142,7 @@ }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", @@ -4210,7 +4161,7 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", @@ -4218,6 +4169,51 @@ "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/zod/-/zod-4.3.6.tgz", From 57091ebbedcdf35d5c43fabc46ef23f14370dbc5 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Thu, 12 Mar 2026 23:39:49 -0700 Subject: [PATCH 18/19] chore: fix NPM 401 error by regenerating package-lock.json via public registry --- samples/client/lit/package-lock.json | 3155 ++++++++++++++++---------- 1 file changed, 1927 insertions(+), 1228 deletions(-) diff --git a/samples/client/lit/package-lock.json b/samples/client/lit/package-lock.json index d6d5a3b19..fa7e29891 100644 --- a/samples/client/lit/package-lock.json +++ b/samples/client/lit/package-lock.json @@ -44,562 +44,2054 @@ "wireit": "^0.15.0-pre.2" } }, - "../../../renderers/markdown/markdown-it": { - "name": "@a2ui/markdown-it", - "version": "0.0.2", - "license": "Apache-2.0", + "../../../renderers/lit/node_modules/@a2ui/web_core": { + "resolved": "../../../renderers/web_core", + "link": true + }, + "../../../renderers/lit/node_modules/@lit-labs/signals": { + "version": "0.1.3", + "license": "BSD-3-Clause", "dependencies": { - "dompurify": "^3.3.1", - "markdown-it": "^14.1.0" - }, - "devDependencies": { - "@a2ui/web_core": "file:../../web_core", - "@types/dompurify": "^3.0.5", - "@types/jsdom": "^28.0.0", - "@types/markdown-it": "^14.1.2", - "@types/node": "^24.10.1", - "jsdom": "^28.1.0", - "prettier": "^3.4.2", - "typescript": "^5.8.3", - "wireit": "^0.15.0-pre.2" - }, - "peerDependencies": { - "@a2ui/web_core": "file:../../web_core" + "lit": "^2.0.0 || ^3.0.0", + "signal-polyfill": "^0.2.0" } }, - "../../../renderers/web_core": { - "name": "@a2ui/web_core", - "version": "0.8.5", - "license": "Apache-2.0", + "../../../renderers/lit/node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.5.1", + "license": "BSD-3-Clause" + }, + "../../../renderers/lit/node_modules/@lit/context": { + "version": "1.1.6", + "license": "BSD-3-Clause", "dependencies": { - "@preact/signals-core": "^1.13.0", - "zod": "^3.25.76" - }, - "devDependencies": { - "@types/node": "^24.11.0", - "typescript": "^5.8.3", - "wireit": "^0.15.0-pre.2", - "zod-to-json-schema": "^3.25.1" + "@lit/reactive-element": "^1.6.2 || ^2.1.0" } }, - "contact": { - "name": "@a2ui/contact", - "version": "0.8.1", - "license": "Apache-2.0", + "../../../renderers/lit/node_modules/@lit/reactive-element": { + "version": "2.1.2", + "license": "BSD-3-Clause", "dependencies": { - "@a2a-js/sdk": "^0.3.4", - "@a2ui/lit": "file:../../../../renderers/lit", - "@lit-labs/signals": "^0.1.3", - "@lit/context": "^1.1.4", - "@modelcontextprotocol/ext-apps": "^1.1.2", - "lit": "^3.3.1" - }, - "devDependencies": { - "dotenv": "^17.2.3", - "typescript": "^5.8.3", - "uuid": "^13.0.0", - "vite": "^7.1.11", - "wireit": "^0.15.0-pre.2" + "@lit-labs/ssr-dom-shim": "^1.5.0" } }, - "node_modules/@a2a-js/sdk": { - "version": "0.3.12", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@a2a-js/sdk/-/sdk-0.3.12.tgz", - "integrity": "sha512-iYV4rkOrAiGGN0ID54NiszHmgtBI0zJwgY3ZfsGOxwfz5CC8ERSSG1te5pwXApyqlZM+GxENad9gvmTk9oS1vQ==", - "license": "Apache-2.0", + "../../../renderers/lit/node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", "dependencies": { - "uuid": "^11.1.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@bufbuild/protobuf": "^2.10.2", - "@grpc/grpc-js": "^1.11.0", - "express": "^4.21.2 || ^5.1.0" - }, - "peerDependenciesMeta": { - "@bufbuild/protobuf": { - "optional": true - }, - "@grpc/grpc-js": { - "optional": true - }, - "express": { - "optional": true - } + "node": ">= 8" } }, - "node_modules/@a2a-js/sdk/node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], + "../../../renderers/lit/node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" + "engines": { + "node": ">= 8" } }, - "node_modules/@a2ui/contact": { - "resolved": "contact", - "link": true - }, - "node_modules/@a2ui/lit": { - "resolved": "../../../renderers/lit", - "link": true - }, - "node_modules/@a2ui/markdown-it": { - "resolved": "../../../renderers/markdown/markdown-it", - "link": true - }, - "node_modules/@a2ui/shell": { - "resolved": "shell", - "link": true - }, - "node_modules/@a2ui/web_core": { - "resolved": "../../../renderers/web_core", - "link": true - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", - "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", - "cpu": [ - "ppc64" - ], + "../../../renderers/lit/node_modules/@nodelib/fs.walk": { + "version": "1.2.8", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/android-arm/-/android-arm-0.27.4.tgz", - "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", - "cpu": [ - "arm" - ], + "../../../renderers/lit/node_modules/@types/node": { + "version": "24.11.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "undici-types": "~7.16.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", - "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", - "cpu": [ - "arm64" - ], + "../../../renderers/lit/node_modules/@types/trusted-types": { + "version": "2.0.7", + "license": "MIT" + }, + "../../../renderers/lit/node_modules/anymatch": { + "version": "3.1.3", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/android-x64/-/android-x64-0.27.4.tgz", - "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", - "cpu": [ - "x64" - ], + "../../../renderers/lit/node_modules/balanced-match": { + "version": "3.0.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">= 16" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", - "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", - "cpu": [ - "arm64" - ], + "../../../renderers/lit/node_modules/binary-extensions": { + "version": "2.3.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=18" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", - "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", - "cpu": [ - "x64" - ], + "../../../renderers/lit/node_modules/brace-expansion": { + "version": "4.0.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "balanced-match": "^3.0.0" + }, "engines": { - "node": ">=18" + "node": ">= 18" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", - "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", - "cpu": [ - "arm64" - ], + "../../../renderers/lit/node_modules/braces": { + "version": "3.0.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "fill-range": "^7.1.1" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", - "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", - "cpu": [ - "x64" - ], + "../../../renderers/lit/node_modules/chokidar": { + "version": "3.6.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": ">=18" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", - "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", - "cpu": [ - "arm" - ], + "../../../renderers/lit/node_modules/fast-glob": { + "version": "3.3.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, "engines": { - "node": ">=18" + "node": ">=8.6.0" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", - "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", - "cpu": [ - "arm64" - ], + "../../../renderers/lit/node_modules/fastq": { + "version": "1.20.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "../../../renderers/lit/node_modules/fill-range": { + "version": "7.1.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "to-regex-range": "^5.0.1" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", - "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", - "cpu": [ - "ia32" - ], + "../../../renderers/lit/node_modules/fsevents": { + "version": "2.3.3", "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { - "node": ">=18" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", - "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", - "cpu": [ - "loong64" - ], + "../../../renderers/lit/node_modules/glob-parent": { + "version": "5.1.2", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, "engines": { - "node": ">=18" + "node": ">= 6" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", - "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", - "cpu": [ - "mips64el" - ], + "../../../renderers/lit/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "../../../renderers/lit/node_modules/is-binary-path": { + "version": "2.1.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", - "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", - "cpu": [ - "ppc64" - ], + "../../../renderers/lit/node_modules/is-extglob": { + "version": "2.1.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", - "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", - "cpu": [ - "riscv64" - ], + "../../../renderers/lit/node_modules/is-glob": { + "version": "4.0.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "is-extglob": "^2.1.1" + }, "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", - "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", - "cpu": [ - "s390x" - ], + "../../../renderers/lit/node_modules/is-number": { + "version": "7.0.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=0.12.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", - "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", - "cpu": [ - "x64" - ], + "../../../renderers/lit/node_modules/jsonc-parser": { + "version": "3.3.1", + "dev": true, + "license": "MIT" + }, + "../../../renderers/lit/node_modules/lit": { + "version": "3.3.2", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "../../../renderers/lit/node_modules/lit-element": { + "version": "4.2.2", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "../../../renderers/lit/node_modules/lit-html": { + "version": "3.3.2", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "../../../renderers/lit/node_modules/merge2": { + "version": "1.4.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", - "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", - "cpu": [ - "arm64" - ], + "../../../renderers/lit/node_modules/micromatch": { + "version": "4.0.8", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, "engines": { - "node": ">=18" + "node": ">=8.6" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", - "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", - "cpu": [ - "x64" - ], + "../../../renderers/lit/node_modules/normalize-path": { + "version": "3.0.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", - "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", - "cpu": [ - "arm64" - ], + "../../../renderers/lit/node_modules/picomatch": { + "version": "2.3.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], "engines": { - "node": ">=18" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", - "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", - "cpu": [ - "x64" - ], + "../../../renderers/lit/node_modules/proper-lockfile": { + "version": "4.1.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "../../../renderers/lit/node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } ], + "license": "MIT" + }, + "../../../renderers/lit/node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">=18" + "node": ">=8.10.0" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", - "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", - "cpu": [ - "arm64" - ], + "../../../renderers/lit/node_modules/retry": { + "version": "0.12.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], "engines": { - "node": ">=18" + "node": ">= 4" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", - "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", - "cpu": [ - "x64" - ], + "../../../renderers/lit/node_modules/reusify": { + "version": "1.1.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], "engines": { - "node": ">=18" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", - "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", - "cpu": [ - "arm64" + "../../../renderers/lit/node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "../../../renderers/lit/node_modules/signal-exit": { + "version": "3.0.7", "dev": true, + "license": "ISC" + }, + "../../../renderers/lit/node_modules/signal-polyfill": { + "version": "0.2.2", + "license": "Apache-2.0" + }, + "../../../renderers/lit/node_modules/signal-utils": { + "version": "0.21.1", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "peerDependencies": { + "signal-polyfill": "^0.2.0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", - "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } + "../../../renderers/lit/node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "../../../renderers/lit/node_modules/typescript": { + "version": "5.9.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "../../../renderers/lit/node_modules/undici-types": { + "version": "7.16.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/lit/node_modules/wireit": { + "version": "0.15.0-pre.2", + "dev": true, + "license": "Apache-2.0", + "workspaces": [ + "vscode-extension", + "website" + ], + "dependencies": { + "brace-expansion": "^4.0.0", + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "jsonc-parser": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "bin": { + "wireit": "bin/wireit.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../../renderers/markdown/markdown-it": { + "name": "@a2ui/markdown-it", + "version": "0.0.2", + "license": "Apache-2.0", + "dependencies": { + "dompurify": "^3.3.1", + "markdown-it": "^14.1.0" + }, + "devDependencies": { + "@a2ui/web_core": "file:../../web_core", + "@types/dompurify": "^3.0.5", + "@types/jsdom": "^28.0.0", + "@types/markdown-it": "^14.1.2", + "@types/node": "^24.10.1", + "jsdom": "^28.1.0", + "prettier": "^3.4.2", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + }, + "peerDependencies": { + "@a2ui/web_core": "file:../../web_core" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@a2ui/web_core": { + "resolved": "../../../renderers/web_core", + "link": true + }, + "../../../renderers/markdown/markdown-it/node_modules/@acemir/cssom": { + "version": "0.9.31", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/@asamuzakjp/css-color": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.1.1", + "@csstools/css-color-parser": "^4.0.2", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@asamuzakjp/dom-selector": { + "version": "6.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.6" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/@bramus/specificity": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@csstools/color-helpers": { + "version": "6.0.2", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@csstools/css-calc": { + "version": "3.1.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@csstools/css-color-parser": { + "version": "4.0.2", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.1.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.0.28", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0" + }, + "../../../renderers/markdown/markdown-it/node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@exodus/bytes": { + "version": "1.14.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/dompurify": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/jsdom": { + "version": "28.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0", + "undici-types": "^7.21.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/linkify-it": { + "version": "5.0.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/markdown-it": { + "version": "14.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/mdurl": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/node": { + "version": "24.10.13", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/node/node_modules/undici-types": { + "version": "7.16.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/tough-cookie": { + "version": "4.0.5", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/@types/trusted-types": { + "version": "2.0.7", + "devOptional": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/agent-base": { + "version": "7.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "../../../renderers/markdown/markdown-it/node_modules/balanced-match": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/bidi-js": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/brace-expansion": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^3.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/chokidar": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/css-tree": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/cssstyle": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.0.0", + "@csstools/css-syntax-patches-for-csstree": "^1.0.28", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.6" + }, + "engines": { + "node": ">=20" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/data-urls": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/debug": { + "version": "4.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "../../../renderers/markdown/markdown-it/node_modules/decimal.js": { + "version": "10.6.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/dompurify": { + "version": "3.3.1", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/entities": { + "version": "4.5.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/fast-glob": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/fastq": { + "version": "1.20.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "../../../renderers/markdown/markdown-it/node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/https-proxy-agent": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/jsdom": { + "version": "28.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.31", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", + "@exodus/bytes": "^1.11.0", + "cssstyle": "^6.0.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "undici": "^7.21.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "../../../renderers/markdown/markdown-it/node_modules/jsdom/node_modules/entities": { + "version": "6.0.1", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/jsdom/node_modules/parse5": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/jsonc-parser": { + "version": "3.3.1", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/linkify-it": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/lru-cache": { + "version": "11.2.6", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/markdown-it": { + "version": "14.1.1", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/mdn-data": { + "version": "2.12.2", + "dev": true, + "license": "CC0-1.0" + }, + "../../../renderers/markdown/markdown-it/node_modules/mdurl": { + "version": "2.0.0", + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/parse5": { + "version": "7.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/prettier": { + "version": "3.8.1", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/proper-lockfile": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/punycode.js": { + "version": "2.3.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/reusify": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/saxes": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "../../../renderers/markdown/markdown-it/node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/symbol-tree": { + "version": "3.2.4", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/tldts": { + "version": "7.0.23", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.23" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/tldts-core": { + "version": "7.0.23", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/tough-cookie": { + "version": "6.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/tr46": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/typescript": { + "version": "5.9.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/uc.micro": { + "version": "2.1.0", + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/undici": { + "version": "7.22.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/undici-types": { + "version": "7.22.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/markdown/markdown-it/node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/webidl-conversions": { + "version": "8.0.1", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/whatwg-url": { + "version": "16.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/wireit": { + "version": "0.15.0-pre.2", + "dev": true, + "license": "Apache-2.0", + "workspaces": [ + "vscode-extension", + "website" + ], + "dependencies": { + "brace-expansion": "^4.0.0", + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "jsonc-parser": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "bin": { + "wireit": "bin/wireit.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/xml-name-validator": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "../../../renderers/markdown/markdown-it/node_modules/xmlchars": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/web_core": { + "name": "@a2ui/web_core", + "version": "0.8.5", + "license": "Apache-2.0", + "dependencies": { + "@preact/signals-core": "^1.13.0", + "zod": "^3.25.76" + }, + "devDependencies": { + "@types/node": "^24.11.0", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2", + "zod-to-json-schema": "^3.25.1" + } + }, + "../../../renderers/web_core/node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/web_core/node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/web_core/node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/web_core/node_modules/@types/node": { + "version": "24.10.15", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "../../../renderers/web_core/node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/web_core/node_modules/balanced-match": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "../../../renderers/web_core/node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../../renderers/web_core/node_modules/brace-expansion": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^3.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "../../../renderers/web_core/node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../../renderers/web_core/node_modules/chokidar": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "../../../renderers/web_core/node_modules/fast-glob": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "../../../renderers/web_core/node_modules/fastq": { + "version": "1.20.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "../../../renderers/web_core/node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../../../renderers/web_core/node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "../../../renderers/web_core/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "../../../renderers/web_core/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "../../../renderers/web_core/node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../../../renderers/web_core/node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/web_core/node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/web_core/node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "../../../renderers/web_core/node_modules/jsonc-parser": { + "version": "3.3.1", + "dev": true, + "license": "MIT" + }, + "../../../renderers/web_core/node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "../../../renderers/web_core/node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "../../../renderers/web_core/node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "../../../renderers/web_core/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "../../../renderers/web_core/node_modules/proper-lockfile": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "../../../renderers/web_core/node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "../../../renderers/web_core/node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "../../../renderers/web_core/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "../../../renderers/web_core/node_modules/reusify": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "../../../renderers/web_core/node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "../../../renderers/web_core/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "../../../renderers/web_core/node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "../../../renderers/web_core/node_modules/typescript": { + "version": "5.9.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "../../../renderers/web_core/node_modules/undici-types": { + "version": "7.16.0", + "dev": true, + "license": "MIT" + }, + "../../../renderers/web_core/node_modules/wireit": { + "version": "0.15.0-pre.2", + "dev": true, + "license": "Apache-2.0", + "workspaces": [ + "vscode-extension", + "website" + ], + "dependencies": { + "brace-expansion": "^4.0.0", + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "jsonc-parser": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "bin": { + "wireit": "bin/wireit.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../../renderers/web_core/node_modules/zod": { + "version": "3.25.76", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "../../../renderers/web_core/node_modules/zod-to-json-schema": { + "version": "3.25.1", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, + "contact": { + "name": "@a2ui/contact", + "version": "0.8.1", + "license": "Apache-2.0", + "dependencies": { + "@a2a-js/sdk": "^0.3.4", + "@a2ui/lit": "file:../../../../renderers/lit", + "@lit-labs/signals": "^0.1.3", + "@lit/context": "^1.1.4", + "@modelcontextprotocol/ext-apps": "^1.1.2", + "lit": "^3.3.1" + }, + "devDependencies": { + "dotenv": "^17.2.3", + "typescript": "^5.8.3", + "uuid": "^13.0.0", + "vite": "^7.1.11", + "wireit": "^0.15.0-pre.2" + } + }, + "node_modules/@a2a-js/sdk": { + "version": "0.3.12", + "license": "Apache-2.0", + "dependencies": { + "uuid": "^11.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@bufbuild/protobuf": "^2.10.2", + "@grpc/grpc-js": "^1.11.0", + "express": "^4.21.2 || ^5.1.0" + }, + "peerDependenciesMeta": { + "@bufbuild/protobuf": { + "optional": true + }, + "@grpc/grpc-js": { + "optional": true + }, + "express": { + "optional": true + } + } + }, + "node_modules/@a2a-js/sdk/node_modules/uuid": { + "version": "11.1.0", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/@a2ui/contact": { + "resolved": "contact", + "link": true + }, + "node_modules/@a2ui/lit": { + "resolved": "../../../renderers/lit", + "link": true + }, + "node_modules/@a2ui/markdown-it": { + "resolved": "../../../renderers/markdown/markdown-it", + "link": true + }, + "node_modules/@a2ui/shell": { + "resolved": "shell", + "link": true + }, + "node_modules/@a2ui/web_core": { + "resolved": "../../../renderers/web_core", + "link": true }, - "node_modules/@esbuild/win32-x64": { + "node_modules/@esbuild/darwin-arm64": { "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", - "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "darwin" ], "engines": { "node": ">=18" @@ -607,8 +2099,6 @@ }, "node_modules/@google/genai": { "version": "1.45.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@google/genai/-/genai-1.45.0.tgz", - "integrity": "sha512-+sNRWhKiRibVgc4OKi7aBJJ0A7RcoVD8tGG+eFkqxAWRjASDW+ktS9lLwTDnAxZICzCVoeAdu8dYLJVTX60N9w==", "license": "Apache-2.0", "dependencies": { "google-auth-library": "^10.3.0", @@ -630,8 +2120,6 @@ }, "node_modules/@hono/node-server": { "version": "1.19.11", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@hono/node-server/-/node-server-1.19.11.tgz", - "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", "license": "MIT", "peer": true, "engines": { @@ -643,8 +2131,6 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -660,8 +2146,6 @@ }, "node_modules/@lit-labs/signals": { "version": "0.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit-labs/signals/-/signals-0.1.3.tgz", - "integrity": "sha512-P0yWgH5blwVyEwBg+WFspLzeu1i0ypJP1QB0l1Omr9qZLIPsUu0p4Fy2jshOg7oQyha5n163K3GJGeUhQQ682Q==", "license": "BSD-3-Clause", "dependencies": { "lit": "^2.0.0 || ^3.0.0", @@ -670,14 +2154,10 @@ }, "node_modules/@lit-labs/ssr-dom-shim": { "version": "1.5.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.5.1.tgz", - "integrity": "sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==", "license": "BSD-3-Clause" }, "node_modules/@lit/context": { "version": "1.1.6", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit/context/-/context-1.1.6.tgz", - "integrity": "sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==", "license": "BSD-3-Clause", "dependencies": { "@lit/reactive-element": "^1.6.2 || ^2.1.0" @@ -685,8 +2165,6 @@ }, "node_modules/@lit/reactive-element": { "version": "2.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@lit/reactive-element/-/reactive-element-2.1.2.tgz", - "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", "license": "BSD-3-Clause", "dependencies": { "@lit-labs/ssr-dom-shim": "^1.5.0" @@ -694,8 +2172,6 @@ }, "node_modules/@modelcontextprotocol/ext-apps": { "version": "1.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@modelcontextprotocol/ext-apps/-/ext-apps-1.2.2.tgz", - "integrity": "sha512-qMnhIKb8tyPesl+kZU76Xz9Bi9putCO+LcgvBJ00fDdIniiLZsnQbAeTKoq+sTiYH1rba2Fvj8NPAFxij+gyxw==", "license": "MIT", "workspaces": [ "examples/*" @@ -720,8 +2196,6 @@ }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.27.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz", - "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==", "license": "MIT", "peer": true, "dependencies": { @@ -761,8 +2235,6 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { @@ -775,8 +2247,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", "engines": { @@ -785,8 +2255,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { @@ -799,8 +2267,6 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "license": "MIT", "optional": true, "engines": { @@ -809,32 +2275,22 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.1", @@ -843,66 +2299,26 @@ }, "node_modules/@protobufjs/float": { "version": "1.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "license": "BSD-3-Clause" }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -913,325 +2329,13 @@ "darwin" ] }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@types/estree": { "version": "1.0.8", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "24.12.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/node/-/node-24.12.0.tgz", - "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -1239,20 +2343,14 @@ }, "node_modules/@types/retry": { "version": "0.12.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "license": "MIT" }, "node_modules/@types/trusted-types": { "version": "2.0.7", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT" }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "peer": true, "dependencies": { @@ -1265,8 +2363,6 @@ }, "node_modules/agent-base": { "version": "7.1.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { "node": ">= 14" @@ -1274,8 +2370,6 @@ }, "node_modules/ajv": { "version": "8.18.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "peer": true, "dependencies": { @@ -1291,8 +2385,6 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "peer": true, "dependencies": { @@ -1309,8 +2401,6 @@ }, "node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -1321,8 +2411,6 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1336,8 +2424,6 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", "dependencies": { @@ -1350,8 +2436,6 @@ }, "node_modules/anymatch/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { @@ -1363,14 +2447,10 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -1389,8 +2469,6 @@ }, "node_modules/bignumber.js": { "version": "9.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", "license": "MIT", "engines": { "node": "*" @@ -1398,8 +2476,6 @@ }, "node_modules/binary-extensions": { "version": "2.3.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", "engines": { @@ -1411,8 +2487,6 @@ }, "node_modules/body-parser": { "version": "2.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "peer": true, "dependencies": { @@ -1436,8 +2510,6 @@ }, "node_modules/brace-expansion": { "version": "2.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -1445,8 +2517,6 @@ }, "node_modules/braces": { "version": "3.0.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", "dependencies": { @@ -1458,14 +2528,10 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "peer": true, "engines": { @@ -1474,8 +2540,6 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "peer": true, "dependencies": { @@ -1488,8 +2552,6 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "peer": true, "dependencies": { @@ -1505,7 +2567,7 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/chalk/-/chalk-4.1.2.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", @@ -1522,7 +2584,7 @@ }, "node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/supports-color/-/supports-color-7.2.0.tgz", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", @@ -1535,8 +2597,6 @@ }, "node_modules/chokidar": { "version": "3.6.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", "dependencies": { @@ -1560,7 +2620,7 @@ }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cliui/-/cliui-8.0.1.tgz", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", @@ -1575,7 +2635,7 @@ }, "node_modules/cliui/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", @@ -1585,14 +2645,14 @@ }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", @@ -1607,7 +2667,7 @@ }, "node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", @@ -1620,7 +2680,7 @@ }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", @@ -1638,8 +2698,6 @@ }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1650,13 +2708,11 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/concurrently": { "version": "9.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/concurrently/-/concurrently-9.2.1.tgz", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", "dev": true, "license": "MIT", @@ -1681,8 +2737,6 @@ }, "node_modules/content-disposition": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", "peer": true, "engines": { @@ -1695,8 +2749,6 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "peer": true, "engines": { @@ -1705,8 +2757,6 @@ }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "peer": true, "engines": { @@ -1715,8 +2765,6 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "peer": true, "engines": { @@ -1725,8 +2773,6 @@ }, "node_modules/cors": { "version": "2.8.6", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "peer": true, "dependencies": { @@ -1743,8 +2789,6 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1757,8 +2801,6 @@ }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "license": "MIT", "engines": { "node": ">= 12" @@ -1766,8 +2808,6 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1783,8 +2823,6 @@ }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "peer": true, "engines": { @@ -1793,8 +2831,6 @@ }, "node_modules/dotenv": { "version": "17.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/dotenv/-/dotenv-17.3.1.tgz", - "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1806,8 +2842,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "peer": true, "dependencies": { @@ -1821,14 +2855,10 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -1836,21 +2866,15 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT", "peer": true }, "node_modules/emoji-regex": { "version": "9.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "peer": true, "engines": { @@ -1859,8 +2883,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "peer": true, "engines": { @@ -1869,8 +2891,6 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "peer": true, "engines": { @@ -1879,8 +2899,6 @@ }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "peer": true, "dependencies": { @@ -1892,8 +2910,6 @@ }, "node_modules/esbuild": { "version": "0.27.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/esbuild/-/esbuild-0.27.4.tgz", - "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1934,7 +2950,7 @@ }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/escalade/-/escalade-3.2.0.tgz", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", @@ -1944,15 +2960,11 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT", "peer": true }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "peer": true, "engines": { @@ -1961,8 +2973,6 @@ }, "node_modules/eventsource": { "version": "3.0.7", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "license": "MIT", "peer": true, "dependencies": { @@ -1974,8 +2984,6 @@ }, "node_modules/eventsource-parser": { "version": "3.0.6", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "license": "MIT", "peer": true, "engines": { @@ -1984,8 +2992,6 @@ }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "peer": true, "dependencies": { @@ -2028,8 +3034,6 @@ }, "node_modules/express-rate-limit": { "version": "8.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/express-rate-limit/-/express-rate-limit-8.3.1.tgz", - "integrity": "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==", "license": "MIT", "peer": true, "dependencies": { @@ -2047,21 +3051,15 @@ }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT", "peer": true }, "node_modules/fast-glob": { "version": "3.3.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { @@ -2077,8 +3075,6 @@ }, "node_modules/fast-uri": { "version": "3.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -2094,8 +3090,6 @@ }, "node_modules/fastq": { "version": "1.20.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", "dependencies": { @@ -2104,8 +3098,6 @@ }, "node_modules/fdir": { "version": "6.5.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", "engines": { @@ -2122,8 +3114,6 @@ }, "node_modules/fetch-blob": { "version": "3.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", "funding": [ { "type": "github", @@ -2145,8 +3135,6 @@ }, "node_modules/fill-range": { "version": "7.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { @@ -2158,8 +3146,6 @@ }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "peer": true, "dependencies": { @@ -2180,8 +3166,6 @@ }, "node_modules/foreground-child": { "version": "3.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -2196,8 +3180,6 @@ }, "node_modules/formdata-polyfill": { "version": "4.0.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "license": "MIT", "dependencies": { "fetch-blob": "^3.1.2" @@ -2208,8 +3190,6 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "peer": true, "engines": { @@ -2218,8 +3198,6 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "peer": true, "engines": { @@ -2228,10 +3206,7 @@ }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -2243,8 +3218,6 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "peer": true, "funding": { @@ -2253,8 +3226,6 @@ }, "node_modules/gaxios": { "version": "7.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/gaxios/-/gaxios-7.1.3.tgz", - "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", @@ -2268,8 +3239,6 @@ }, "node_modules/gcp-metadata": { "version": "8.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", "license": "Apache-2.0", "dependencies": { "gaxios": "^7.0.0", @@ -2282,7 +3251,7 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/get-caller-file/-/get-caller-file-2.0.5.tgz", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, "license": "ISC", @@ -2292,8 +3261,6 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "peer": true, "dependencies": { @@ -2317,8 +3284,6 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "peer": true, "dependencies": { @@ -2331,9 +3296,6 @@ }, "node_modules/glob": { "version": "10.5.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -2352,8 +3314,6 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { @@ -2365,8 +3325,6 @@ }, "node_modules/google-auth-library": { "version": "10.6.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/google-auth-library/-/google-auth-library-10.6.1.tgz", - "integrity": "sha512-5awwuLrzNol+pFDmKJd0dKtZ0fPLAtoA5p7YO4ODsDu6ONJUVqbYwvv8y2ZBO5MBNp9TJXigB19710kYpBPdtA==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", @@ -2382,8 +3340,6 @@ }, "node_modules/google-logging-utils": { "version": "1.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -2391,8 +3347,6 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "peer": true, "engines": { @@ -2404,14 +3358,12 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/has-flag/-/has-flag-4.0.0.tgz", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", @@ -2421,8 +3373,6 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "peer": true, "engines": { @@ -2434,8 +3384,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "peer": true, "dependencies": { @@ -2447,8 +3395,6 @@ }, "node_modules/hono": { "version": "4.12.7", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/hono/-/hono-4.12.7.tgz", - "integrity": "sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw==", "license": "MIT", "peer": true, "engines": { @@ -2457,8 +3403,6 @@ }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "peer": true, "dependencies": { @@ -2478,8 +3422,6 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -2491,8 +3433,6 @@ }, "node_modules/iconv-lite": { "version": "0.7.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "peer": true, "dependencies": { @@ -2508,15 +3448,11 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC", "peer": true }, "node_modules/ip-address": { "version": "10.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "peer": true, "engines": { @@ -2525,8 +3461,6 @@ }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "peer": true, "engines": { @@ -2535,8 +3469,6 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", "dependencies": { @@ -2548,8 +3480,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", "engines": { @@ -2558,8 +3488,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -2567,8 +3495,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", "dependencies": { @@ -2580,8 +3506,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", "engines": { @@ -2590,21 +3514,15 @@ }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT", "peer": true }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -2618,8 +3536,6 @@ }, "node_modules/jose": { "version": "6.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jose/-/jose-6.2.1.tgz", - "integrity": "sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==", "license": "MIT", "peer": true, "funding": { @@ -2628,8 +3544,6 @@ }, "node_modules/json-bigint": { "version": "1.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "license": "MIT", "dependencies": { "bignumber.js": "^9.0.0" @@ -2637,29 +3551,21 @@ }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT", "peer": true }, "node_modules/json-schema-typed": { "version": "8.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", "license": "BSD-2-Clause", "peer": true }, "node_modules/jsonc-parser": { "version": "3.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "dev": true, "license": "MIT" }, "node_modules/jwa": { "version": "2.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -2669,8 +3575,6 @@ }, "node_modules/jws": { "version": "4.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { "jwa": "^2.0.1", @@ -2679,8 +3583,6 @@ }, "node_modules/lit": { "version": "3.3.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lit/-/lit-3.3.2.tgz", - "integrity": "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==", "license": "BSD-3-Clause", "dependencies": { "@lit/reactive-element": "^2.1.0", @@ -2690,8 +3592,6 @@ }, "node_modules/lit-element": { "version": "4.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lit-element/-/lit-element-4.2.2.tgz", - "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", "license": "BSD-3-Clause", "dependencies": { "@lit-labs/ssr-dom-shim": "^1.5.0", @@ -2701,8 +3601,6 @@ }, "node_modules/lit-html": { "version": "3.3.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lit-html/-/lit-html-3.3.2.tgz", - "integrity": "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==", "license": "BSD-3-Clause", "dependencies": { "@types/trusted-types": "^2.0.2" @@ -2710,20 +3608,14 @@ }, "node_modules/long": { "version": "5.3.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, "node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "peer": true, "engines": { @@ -2732,8 +3624,6 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "peer": true, "engines": { @@ -2742,8 +3632,6 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "peer": true, "engines": { @@ -2755,8 +3643,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", "engines": { @@ -2765,8 +3651,6 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -2779,8 +3663,6 @@ }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { @@ -2792,8 +3674,6 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "peer": true, "engines": { @@ -2802,8 +3682,6 @@ }, "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "peer": true, "dependencies": { @@ -2819,8 +3697,6 @@ }, "node_modules/minimatch": { "version": "9.0.9", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.2" @@ -2834,8 +3710,6 @@ }, "node_modules/minipass": { "version": "7.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" @@ -2843,14 +3717,10 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.11", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -2868,8 +3738,6 @@ }, "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "peer": true, "engines": { @@ -2878,9 +3746,6 @@ }, "node_modules/node-domexception": { "version": "1.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", "funding": [ { "type": "github", @@ -2898,8 +3763,6 @@ }, "node_modules/node-fetch": { "version": "3.3.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -2916,8 +3779,6 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", "engines": { @@ -2926,8 +3787,6 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "peer": true, "engines": { @@ -2936,8 +3795,6 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "peer": true, "engines": { @@ -2949,8 +3806,6 @@ }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "peer": true, "dependencies": { @@ -2962,8 +3817,6 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "peer": true, "dependencies": { @@ -2972,8 +3825,6 @@ }, "node_modules/p-retry": { "version": "4.6.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "license": "MIT", "dependencies": { "@types/retry": "0.12.0", @@ -2985,14 +3836,10 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "peer": true, "engines": { @@ -3001,8 +3848,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -3010,8 +3855,6 @@ }, "node_modules/path-scurry": { "version": "1.11.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -3026,8 +3869,6 @@ }, "node_modules/path-to-regexp": { "version": "8.3.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", "peer": true, "funding": { @@ -3037,15 +3878,11 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -3057,8 +3894,6 @@ }, "node_modules/pkce-challenge": { "version": "5.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "license": "MIT", "peer": true, "engines": { @@ -3067,8 +3902,6 @@ }, "node_modules/postcss": { "version": "8.5.8", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -3096,8 +3929,6 @@ }, "node_modules/proper-lockfile": { "version": "4.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", "dev": true, "license": "MIT", "dependencies": { @@ -3108,8 +3939,6 @@ }, "node_modules/proper-lockfile/node_modules/retry": { "version": "0.12.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, "license": "MIT", "engines": { @@ -3118,15 +3947,11 @@ }, "node_modules/proper-lockfile/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, "license": "ISC" }, "node_modules/protobufjs": { "version": "7.5.4", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -3149,8 +3974,6 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "peer": true, "dependencies": { @@ -3163,8 +3986,6 @@ }, "node_modules/qs": { "version": "6.15.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "peer": true, "dependencies": { @@ -3179,8 +4000,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -3200,8 +4019,6 @@ }, "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "peer": true, "engines": { @@ -3210,8 +4027,6 @@ }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "peer": true, "dependencies": { @@ -3226,8 +4041,6 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", "dependencies": { @@ -3239,8 +4052,6 @@ }, "node_modules/readdirp/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { @@ -3252,7 +4063,7 @@ }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/require-directory/-/require-directory-2.1.1.tgz", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", @@ -3262,8 +4073,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "peer": true, "engines": { @@ -3272,8 +4081,6 @@ }, "node_modules/retry": { "version": "0.13.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", "engines": { "node": ">= 4" @@ -3281,8 +4088,6 @@ }, "node_modules/reusify": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -3292,8 +4097,6 @@ }, "node_modules/rimraf": { "version": "5.0.10", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "license": "ISC", "dependencies": { "glob": "^10.3.7" @@ -3307,8 +4110,6 @@ }, "node_modules/rollup": { "version": "4.59.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -3352,8 +4153,6 @@ }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "peer": true, "dependencies": { @@ -3369,8 +4168,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -3393,7 +4190,7 @@ }, "node_modules/rxjs": { "version": "7.8.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/rxjs/-/rxjs-7.8.2.tgz", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "dev": true, "license": "Apache-2.0", @@ -3403,8 +4200,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -3423,15 +4218,11 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT", "peer": true }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "peer": true, "dependencies": { @@ -3457,8 +4248,6 @@ }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "peer": true, "dependencies": { @@ -3477,15 +4266,11 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC", "peer": true }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3496,8 +4281,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" @@ -3505,7 +4288,7 @@ }, "node_modules/shell-quote": { "version": "1.8.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/shell-quote/-/shell-quote-1.8.3.tgz", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, "license": "MIT", @@ -3518,8 +4301,6 @@ }, "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "peer": true, "dependencies": { @@ -3538,8 +4319,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "peer": true, "dependencies": { @@ -3555,8 +4334,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "peer": true, "dependencies": { @@ -3574,8 +4351,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "peer": true, "dependencies": { @@ -3594,8 +4369,6 @@ }, "node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { "node": ">=14" @@ -3606,14 +4379,10 @@ }, "node_modules/signal-polyfill": { "version": "0.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/signal-polyfill/-/signal-polyfill-0.2.2.tgz", - "integrity": "sha512-p63Y4Er5/eMQ9RHg0M0Y64NlsQKpiu6MDdhBXpyywRuWiPywhJTpKJ1iB5K2hJEbFZ0BnDS7ZkJ+0AfTuL37Rg==", "license": "Apache-2.0" }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -3622,8 +4391,6 @@ }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "peer": true, "engines": { @@ -3632,8 +4399,6 @@ }, "node_modules/string-width": { "version": "5.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -3650,8 +4415,6 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3664,8 +4427,6 @@ }, "node_modules/string-width-cjs/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -3673,14 +4434,10 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3691,8 +4448,6 @@ }, "node_modules/strip-ansi": { "version": "7.2.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -3707,8 +4462,6 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3719,8 +4472,6 @@ }, "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -3728,7 +4479,7 @@ }, "node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/supports-color/-/supports-color-8.1.1.tgz", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", @@ -3744,8 +4495,6 @@ }, "node_modules/tinyglobby": { "version": "0.2.15", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3761,8 +4510,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3774,8 +4521,6 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "peer": true, "engines": { @@ -3784,7 +4529,7 @@ }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/tree-kill/-/tree-kill-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, "license": "MIT", @@ -3794,15 +4539,13 @@ }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/tslib/-/tslib-2.8.1.tgz", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, "node_modules/type-is": { "version": "2.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "peer": true, "dependencies": { @@ -3816,8 +4559,6 @@ }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3830,14 +4571,10 @@ }, "node_modules/undici-types": { "version": "7.16.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "peer": true, "engines": { @@ -3846,8 +4583,6 @@ }, "node_modules/uuid": { "version": "13.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/uuid/-/uuid-13.0.0.tgz", - "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -3860,8 +4595,6 @@ }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "peer": true, "engines": { @@ -3870,8 +4603,6 @@ }, "node_modules/vite": { "version": "7.3.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { @@ -3945,8 +4676,6 @@ }, "node_modules/web-streams-polyfill": { "version": "3.3.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "license": "MIT", "engines": { "node": ">= 8" @@ -3954,8 +4683,6 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -3969,8 +4696,6 @@ }, "node_modules/wireit": { "version": "0.15.0-pre.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wireit/-/wireit-0.15.0-pre.2.tgz", - "integrity": "sha512-pXOTR56btrL7STFOPQgtq8MjAFWagSqs188E2FflCgcxk5uc0Xbn8CuLIR9FbqK97U3Jw6AK8zDEu/M/9ENqgA==", "dev": true, "license": "Apache-2.0", "workspaces": [ @@ -3993,8 +4718,6 @@ }, "node_modules/wireit/node_modules/balanced-match": { "version": "3.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/balanced-match/-/balanced-match-3.0.1.tgz", - "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", "dev": true, "license": "MIT", "engines": { @@ -4003,8 +4726,6 @@ }, "node_modules/wireit/node_modules/brace-expansion": { "version": "4.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/brace-expansion/-/brace-expansion-4.0.1.tgz", - "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", "dev": true, "license": "MIT", "dependencies": { @@ -4016,8 +4737,6 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -4034,8 +4753,6 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -4051,8 +4768,6 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -4060,14 +4775,10 @@ }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -4080,8 +4791,6 @@ }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4092,8 +4801,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -4104,15 +4811,11 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC", "peer": true }, "node_modules/ws": { "version": "8.19.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -4132,7 +4835,7 @@ }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/y18n/-/y18n-5.0.8.tgz", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "license": "ISC", @@ -4142,7 +4845,7 @@ }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/yargs/-/yargs-17.7.2.tgz", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", @@ -4161,7 +4864,7 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/yargs-parser/-/yargs-parser-21.1.1.tgz", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", @@ -4171,7 +4874,7 @@ }, "node_modules/yargs/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", @@ -4181,14 +4884,14 @@ }, "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/string-width/-/string-width-4.2.3.tgz", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", @@ -4203,7 +4906,7 @@ }, "node_modules/yargs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", @@ -4216,8 +4919,6 @@ }, "node_modules/zod": { "version": "4.3.6", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "peer": true, "funding": { @@ -4226,8 +4927,6 @@ }, "node_modules/zod-to-json-schema": { "version": "3.25.1", - "resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", "license": "ISC", "peer": true, "peerDependencies": { From dd1d84695d4b33a57d1e4ab7b7229e1ae65f92e7 Mon Sep 17 00:00:00 2001 From: Mandar Deolalikar <11888634+dmandar@users.noreply.github.com> Date: Fri, 13 Mar 2026 10:51:46 -0700 Subject: [PATCH 19/19] chore: revert non-functional pyink formatting outside sample scope and fix a2ui schema validation for multi-surface payloads --- .../python/src/a2ui/core/schema/manager.py | 9 +- .../python/src/a2ui/core/schema/utils.py | 10 + .../python/src/a2ui/core/schema/validator.py | 66 +- .../tests/core/schema/test_validator.py | 118 +- docs/scripts/convert_docs.py | 51 +- docs/scripts/test_convert_docs.py | 50 +- renderers/angular/.npmrc | 2 + renderers/lit/.npmrc | 2 + .../lit/src/0.8/ui/directives/markdown.ts | 5 +- renderers/markdown/markdown-it/.npmrc | 2 + .../adk/component_gallery/gallery_examples.py | 16 +- samples/agent/adk/rizzcharts/agent.py | 9 +- samples/agent/mcp/server.py | 254 ++-- samples/personalized_learning/agent/agent.py | 24 +- .../agent/download_openstax.py | 8 +- .../agent/openstax_chapters.py | 171 +-- .../agent/openstax_content.py | 67 +- .../agent/openstax_modules.py | 1302 ++++------------- samples/personalized_learning/deploy.py | 630 ++------ .../personalized_learning/deploy_hosting.py | 312 ++-- specification/scripts/validate.py | 100 +- specification/v0_10/test/run_tests.py | 56 +- specification/v0_9/test/run_tests.py | 57 +- tools/build_catalog/build_catalog.py | 94 +- .../build_catalog/tests/test_build_catalog.py | 132 +- 25 files changed, 1050 insertions(+), 2497 deletions(-) create mode 100644 renderers/angular/.npmrc create mode 100644 renderers/lit/.npmrc create mode 100644 renderers/markdown/markdown-it/.npmrc diff --git a/agent_sdks/python/src/a2ui/core/schema/manager.py b/agent_sdks/python/src/a2ui/core/schema/manager.py index 5a92c8787..97e9eefd4 100644 --- a/agent_sdks/python/src/a2ui/core/schema/manager.py +++ b/agent_sdks/python/src/a2ui/core/schema/manager.py @@ -19,7 +19,7 @@ import importlib.resources from typing import List, Dict, Any, Optional, Callable from dataclasses import dataclass, field -from .utils import load_from_bundled_resource +from .utils import load_from_bundled_resource, deep_update from ..inference_strategy import InferenceStrategy from .constants import * from .catalog import CatalogConfig, A2uiCatalog @@ -146,10 +146,15 @@ def _select_catalog( # Load the first inline catalog schema. inline_catalog_schema = inline_catalogs[0] inline_catalog_schema = self._apply_modifiers(inline_catalog_schema) + + # Deep merge the standard catalog properties with the inline catalog + merged_schema = copy.deepcopy(self._supported_catalogs[0].catalog_schema) + deep_update(merged_schema, inline_catalog_schema) + return A2uiCatalog( version=self._version, name=INLINE_CATALOG_NAME, - catalog_schema=inline_catalog_schema, + catalog_schema=merged_schema, s2c_schema=self._server_to_client_schema, common_types_schema=self._common_types_schema, ) diff --git a/agent_sdks/python/src/a2ui/core/schema/utils.py b/agent_sdks/python/src/a2ui/core/schema/utils.py index f68ce85b7..193a289c0 100644 --- a/agent_sdks/python/src/a2ui/core/schema/utils.py +++ b/agent_sdks/python/src/a2ui/core/schema/utils.py @@ -117,3 +117,13 @@ def wrap_as_json_array(a2ui_schema: dict[str, Any]) -> dict[str, Any]: if not a2ui_schema: raise ValueError("A2UI schema is empty") return {"type": "array", "items": a2ui_schema} + + +def deep_update(d: dict, u: dict) -> dict: + """Recursively update a dict with another dict.""" + for k, v in u.items(): + if isinstance(v, dict): + d[k] = deep_update(d.get(k, {}), v) + else: + d[k] = v + return d diff --git a/agent_sdks/python/src/a2ui/core/schema/validator.py b/agent_sdks/python/src/a2ui/core/schema/validator.py index 07c1b968a..5bd37624d 100644 --- a/agent_sdks/python/src/a2ui/core/schema/validator.py +++ b/agent_sdks/python/src/a2ui/core/schema/validator.py @@ -274,31 +274,35 @@ def validate(self, a2ui_json: Union[Dict[str, Any], List[Any]]) -> None: msg += f"\n - {sub_error.message}" raise ValueError(msg) - root_id = _find_root_id(messages) - for message in messages: if not isinstance(message, dict): continue components = None + surface_id = None if "surfaceUpdate" in message: # v0.8 components = message["surfaceUpdate"].get(COMPONENTS) + surface_id = message["surfaceUpdate"].get("surfaceId") elif "updateComponents" in message and isinstance( message["updateComponents"], dict ): # v0.9 components = message["updateComponents"].get(COMPONENTS) + surface_id = message["updateComponents"].get("surfaceId") if components: ref_map = _extract_component_ref_fields(self._catalog) + root_id = _find_root_id(messages, surface_id) _validate_component_integrity(root_id, components, ref_map) _validate_topology(root_id, components, ref_map) _validate_recursion_and_paths(message) -def _find_root_id(messages: List[Dict[str, Any]]) -> str: +def _find_root_id( + messages: List[Dict[str, Any]], surface_id: Optional[str] = None +) -> Optional[str]: """ - Finds the root id from a list of A2UI messages. + Finds the root id from a list of A2UI messages for a given surface. - For v0.8, the root id is in the beginRendering message. - For v0.9+, the root id is 'root'. """ @@ -306,12 +310,18 @@ def _find_root_id(messages: List[Dict[str, Any]]) -> str: if not isinstance(message, dict): continue if "beginRendering" in message: + if surface_id and message["beginRendering"].get("surfaceId") != surface_id: + continue return message["beginRendering"].get(ROOT, ROOT) - return ROOT + if "createSurface" in message: + if surface_id and message["createSurface"].get("surfaceId") != surface_id: + continue + return ROOT + return None def _validate_component_integrity( - root_id: str, + root_id: Optional[str], components: List[Dict[str, Any]], ref_fields_map: Dict[str, tuple[Set[str], Set[str]]], ) -> None: @@ -334,21 +344,23 @@ def _validate_component_integrity( ids.add(comp_id) # 2. Check for root component - if root_id not in ids: + if root_id is not None and root_id not in ids: raise ValueError(f"Missing root component: No component has id='{root_id}'") # 3. Check for dangling references using helper - for comp in components: - for ref_id, field_name in _get_component_references(comp, ref_fields_map): - if ref_id not in ids: - raise ValueError( - f"Component '{comp.get(ID)}' references non-existent component '{ref_id}'" - f" in field '{field_name}'" - ) + # In an incremental update (root_id is None), components may reference IDs already on the client. + if root_id is not None: + for comp in components: + for ref_id, field_name in _get_component_references(comp, ref_fields_map): + if ref_id not in ids: + raise ValueError( + f"Component '{comp.get(ID)}' references non-existent component '{ref_id}'" + f" in field '{field_name}'" + ) def _validate_topology( - root_id: str, + root_id: Optional[str], components: List[Dict[str, Any]], ref_fields_map: Dict[str, tuple[Set[str], Set[str]]], ) -> None: @@ -401,16 +413,22 @@ def dfs(node_id: str, depth: int): recursion_stack.remove(node_id) - if root_id in all_ids: - dfs(root_id, 0) + if root_id is not None: + if root_id in all_ids: + dfs(root_id, 0) - # Check for Orphans - orphans = all_ids - visited - if orphans: - sorted_orphans = sorted(list(orphans)) - raise ValueError( - f"Component '{sorted_orphans[0]}' is not reachable from '{root_id}'" - ) + # Check for Orphans + orphans = all_ids - visited + if orphans: + sorted_orphans = sorted(list(orphans)) + raise ValueError( + f"Component '{sorted_orphans[0]}' is not reachable from '{root_id}'" + ) + else: + # Partial update: we cannot check root reachability, but we still check for cycles + for node_id in all_ids: + if node_id not in visited: + dfs(node_id, 0) def _extract_component_ref_fields( diff --git a/agent_sdks/python/tests/core/schema/test_validator.py b/agent_sdks/python/tests/core/schema/test_validator.py index d46d093fa..47224b794 100644 --- a/agent_sdks/python/tests/core/schema/test_validator.py +++ b/agent_sdks/python/tests/core/schema/test_validator.py @@ -48,7 +48,10 @@ def catalog_0_9(self): "catalogId": { "type": "string", }, - "theme": {"type": "object", "additionalProperties": True}, + "theme": { + "type": "object", + "additionalProperties": True, + }, }, "required": ["surfaceId", "catalogId"], "additionalProperties": False, @@ -495,7 +498,10 @@ def test_custom_catalog_0_8(self, catalog_0_8): "children": { "type": "object", "properties": { - "explicitList": {"type": "array", "items": {"type": "string"}} + "explicitList": { + "type": "array", + "items": {"type": "string"}, + } }, "required": ["explicitList"], } @@ -723,30 +729,53 @@ def make_payload(self, catalog, components=None, data_model=None): processed.append(comp) if catalog.version == VERSION_0_8: - payload = { - "surfaceUpdate": {"surfaceId": "test-surface", "components": processed} - } + payload = [ + {"beginRendering": {"surfaceId": "test-surface", "root": "root"}}, + { + "surfaceUpdate": { + "surfaceId": "test-surface", + "components": processed, + } + }, + ] else: - payload = { - "version": "v0.9", - "updateComponents": {"surfaceId": "test-surface", "components": processed}, - } + payload = [ + { + "version": "v0.9", + "createSurface": {"surfaceId": "test-surface", "catalogId": "std"}, + }, + { + "version": "v0.9", + "updateComponents": { + "surfaceId": "test-surface", + "components": processed, + }, + }, + ] elif data_model: if catalog.version == VERSION_0_8: - payload = { - "dataModelUpdate": {"surfaceId": "test-surface", "contents": data_model} - } + payload = [ + { + "dataModelUpdate": { + "surfaceId": "test-surface", + "contents": data_model, + } + } + ] else: - payload = { + payload = [{ "version": "v0.9", - "updateDataModel": {"surfaceId": "test-surface", "value": data_model}, - } + "updateDataModel": { + "surfaceId": "test-surface", + "value": data_model, + }, + }] if payload is None: - return [] if catalog.version == VERSION_0_9 else {} + return [] - return [payload] if catalog.version == VERSION_0_9 else payload + return payload def test_validate_duplicate_ids(self, test_catalog): components = [ @@ -762,20 +791,29 @@ def test_validate_missing_root(self, test_catalog): # This payload has components but none are 'root' # bypass make_payload as it adds root if missing if test_catalog.version == VERSION_0_8: - payload = { - "surfaceUpdate": { - "surfaceId": "test", - "components": [{"id": "c1", "component": {"Text": {"text": "hi"}}}], - } - } + payload = [ + {"beginRendering": {"surfaceId": "test", "root": "root"}}, + { + "surfaceUpdate": { + "surfaceId": "test", + "components": [{"id": "c1", "component": {"Text": {"text": "hi"}}}], + } + }, + ] else: - payload = [{ - "version": "v0.9", - "updateComponents": { - "surfaceId": "test", - "components": [{"id": "c1", "component": "Text", "text": "hi"}], + payload = [ + { + "version": "v0.9", + "createSurface": {"surfaceId": "test", "catalogId": "std"}, + }, + { + "version": "v0.9", + "updateComponents": { + "surfaceId": "test", + "components": [{"id": "c1", "component": "Text", "text": "hi"}], + }, }, - }] + ] with pytest.raises(ValueError, match="Missing root component"): test_catalog.validator.validate(payload) @@ -915,12 +953,9 @@ def test_validate_v08_custom_root_reachability(self, test_catalog): {"id": "custom-root", "component": "Text", "text": "I am the root"}, {"id": "orphan", "component": "Text", "text": "I am an orphan"}, ] - # make_payload only gives us surfaceUpdate, we need to wrap it with beginRendering - surface_update = self.make_payload(test_catalog, components=components) - payload = [ - {"beginRendering": {"surfaceId": "test-surface", "root": "custom-root"}}, - surface_update, - ] + # make_payload gives us both beginRendering and surfaceUpdate. We just need to change root. + payload = self.make_payload(test_catalog, components=components) + payload[0]["beginRendering"]["root"] = "custom-root" # This should fail because 'orphan' is not reachable from 'custom-root' with pytest.raises( @@ -933,13 +968,8 @@ def test_validate_v08_custom_root_reachability(self, test_catalog): {"id": "custom-root", "component": "Card", "child": "orphan"}, {"id": "orphan", "component": "Text", "text": "I am no longer an orphan"}, ] - surface_update_connected = self.make_payload( - test_catalog, components=components_connected - ) - payload_connected = [ - {"beginRendering": {"surfaceId": "test-surface", "root": "custom-root"}}, - surface_update_connected, - ] + payload_connected = self.make_payload(test_catalog, components=components_connected) + payload_connected[0]["beginRendering"]["root"] = "custom-root" test_catalog.validator.validate(payload_connected) @pytest.mark.parametrize( @@ -985,8 +1015,8 @@ def test_validate_invalid_paths(self, test_catalog, payload): p[0]["updateDataModel"]["path"] = data.get("path") p[0]["updateDataModel"]["surfaceId"] = data.get("surfaceId", "surface1") else: - p["dataModelUpdate"]["path"] = data.get("path") - p["dataModelUpdate"]["surfaceId"] = data.get("surfaceId", "surface1") + p[0]["dataModelUpdate"]["path"] = data.get("path") + p[0]["dataModelUpdate"]["surfaceId"] = data.get("surfaceId", "surface1") with pytest.raises( ValueError, diff --git a/docs/scripts/convert_docs.py b/docs/scripts/convert_docs.py index ffdaed7f5..a82b72ac0 100644 --- a/docs/scripts/convert_docs.py +++ b/docs/scripts/convert_docs.py @@ -17,9 +17,9 @@ import argparse # Registry for bidirectional format conversion: -# +# # Key: The MkDocs admonition type (the target for '!!! type' syntax). -# Value: +# Value: # - emoji: Used for mapping GitHub-style emoji quotes (> ⚠️) to MkDocs. # - tag: Reserved for mapping official GitHub Alert syntax (> [!WARNING]). MAPPING = { @@ -28,19 +28,17 @@ "info": {"emoji": "ℹ️", "tag": "NOTE"}, "success": {"emoji": "✅", "tag": "SUCCESS"}, "danger": {"emoji": "🚫", "tag": "CAUTION"}, - "note": {"emoji": "📝", "tag": "NOTE"}, + "note": {"emoji": "📝", "tag": "NOTE"} } # Reverse lookup: mapping emojis back to their respective MkDocs types EMOJI_TO_TYPE = {v["emoji"]: k for k, v in MAPPING.items()} # Emoji Pattern: Handles optional bold titles and standard emojis -EMOJI_PATTERN = r">\s*(⚠️|💡|ℹ️|✅|🚫|📝)(?:\s*\*\*(.*?)\*\*)?\s*\n((?:>\s*.*\n?)*)" +EMOJI_PATTERN = r'>\s*(⚠️|💡|ℹ️|✅|🚫|📝)(?:\s*\*\*(.*?)\*\*)?\s*\n((?:>\s*.*\n?)*)' # GitHub Alert Pattern [!TYPE] -GITHUB_ALERT_PATTERN = ( - r">\s*\[\!(WARNING|TIP|NOTE|IMPORTANT|CAUTION)\]\s*\n((?:>\s*.*\n?)*)" -) +GITHUB_ALERT_PATTERN = r'>\s*\[\!(WARNING|TIP|NOTE|IMPORTANT|CAUTION)\]\s*\n((?:>\s*.*\n?)*)' # MkDocs Pattern: Captures '!!! type "Title"' blocks MKDOCS_PATTERN = r'!!!\s+(\w+)\s+"(.*?)"\n((?:\s{4}.*\n?)*)' @@ -55,29 +53,28 @@ def clean_body_for_mkdocs(body_text): 4. Preserves internal paragraph breaks. """ # Remove leading '>' and trailing whitespace from each line - raw_lines = [re.sub(r"^>\s?", "", line).rstrip() for line in body_text.split("\n")] - + raw_lines = [re.sub(r'^>\s?', '', line).rstrip() for line in body_text.split('\n')] + # Find the first line with actual text (to strip leading blank lines) start_idx = -1 for i, line in enumerate(raw_lines): if line.strip(): start_idx = i break - + if start_idx == -1: return "" - + # Slice from the first content line content_lines = raw_lines[start_idx:] - + # Join lines and rstrip the entire block to remove trailing blank lines body = "\n".join([f" {l}".rstrip() for l in content_lines]).rstrip() return body - def to_mkdocs(content): """Converts GitHub style to MkDocs style.""" - + def emoji_replacer(match): emoji_char, title, raw_body = match.groups() adm_type = EMOJI_TO_TYPE.get(emoji_char, "note") @@ -86,17 +83,18 @@ def emoji_replacer(match): # Return block with exactly one newline at the end return f'!!! {adm_type} "{title_val}"\n{body}\n' + def alert_replacer(match): alert_type = match.group(1).lower() type_map = {"important": "info", "caution": "danger"} mkdocs_type = type_map.get(alert_type, alert_type) raw_body = match.group(2) - - first_line_match = re.search(r"^>\s*\*\*(.*?)\*\*\s*\n", raw_body) + + first_line_match = re.search(r'^>\s*\*\*(.*?)\*\*\s*\n', raw_body) title = first_line_match.group(1) if first_line_match else "" if first_line_match: - raw_body = raw_body[first_line_match.end() :] - + raw_body = raw_body[first_line_match.end():] + body = clean_body_for_mkdocs(raw_body) return f'!!! {mkdocs_type} "{title}"\n{body}\n' @@ -104,29 +102,24 @@ def alert_replacer(match): content = re.sub(GITHUB_ALERT_PATTERN, alert_replacer, content, flags=re.MULTILINE) return content - def process_file(path): - with open(path, "r", encoding="utf-8") as f: + with open(path, 'r', encoding='utf-8') as f: content = f.read() new_content = to_mkdocs(content) if new_content != content: - with open(path, "w", encoding="utf-8") as f: + with open(path, 'w', encoding='utf-8') as f: f.write(new_content) print(f"[CONVERTED] {path}") - def run_conversion(): - for root, dirs, files in os.walk("docs"): - if any(x in root for x in ["scripts", "assets", "__pycache__"]): + for root, dirs, files in os.walk('docs'): + if any(x in root for x in ['scripts', 'assets', '__pycache__']): continue for file in files: - if file.endswith(".md"): + if file.endswith('.md'): process_file(os.path.join(root, file)) - if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="GitHub to MkDocs Markdown Admonition Converter" - ) + parser = argparse.ArgumentParser(description="GitHub to MkDocs Markdown Admonition Converter") args = parser.parse_args() run_conversion() diff --git a/docs/scripts/test_convert_docs.py b/docs/scripts/test_convert_docs.py index 6ab9114ae..03bae2d3e 100644 --- a/docs/scripts/test_convert_docs.py +++ b/docs/scripts/test_convert_docs.py @@ -18,26 +18,21 @@ # --- 1. A2UI Specific Header Cases --- ADMONITION_CASES = [ ('!!! info "Coming soon..."', "Coming soon...", "ℹ️"), - ( - '!!! warning "Status: Early Stage Public Preview"', - "Status: Early Stage Public Preview", - "⚠️", - ), + ('!!! warning "Status: Early Stage Public Preview"', "Status: Early Stage Public Preview", "⚠️"), ('!!! success "Stable Release"', "Stable Release", "✅"), ('!!! note "Version Compatibility"', "Version Compatibility", "📝"), ('!!! warning "Attention"', "Attention", "⚠️"), ('!!! tip "It\'s Just JSON"', "It's Just JSON", "💡"), ] - @pytest.mark.parametrize("expected_header, title, emoji", ADMONITION_CASES) def test_standard_a2ui_conversion(expected_header, title, emoji): """Verifies that GitHub style converts to expected A2UI headers.""" body = " Line 1\n Line 2" github_input = f"> {emoji} **{title}**\n>\n> Line 1\n> Line 2\n" - + expected = f"{expected_header}\n{body}\n" - + # GitHub -> MkDocs result = to_mkdocs(github_input) assert result.strip() == expected.strip() @@ -50,7 +45,7 @@ def test_empty_title_case(): """ github_input = "> 💡\n>\n> Content.\n" expected = '!!! tip ""\n Content.\n' - + result = to_mkdocs(github_input) assert result == expected @@ -65,17 +60,22 @@ def test_paragraph_spacing_and_trailing_lines(): """ source_github = ( "> ✅ **Stable Release**\n" - ">\n" # Spacer line + ">\n" # Spacer line "> Line 1\n" - ">\n" # Internal break + ">\n" # Internal break "> Line 2\n" - ">\n" # Trailing line 1 - ">\n" # Trailing line 2 + ">\n" # Trailing line 1 + ">\n" # Trailing line 2 ) - + result = to_mkdocs(source_github) - - expected = '!!! success "Stable Release"\n' " Line 1\n" "\n" " Line 2\n" + + expected = ( + '!!! success "Stable Release"\n' + ' Line 1\n' + '\n' + ' Line 2\n' + ) assert result == expected @@ -83,17 +83,21 @@ def test_paragraph_spacing_and_trailing_lines(): def test_multiple_blocks_in_one_file(): """Ensures multiple blocks are processed without bleeding into each other.""" github_input = ( - "> ✅ **Block 1**\n" "> Content 1\n" "\n" "> ℹ️ **Block 2**\n" "> Content 2\n" + '> ✅ **Block 1**\n' + '> Content 1\n' + '\n' + '> ℹ️ **Block 2**\n' + '> Content 2\n' ) - + expected = ( '!!! success "Block 1"\n' - " Content 1\n" - "\n" + ' Content 1\n' + '\n' '!!! info "Block 2"\n' - " Content 2\n" + ' Content 2\n' ) - + result = to_mkdocs(github_input) assert result == expected @@ -110,5 +114,5 @@ def test_github_alert_to_mkdocs(): """Verifies official [!TYPE] syntax conversion.""" source = "> [!WARNING]\n> **Security Notice**\n> Do not share keys." expected = '!!! warning "Security Notice"\n Do not share keys.\n' - + assert to_mkdocs(source) == expected diff --git a/renderers/angular/.npmrc b/renderers/angular/.npmrc new file mode 100644 index 000000000..06b0eef7e --- /dev/null +++ b/renderers/angular/.npmrc @@ -0,0 +1,2 @@ +@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ +//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/renderers/lit/.npmrc b/renderers/lit/.npmrc new file mode 100644 index 000000000..06b0eef7e --- /dev/null +++ b/renderers/lit/.npmrc @@ -0,0 +1,2 @@ +@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ +//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/renderers/lit/src/0.8/ui/directives/markdown.ts b/renderers/lit/src/0.8/ui/directives/markdown.ts index 9a3b20330..d909ac823 100644 --- a/renderers/lit/src/0.8/ui/directives/markdown.ts +++ b/renderers/lit/src/0.8/ui/directives/markdown.ts @@ -58,10 +58,7 @@ class MarkdownDirective extends Directive { }) // The until directive lets us render a placeholder *until* the rendered // content resolves. - return until( - rendered, - html`${value}` - ); + return until(rendered, html`${value}`); } if (!MarkdownDirective.defaultMarkdownWarningLogged) { diff --git a/renderers/markdown/markdown-it/.npmrc b/renderers/markdown/markdown-it/.npmrc new file mode 100644 index 000000000..06b0eef7e --- /dev/null +++ b/renderers/markdown/markdown-it/.npmrc @@ -0,0 +1,2 @@ +@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ +//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/samples/agent/adk/component_gallery/gallery_examples.py b/samples/agent/adk/component_gallery/gallery_examples.py index 65e5e788e..f241ea320 100644 --- a/samples/agent/adk/component_gallery/gallery_examples.py +++ b/samples/agent/adk/component_gallery/gallery_examples.py @@ -54,10 +54,7 @@ def add_demo_surface(surface_id, component_def): # Inject data model for this surface messages.append({ - "dataModelUpdate": { - "surfaceId": surface_id, - "contents": [gallery_data_content], - } + "dataModelUpdate": {"surfaceId": surface_id, "contents": [gallery_data_content]} }) # 1. TextField @@ -307,11 +304,7 @@ def add_demo_surface(surface_id, component_def): "component": { "Column": { "children": { - "explicitList": [ - "div-text-1", - "div-horiz", - "div-text-2", - ] + "explicitList": ["div-text-1", "div-horiz", "div-text-2"] }, "distribution": "start", "alignment": "stretch", @@ -322,10 +315,7 @@ def add_demo_surface(surface_id, component_def): "id": "div-text-1", "component": {"Text": {"text": {"literalString": "Above Divider"}}}, }, - { - "id": "div-horiz", - "component": {"Divider": {"axis": "horizontal"}}, - }, + {"id": "div-horiz", "component": {"Divider": {"axis": "horizontal"}}}, { "id": "div-text-2", "component": {"Text": {"text": {"literalString": "Below Divider"}}}, diff --git a/samples/agent/adk/rizzcharts/agent.py b/samples/agent/adk/rizzcharts/agent.py index 26f92c738..850b6cc12 100644 --- a/samples/agent/adk/rizzcharts/agent.py +++ b/samples/agent/adk/rizzcharts/agent.py @@ -194,14 +194,7 @@ def get_agent_card(self) -> AgentCard: "Displays a map showing regional sales outliers or store-level" " performance." ), - tags=[ - "sales", - "regional", - "outliers", - "stores", - "map", - "performance", - ], + tags=["sales", "regional", "outliers", "stores", "map", "performance"], examples=[ "interesting. were there any outlier stores", "show me a map of store performance", diff --git a/samples/agent/mcp/server.py b/samples/agent/mcp/server.py index cef4b5492..5d4958571 100644 --- a/samples/agent/mcp/server.py +++ b/samples/agent/mcp/server.py @@ -26,32 +26,32 @@ def load_a2ui_schema() -> dict[str, Any]: - current_dir = pathlib.Path(__file__).resolve().parent - spec_root = current_dir / "../../../specification/v0_8/json" + current_dir = pathlib.Path(__file__).resolve().parent + spec_root = current_dir / "../../../specification/v0_8/json" - server_to_client_content = (spec_root / "server_to_client.json").read_text() - server_to_client_json = json.loads(server_to_client_content) + server_to_client_content = (spec_root / "server_to_client.json").read_text() + server_to_client_json = json.loads(server_to_client_content) - standard_catalog_content = ( - spec_root / "standard_catalog_definition.json" - ).read_text() - standard_catalog_json = json.loads(standard_catalog_content) + standard_catalog_content = ( + spec_root / "standard_catalog_definition.json" + ).read_text() + standard_catalog_json = json.loads(standard_catalog_content) - server_to_client_json["properties"]["surfaceUpdate"]["properties"]["components"][ - "items" - ]["properties"]["component"]["properties"] = standard_catalog_json + server_to_client_json["properties"]["surfaceUpdate"]["properties"]["components"][ + "items" + ]["properties"]["component"]["properties"] = standard_catalog_json - return wrap_as_json_array(server_to_client_json) + return wrap_as_json_array(server_to_client_json) def load_a2ui_client_to_server_schema() -> dict[str, Any]: - current_dir = pathlib.Path(__file__).resolve().parent - spec_root = current_dir / "../../../specification/v0_8/json" + current_dir = pathlib.Path(__file__).resolve().parent + spec_root = current_dir / "../../../specification/v0_8/json" - client_to_server_content = (spec_root / "client_to_server.json").read_text() - client_to_server_json = json.loads(client_to_server_content) + client_to_server_content = (spec_root / "client_to_server.json").read_text() + client_to_server_json = json.loads(client_to_server_content) - return client_to_server_json + return client_to_server_json @click.command() @@ -63,130 +63,124 @@ def load_a2ui_client_to_server_schema() -> dict[str, Any]: help="Transport type", ) def main(port: int, transport: str) -> int: - a2ui_schema = load_a2ui_schema() - print(f"Loaded A2UI schema: {a2ui_schema}") + a2ui_schema = load_a2ui_schema() + print(f"Loaded A2UI schema: {a2ui_schema}") - recipe_a2ui_json = json.loads( - (pathlib.Path(__file__).resolve().parent / "recipe_a2ui.json").read_text() - ) - jsonschema.validate(instance=recipe_a2ui_json, schema=a2ui_schema) - print(f"Loaded Recipe A2UI JSON: {recipe_a2ui_json}") + recipe_a2ui_json = json.loads( + (pathlib.Path(__file__).resolve().parent / "recipe_a2ui.json").read_text() + ) + jsonschema.validate(instance=recipe_a2ui_json, schema=a2ui_schema) + print(f"Loaded Recipe A2UI JSON: {recipe_a2ui_json}") - a2ui_client_to_server_schema = load_a2ui_client_to_server_schema() - print(f"Loaded A2UI client to server schema: {a2ui_client_to_server_schema}") + a2ui_client_to_server_schema = load_a2ui_client_to_server_schema() + print(f"Loaded A2UI client to server schema: {a2ui_client_to_server_schema}") - app = Server("a2ui-over-mcp-demo") + app = Server("a2ui-over-mcp-demo") - @app.call_tool() - async def handle_call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]: - if name == "get_recipe_a2ui": - return {"events": recipe_a2ui_json} + @app.call_tool() + async def handle_call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]: + if name == "get_recipe_a2ui": + return {"events": recipe_a2ui_json} - if name == "send_a2ui_user_action": - return {"response": f"Received A2UI user action", "args": arguments} + if name == "send_a2ui_user_action": + return {"response": f"Received A2UI user action", "args": arguments} - if name == "send_a2ui_error": - return {"response": f"Received A2UI error", "args": arguments} + if name == "send_a2ui_error": + return {"response": f"Received A2UI error", "args": arguments} - raise ValueError(f"Unknown tool: {name}") + raise ValueError(f"Unknown tool: {name}") - @app.list_resources() - async def list_resources() -> list[types.Resource]: - return [ - types.Resource( - uri="ui://calculator/app", - name="Calculator App", - mimeType="text/html;profile=mcp-app", - description="A simple calculator application", - ) - ] - - @app.read_resource() - async def read_resource(uri: Any) -> str | bytes: - if str(uri) == "ui://calculator/app": - return ( - pathlib.Path(__file__).parent / "apps" / "calculator.html" - ).read_text() - raise ValueError(f"Unknown resource: {uri}") - - @app.list_tools() - async def list_tools() -> list[types.Tool]: - return [ - types.Tool( - name="get_recipe_a2ui", - title="Get Recipe A2UI", - description="Returns the A2UI JSON to show a recipe", - inputSchema={"type": "object", "additionalProperties": False}, - # MCP throws an error for "type":"array" so wrapping in an object - # TODO fix this in MCP SDK - outputSchema={ - "type": "object", - "properties": {"events": a2ui_schema}, - "required": ["events"], - "additionalProperties": False, - }, - ), - types.Tool( - name="send_a2ui_user_action", - title="Send A2UI User Action", - description="Sends an A2UI user action", - inputSchema=a2ui_client_to_server_schema["properties"]["userAction"], - ), - types.Tool( - name="send_a2ui_error", - title="Send A2UI Error", - description="Sends an A2UI error", - inputSchema=a2ui_client_to_server_schema["properties"]["error"], - ), - ] - - if transport == "sse": - from mcp.server.sse import SseServerTransport - from starlette.applications import Starlette - from starlette.responses import Response - from starlette.routing import Mount, Route - from starlette.middleware import Middleware - from starlette.middleware.cors import CORSMiddleware - - sse = SseServerTransport("/messages/") - - async def handle_sse(request: Request): - async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage] - await app.run( - streams[0], streams[1], app.create_initialization_options() - ) - return Response() - - starlette_app = Starlette( - debug=True, - routes=[ - Route("/sse", endpoint=handle_sse, methods=["GET"]), - Mount("/messages/", app=sse.handle_post_message), - ], - middleware=[ - Middleware( - CORSMiddleware, - allow_origins=["*"], - allow_methods=["*"], - allow_headers=["*"], - ) - ], + @app.list_resources() + async def list_resources() -> list[types.Resource]: + return [ + types.Resource( + uri="ui://calculator/app", + name="Calculator App", + mimeType="text/html;profile=mcp-app", + description="A simple calculator application", ) + ] + + @app.read_resource() + async def read_resource(uri: Any) -> str | bytes: + if str(uri) == "ui://calculator/app": + return (pathlib.Path(__file__).parent / "apps" / "calculator.html").read_text() + raise ValueError(f"Unknown resource: {uri}") + + @app.list_tools() + async def list_tools() -> list[types.Tool]: + return [ + types.Tool( + name="get_recipe_a2ui", + title="Get Recipe A2UI", + description="Returns the A2UI JSON to show a recipe", + inputSchema={"type": "object", "additionalProperties": False}, + # MCP throws an error for "type":"array" so wrapping in an object + # TODO fix this in MCP SDK + outputSchema={ + "type": "object", + "properties": {"events": a2ui_schema}, + "required": ["events"], + "additionalProperties": False, + }, + ), + types.Tool( + name="send_a2ui_user_action", + title="Send A2UI User Action", + description="Sends an A2UI user action", + inputSchema=a2ui_client_to_server_schema["properties"]["userAction"], + ), + types.Tool( + name="send_a2ui_error", + title="Send A2UI Error", + description="Sends an A2UI error", + inputSchema=a2ui_client_to_server_schema["properties"]["error"], + ), + ] + + if transport == "sse": + from mcp.server.sse import SseServerTransport + from starlette.applications import Starlette + from starlette.responses import Response + from starlette.routing import Mount, Route + from starlette.middleware import Middleware + from starlette.middleware.cors import CORSMiddleware + + sse = SseServerTransport("/messages/") + + async def handle_sse(request: Request): + async with sse.connect_sse(request.scope, request.receive, request._send) as streams: # type: ignore[reportPrivateUsage] + await app.run(streams[0], streams[1], app.create_initialization_options()) + return Response() + + starlette_app = Starlette( + debug=True, + routes=[ + Route("/sse", endpoint=handle_sse, methods=["GET"]), + Mount("/messages/", app=sse.handle_post_message), + ], + middleware=[ + Middleware( + CORSMiddleware, + allow_origins=["*"], + allow_methods=["*"], + allow_headers=["*"], + ) + ], + ) - import uvicorn + import uvicorn - print(f"Server running at 127.0.0.1:{port} using sse") - uvicorn.run(starlette_app, host="127.0.0.1", port=port) - else: - from mcp.server.stdio import stdio_server + print(f"Server running at 127.0.0.1:{port} using sse") + uvicorn.run(starlette_app, host="127.0.0.1", port=port) + else: + from mcp.server.stdio import stdio_server - async def arun(): - async with stdio_server() as streams: - await app.run( - streams[0], streams[1], app.create_initialization_options() - ) + async def arun(): + async with stdio_server() as streams: + await app.run(streams[0], streams[1], app.create_initialization_options()) - click.echo("Server running using stdio", err=True) - anyio.run(arun) + click.echo("Server running using stdio", err=True) + anyio.run(arun) - return 0 + return 0 diff --git a/samples/personalized_learning/agent/agent.py b/samples/personalized_learning/agent/agent.py index 6035cbf9d..39db9cb09 100644 --- a/samples/personalized_learning/agent/agent.py +++ b/samples/personalized_learning/agent/agent.py @@ -36,8 +36,8 @@ # Try multiple possible .env locations env_paths = [ Path(__file__).parent.parent / ".env", # samples/personalized_learning/.env - Path(__file__).parent / ".env", # agent/.env - Path.cwd() / ".env", # current working directory + Path(__file__).parent / ".env", # agent/.env + Path.cwd() / ".env", # current working directory ] for env_path in env_paths: if env_path.exists(): @@ -63,7 +63,6 @@ from .context_loader import get_combined_context, load_context_file from .a2ui_templates import get_system_prompt, SURFACE_ID as _IMPORTED_SURFACE_ID from .openstax_content import fetch_content_for_topic - _HAS_EXTERNAL_MODULES = True _HAS_OPENSTAX = True except Exception as e: @@ -79,7 +78,7 @@ logger.error( "Required modules (context_loader, a2ui_templates) not available. " "Import error: %s", - _IMPORT_ERROR if "_IMPORT_ERROR" in globals() else "unknown", + _IMPORT_ERROR if '_IMPORT_ERROR' in globals() else "unknown" ) if not _HAS_OPENSTAX: @@ -98,6 +97,7 @@ SURFACE_ID = _IMPORTED_SURFACE_ID if _HAS_EXTERNAL_MODULES else "learningContent" + # Context cache with TTL for performance _CONTEXT_CACHE: dict[str, Tuple[str, float]] = {} _CONTEXT_CACHE_TTL = 300 # 5 minutes @@ -216,15 +216,12 @@ async def generate_flashcards( openstax_content = content_result.get("combined_content", "") sources = content_result.get("sources", []) matched_chapters = content_result.get("matched_chapters", []) - logger.info( - f"OpenStax: matched {len(matched_chapters)} chapters, {len(openstax_content)} chars" - ) + logger.info(f"OpenStax: matched {len(matched_chapters)} chapters, {len(openstax_content)} chars") if not openstax_content: logger.warning("NO CONTENT RETURNED from OpenStax fetch!") except Exception as e: logger.error(f"FAILED to fetch OpenStax content: {e}") import traceback - logger.error(traceback.format_exc()) # Combine learner context with OpenStax source material @@ -372,7 +369,9 @@ async def get_audio_content( }, { "id": "audioIcon", - "component": {"Icon": {"name": {"literalString": "podcasts"}}}, + "component": { + "Icon": {"name": {"literalString": "podcasts"}} + }, }, { "id": "audioTitle", @@ -587,9 +586,7 @@ async def _generate_a2ui_content( if not project: logger.error("GOOGLE_CLOUD_PROJECT not configured") - return { - "error": "GOOGLE_CLOUD_PROJECT not configured. Set it in environment or deploy.py." - } + return {"error": "GOOGLE_CLOUD_PROJECT not configured. Set it in environment or deploy.py."} client = genai.Client( vertexai=True, @@ -703,7 +700,6 @@ async def _generate_a2ui_content( and explain the content to the learner. """ - def create_agent() -> Agent: """Create the ADK agent with all tools.""" return Agent( @@ -723,3 +719,5 @@ def create_agent() -> Agent: # Module-level agent for local development with `adk web` root_agent = create_agent() + + diff --git a/samples/personalized_learning/agent/download_openstax.py b/samples/personalized_learning/agent/download_openstax.py index b277e0f4b..33d354a98 100644 --- a/samples/personalized_learning/agent/download_openstax.py +++ b/samples/personalized_learning/agent/download_openstax.py @@ -140,9 +140,7 @@ def upload_module(module_id: str) -> tuple[str, bool, str]: # Use thread pool for parallel uploads with ThreadPoolExecutor(max_workers=workers) as executor: - futures = { - executor.submit(upload_module, mid): mid for mid in sorted(module_ids) - } + futures = {executor.submit(upload_module, mid): mid for mid in sorted(module_ids)} for future in as_completed(futures): module_id, success, message = future.result() @@ -304,9 +302,7 @@ def main(): local_success, local_fail = copy_modules_locally( modules_dir, local_dir, needed_modules ) - print( - f"Local copy complete: {local_success} succeeded, {local_fail} failed" - ) + print(f"Local copy complete: {local_success} succeeded, {local_fail} failed") # Upload to GCS if not local-only if not args.local_only and args.bucket: diff --git a/samples/personalized_learning/agent/openstax_chapters.py b/samples/personalized_learning/agent/openstax_chapters.py index 222ee04d6..c41a12745 100644 --- a/samples/personalized_learning/agent/openstax_chapters.py +++ b/samples/personalized_learning/agent/openstax_chapters.py @@ -34,9 +34,7 @@ """ # GitHub raw content base URL for fetching module content -GITHUB_RAW_BASE = ( - "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" -) +GITHUB_RAW_BASE = "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" # OpenStax website base URL for citations OPENSTAX_WEB_BASE = "https://openstax.org/books/biology-ap-courses/pages" @@ -54,6 +52,7 @@ "3-3-lipids": "Lipids", "3-4-proteins": "Proteins", "3-5-nucleic-acids": "Nucleic Acids", + # Unit 2: The Cell "4-1-studying-cells": "Studying Cells", "4-2-prokaryotic-cells": "Prokaryotic Cells", @@ -89,6 +88,7 @@ "10-3-control-of-the-cell-cycle": "Control of the Cell Cycle", "10-4-cancer-and-the-cell-cycle": "Cancer and the Cell Cycle", "10-5-prokaryotic-cell-division": "Prokaryotic Cell Division", + # Unit 3: Genetics "11-1-the-process-of-meiosis": "The Process of Meiosis", "11-2-sexual-reproduction": "Sexual Reproduction", @@ -120,6 +120,7 @@ "17-3-whole-genome-sequencing": "Whole-Genome Sequencing", "17-4-applying-genomics": "Applying Genomics", "17-5-genomics-and-proteomics": "Genomics and Proteomics", + # Unit 4: Evolutionary Processes "18-1-understanding-evolution": "Understanding Evolution", "18-2-formation-of-new-species": "Formation of New Species", @@ -130,6 +131,7 @@ "20-1-organizing-life-on-earth": "Organizing Life on Earth", "20-2-determining-evolutionary-relationships": "Determining Evolutionary Relationships", "20-3-perspectives-on-the-phylogenetic-tree": "Perspectives on the Phylogenetic Tree", + # Unit 5: Biological Diversity "21-1-viral-evolution-morphology-and-classification": "Viral Evolution, Morphology, and Classification", "21-2-virus-infection-and-hosts": "Virus Infection and Hosts", @@ -140,6 +142,7 @@ "22-3-prokaryotic-metabolism": "Prokaryotic Metabolism", "22-4-bacterial-diseases-in-humans": "Bacterial Diseases in Humans", "22-5-beneficial-prokaryotes": "Beneficial Prokaryotes", + # Unit 6: Plant Structure and Function "23-1-the-plant-body": "The Plant Body", "23-2-stems": "Stems", @@ -147,6 +150,7 @@ "23-4-leaves": "Leaves", "23-5-transport-of-water-and-solutes-in-plants": "Transport of Water and Solutes in Plants", "23-6-plant-sensory-systems-and-responses": "Plant Sensory Systems and Responses", + # Unit 7: Animal Structure and Function "24-1-animal-form-and-function": "Animal Form and Function", "24-2-animal-primary-tissues": "Animal Primary Tissues", @@ -198,6 +202,7 @@ "34-5-fertilization-and-early-embryonic-development": "Fertilization and Early Embryonic Development", "34-6-organogenesis-and-vertebrate-axis-formation": "Organogenesis and Vertebrate Axis Formation", "34-7-human-pregnancy-and-birth": "Human Pregnancy and Birth", + # Unit 8: Ecology "35-1-the-scope-of-ecology": "The Scope of Ecology", "35-2-biogeography": "Biogeography", @@ -220,7 +225,6 @@ "38-4-preserving-biodiversity": "Preserving Biodiversity", } - # Build a formatted string for LLM context def get_chapter_list_for_llm() -> str: """Return a formatted list of all chapters for LLM context.""" @@ -239,19 +243,13 @@ def get_chapter_list_for_llm() -> str: "adenosine triphosphate": ["6-4-atp-adenosine-triphosphate"], "adp": ["6-4-atp-adenosine-triphosphate"], "adenosine diphosphate": ["6-4-atp-adenosine-triphosphate"], - "cellular energy": [ - "6-4-atp-adenosine-triphosphate", - "7-1-energy-in-living-systems", - ], + "cellular energy": ["6-4-atp-adenosine-triphosphate", "7-1-energy-in-living-systems"], "cell energy": ["6-4-atp-adenosine-triphosphate", "7-1-energy-in-living-systems"], "high energy bond": ["6-4-atp-adenosine-triphosphate"], "phosphate bond": ["6-4-atp-adenosine-triphosphate"], "phosphate group": ["6-4-atp-adenosine-triphosphate"], "energy currency": ["6-4-atp-adenosine-triphosphate"], - "energy transfer": [ - "6-4-atp-adenosine-triphosphate", - "7-4-oxidative-phosphorylation", - ], + "energy transfer": ["6-4-atp-adenosine-triphosphate", "7-4-oxidative-phosphorylation"], "bond breaking": ["6-4-atp-adenosine-triphosphate"], "bond energy": ["6-4-atp-adenosine-triphosphate", "6-1-energy-and-metabolism"], "hydrolysis": ["6-4-atp-adenosine-triphosphate"], @@ -263,19 +261,13 @@ def get_chapter_list_for_llm() -> str: "first law": ["6-3-the-laws-of-thermodynamics"], "second law": ["6-3-the-laws-of-thermodynamics"], "entropy": ["6-3-the-laws-of-thermodynamics"], - "photosynthesis": [ - "8-1-overview-of-photosynthesis", - "8-2-the-light-dependent-reaction-of-photosynthesis", - ], + "photosynthesis": ["8-1-overview-of-photosynthesis", "8-2-the-light-dependent-reaction-of-photosynthesis"], "plants make food": ["8-1-overview-of-photosynthesis"], "chloroplast": ["8-1-overview-of-photosynthesis", "4-3-eukaryotic-cells"], "chlorophyll": ["8-2-the-light-dependent-reaction-of-photosynthesis"], "calvin cycle": ["8-3-using-light-to-make-organic-molecules"], "light reaction": ["8-2-the-light-dependent-reaction-of-photosynthesis"], - "cellular respiration": [ - "7-1-energy-in-living-systems", - "7-4-oxidative-phosphorylation", - ], + "cellular respiration": ["7-1-energy-in-living-systems", "7-4-oxidative-phosphorylation"], "glycolysis": ["7-2-glycolysis"], "krebs": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle"], "citric acid": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle"], @@ -286,25 +278,21 @@ def get_chapter_list_for_llm() -> str: "anaerobic": ["7-5-metabolism-without-oxygen"], "mitochondria": ["7-4-oxidative-phosphorylation", "4-3-eukaryotic-cells"], "mitochondrion": ["7-4-oxidative-phosphorylation", "4-3-eukaryotic-cells"], + # Cell Division "mitosis": ["10-1-cell-division", "10-2-the-cell-cycle"], "meiosis": ["11-1-the-process-of-meiosis"], "cell cycle": ["10-2-the-cell-cycle", "10-3-control-of-the-cell-cycle"], "cell division": ["10-1-cell-division"], "cancer": ["10-4-cancer-and-the-cell-cycle", "16-7-cancer-and-gene-regulation"], + # Molecular Biology "dna": ["14-2-dna-structure-and-sequencing", "14-3-basics-of-dna-replication"], "rna": ["15-4-rna-processing-in-eukaryotes", "3-5-nucleic-acids"], - "mrna": [ - "15-4-rna-processing-in-eukaryotes", - "15-5-ribosomes-and-protein-synthesis", - ], + "mrna": ["15-4-rna-processing-in-eukaryotes", "15-5-ribosomes-and-protein-synthesis"], "trna": ["15-5-ribosomes-and-protein-synthesis"], "rrna": ["15-5-ribosomes-and-protein-synthesis"], - "transcription": [ - "15-2-prokaryotic-transcription", - "15-3-eukaryotic-transcription", - ], + "transcription": ["15-2-prokaryotic-transcription", "15-3-eukaryotic-transcription"], "translation": ["15-5-ribosomes-and-protein-synthesis"], "protein synthesis": ["15-5-ribosomes-and-protein-synthesis"], "protein": ["3-4-proteins", "15-5-ribosomes-and-protein-synthesis"], @@ -315,10 +303,8 @@ def get_chapter_list_for_llm() -> str: "codon": ["15-1-the-genetic-code"], "anticodon": ["15-5-ribosomes-and-protein-synthesis"], "ribosome": ["15-5-ribosomes-and-protein-synthesis", "4-3-eukaryotic-cells"], - "replication": [ - "14-3-basics-of-dna-replication", - "14-4-dna-replication-in-prokaryotes", - ], + "replication": ["14-3-basics-of-dna-replication", "14-4-dna-replication-in-prokaryotes"], + # Cell Structure "cell membrane": ["5-1-components-and-structure"], "plasma membrane": ["5-1-components-and-structure"], @@ -336,39 +322,31 @@ def get_chapter_list_for_llm() -> str: "vesicle": ["5-4-bulk-transport", "4-4-the-endomembrane-system-and-proteins"], "endocytosis": ["5-4-bulk-transport"], "exocytosis": ["5-4-bulk-transport"], - "signal transduction": [ - "9-1-signaling-molecules-and-cellular-receptors", - "9-2-propagation-of-the-signal", - ], + "signal transduction": ["9-1-signaling-molecules-and-cellular-receptors", "9-2-propagation-of-the-signal"], "cell signaling": ["9-1-signaling-molecules-and-cellular-receptors"], + # Nervous System "neuron": ["26-1-neurons-and-glial-cells", "26-2-how-neurons-communicate"], - "nervous system": [ - "26-1-neurons-and-glial-cells", - "26-3-the-central-nervous-system", - ], + "nervous system": ["26-1-neurons-and-glial-cells", "26-3-the-central-nervous-system"], "brain": ["26-3-the-central-nervous-system"], "action potential": ["26-2-how-neurons-communicate"], "synapse": ["26-2-how-neurons-communicate"], "senses": ["27-1-sensory-processes"], "vision": ["27-5-vision"], "hearing": ["27-4-hearing-and-vestibular-sensation"], + # Circulatory System - "heart": [ - "31-1-overview-of-the-circulatory-system", - "31-3-mammalian-heart-and-blood-vessels", - ], - "blood": [ - "31-2-components-of-the-blood", - "31-1-overview-of-the-circulatory-system", - ], + "heart": ["31-1-overview-of-the-circulatory-system", "31-3-mammalian-heart-and-blood-vessels"], + "blood": ["31-2-components-of-the-blood", "31-1-overview-of-the-circulatory-system"], "circulatory": ["31-1-overview-of-the-circulatory-system"], "cardiovascular": ["31-1-overview-of-the-circulatory-system"], + # Immune System "immune": ["33-1-innate-immune-response", "33-2-adaptive-immune-response"], "antibod": ["33-3-antibodies"], "infection": ["33-1-innate-immune-response"], "vaccine": ["33-2-adaptive-immune-response"], + # Other Body Systems "respiration": ["30-1-systems-of-gas-exchange", "30-3-breathing"], "breathing": ["30-3-breathing"], @@ -376,22 +354,9 @@ def get_chapter_list_for_llm() -> str: "digestion": ["25-1-digestive-systems", "25-3-digestive-system-processes"], "stomach": ["25-1-digestive-systems"], "intestine": ["25-3-digestive-system-processes"], - "hormone": [ - "28-1-types-of-hormones", - "28-2-how-hormones-work", - "28-4-regulation-of-hormone-production", - ], - "endocrine": [ - "28-5-endocrine-glands", - "28-1-types-of-hormones", - "28-2-how-hormones-work", - ], - "endocrine system": [ - "28-5-endocrine-glands", - "28-1-types-of-hormones", - "28-2-how-hormones-work", - "28-3-regulation-of-body-processes", - ], + "hormone": ["28-1-types-of-hormones", "28-2-how-hormones-work", "28-4-regulation-of-hormone-production"], + "endocrine": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work"], + "endocrine system": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work", "28-3-regulation-of-body-processes"], "pituitary": ["28-5-endocrine-glands", "28-4-regulation-of-hormone-production"], "thyroid": ["28-5-endocrine-glands", "28-3-regulation-of-body-processes"], "adrenal": ["28-5-endocrine-glands"], @@ -403,46 +368,30 @@ def get_chapter_list_for_llm() -> str: "skeleton": ["29-1-types-of-skeletal-systems"], "kidney": ["32-2-the-kidneys-and-osmoregulatory-organs"], "excretion": ["32-3-excretion-systems"], - "reproduction": [ - "34-1-reproduction-methods", - "34-3-human-reproductive-anatomy-and-gametogenesis", - ], - "reproductive": [ - "34-1-reproduction-methods", - "34-3-human-reproductive-anatomy-and-gametogenesis", - ], - "reproductive system": [ - "34-1-reproduction-methods", - "34-3-human-reproductive-anatomy-and-gametogenesis", - "34-4-hormonal-control-of-human-reproduction", - ], + "reproduction": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], + "reproductive": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], + "reproductive system": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis", "34-4-hormonal-control-of-human-reproduction"], "pregnancy": ["34-7-human-pregnancy-and-birth"], "embryo": ["34-5-fertilization-and-early-embryonic-development"], + # Evolution & Genetics "evolution": ["18-1-understanding-evolution", "19-1-population-evolution"], "darwin": ["18-1-understanding-evolution"], - "natural selection": [ - "19-3-adaptive-evolution", - "36-2-life-histories-and-natural-selection", - ], + "natural selection": ["19-3-adaptive-evolution", "36-2-life-histories-and-natural-selection"], "speciation": ["18-2-formation-of-new-species"], - "genetics": [ - "12-1-mendels-experiments-and-the-laws-of-probability", - "12-3-laws-of-inheritance", - ], + "genetics": ["12-1-mendels-experiments-and-the-laws-of-probability", "12-3-laws-of-inheritance"], "mendel": ["12-1-mendels-experiments-and-the-laws-of-probability"], "inheritance": ["12-3-laws-of-inheritance"], "heredity": ["12-3-laws-of-inheritance"], "mutation": ["14-6-dna-repair"], "phylogen": ["20-2-determining-evolutionary-relationships"], + # Microorganisms - "virus": [ - "21-1-viral-evolution-morphology-and-classification", - "21-2-virus-infection-and-hosts", - ], + "virus": ["21-1-viral-evolution-morphology-and-classification", "21-2-virus-infection-and-hosts"], "bacteria": ["22-1-prokaryotic-diversity", "22-4-bacterial-diseases-in-humans"], "prokaryote": ["4-2-prokaryotic-cells", "22-1-prokaryotic-diversity"], "eukaryote": ["4-3-eukaryotic-cells"], + # Plants "plant": ["23-1-the-plant-body"], "leaf": ["23-4-leaves"], @@ -450,21 +399,20 @@ def get_chapter_list_for_llm() -> str: "stem": ["23-2-stems"], "xylem": ["23-5-transport-of-water-and-solutes-in-plants"], "phloem": ["23-5-transport-of-water-and-solutes-in-plants"], + # Ecology "ecology": ["35-1-the-scope-of-ecology", "36-6-community-ecology"], "ecosystem": ["37-1-ecology-for-ecosystems", "37-2-energy-flow-through-ecosystems"], "food chain": ["37-2-energy-flow-through-ecosystems"], "food web": ["37-2-energy-flow-through-ecosystems"], "biome": ["35-3-terrestrial-biomes", "35-4-aquatic-biomes"], - "population": [ - "36-1-population-demography", - "36-3-environmental-limits-to-population-growth", - ], + "population": ["36-1-population-demography", "36-3-environmental-limits-to-population-growth"], "climate": ["35-5-climate-and-the-effects-of-global-climate-change"], "climate change": ["35-5-climate-and-the-effects-of-global-climate-change"], "biodiversity": ["38-1-the-biodiversity-crisis", "38-4-preserving-biodiversity"], "carbon cycle": ["37-3-biogeochemical-cycles"], "nitrogen cycle": ["37-3-biogeochemical-cycles"], + # Chemistry Basics "atom": ["2-1-atoms-isotopes-ions-and-molecules-the-building-blocks"], "water": ["2-2-water"], @@ -472,12 +420,14 @@ def get_chapter_list_for_llm() -> str: "carbohydrate": ["3-2-carbohydrates"], "lipid": ["3-3-lipids"], "nucleic acid": ["3-5-nucleic-acids"], + # Biotechnology "biotechnology": ["17-1-biotechnology"], "crispr": ["17-1-biotechnology"], "cloning": ["17-1-biotechnology"], "genome": ["17-2-mapping-genomes", "17-3-whole-genome-sequencing"], "genomics": ["17-4-applying-genomics", "17-5-genomics-and-proteomics"], + # Additional keywords for better coverage (plurals and common phrases) # Energy & Metabolism "light reactions": ["8-2-the-light-dependent-reaction-of-photosynthesis"], @@ -487,6 +437,7 @@ def get_chapter_list_for_llm() -> str: "proteins": ["3-4-proteins", "15-5-ribosomes-and-protein-synthesis"], "nucleic acids": ["3-5-nucleic-acids"], "ribosomes": ["15-5-ribosomes-and-protein-synthesis", "4-3-eukaryotic-cells"], + # Body Systems (full names) "respiratory system": ["30-1-systems-of-gas-exchange", "30-3-breathing"], "digestive system": ["25-1-digestive-systems", "25-3-digestive-system-processes"], @@ -494,6 +445,7 @@ def get_chapter_list_for_llm() -> str: "muscular system": ["29-4-muscle-contraction-and-locomotion"], "circulatory system": ["31-1-overview-of-the-circulatory-system"], "immune system": ["33-1-innate-immune-response", "33-2-adaptive-immune-response"], + # Plurals "hormones": ["28-1-types-of-hormones", "28-2-how-hormones-work"], "neurons": ["26-1-neurons-and-glial-cells", "26-2-how-neurons-communicate"], @@ -501,27 +453,16 @@ def get_chapter_list_for_llm() -> str: "kidneys": ["32-2-the-kidneys-and-osmoregulatory-organs"], "antibodies": ["33-3-antibodies"], "mutations": ["14-6-dna-repair"], - "ecosystems": [ - "37-1-ecology-for-ecosystems", - "37-2-energy-flow-through-ecosystems", - ], + "ecosystems": ["37-1-ecology-for-ecosystems", "37-2-energy-flow-through-ecosystems"], "biomes": ["35-3-terrestrial-biomes", "35-4-aquatic-biomes"], - "viruses": [ - "21-1-viral-evolution-morphology-and-classification", - "21-2-virus-infection-and-hosts", - ], + "viruses": ["21-1-viral-evolution-morphology-and-classification", "21-2-virus-infection-and-hosts"], "prokaryotes": ["4-2-prokaryotic-cells", "22-1-prokaryotic-diversity"], "eukaryotes": ["4-3-eukaryotic-cells"], - "chromosomes": [ - "13-1-chromosomal-theory-and-genetic-linkages", - "13-2-chromosomal-basis-of-inherited-disorders", - ], + "chromosomes": ["13-1-chromosomal-theory-and-genetic-linkages", "13-2-chromosomal-basis-of-inherited-disorders"], + # Genetics "homeostasis": ["24-3-homeostasis"], - "chromosome": [ - "13-1-chromosomal-theory-and-genetic-linkages", - "13-2-chromosomal-basis-of-inherited-disorders", - ], + "chromosome": ["13-1-chromosomal-theory-and-genetic-linkages", "13-2-chromosomal-basis-of-inherited-disorders"], "allele": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], "alleles": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], "dominant": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], @@ -530,20 +471,16 @@ def get_chapter_list_for_llm() -> str: "recessive traits": ["12-2-characteristics-and-traits", "12-3-laws-of-inheritance"], "genetic disorders": ["13-2-chromosomal-basis-of-inherited-disorders"], "genetic disorder": ["13-2-chromosomal-basis-of-inherited-disorders"], + # Evolution "adaptation": ["19-3-adaptive-evolution"], - "phylogenetic": [ - "20-2-determining-evolutionary-relationships", - "20-3-perspectives-on-the-phylogenetic-tree", - ], - "phylogenetics": [ - "20-2-determining-evolutionary-relationships", - "20-3-perspectives-on-the-phylogenetic-tree", - ], + "phylogenetic": ["20-2-determining-evolutionary-relationships", "20-3-perspectives-on-the-phylogenetic-tree"], + "phylogenetics": ["20-2-determining-evolutionary-relationships", "20-3-perspectives-on-the-phylogenetic-tree"], "fossil": ["18-1-understanding-evolution"], "fossils": ["18-1-understanding-evolution"], "common ancestor": ["20-2-determining-evolutionary-relationships"], "ancestors": ["20-2-determining-evolutionary-relationships"], + # Ecology "energy flow": ["37-2-energy-flow-through-ecosystems"], "trophic": ["37-2-energy-flow-through-ecosystems"], diff --git a/samples/personalized_learning/agent/openstax_content.py b/samples/personalized_learning/agent/openstax_content.py index e29a7e8bd..cfcf836a8 100644 --- a/samples/personalized_learning/agent/openstax_content.py +++ b/samples/personalized_learning/agent/openstax_content.py @@ -35,27 +35,22 @@ logger = logging.getLogger(__name__) - # SSL context for GitHub fetches - uses certifi CA bundle if available def _get_ssl_context() -> ssl.SSLContext: """Get SSL context with proper CA certificates.""" try: import certifi - return ssl.create_default_context(cafile=certifi.where()) except ImportError: # certifi not available, use system defaults return ssl.create_default_context() - # GCS configuration GCS_OPENSTAX_BUCKET = os.getenv("GCS_OPENSTAX_BUCKET", "") GCS_OPENSTAX_PREFIX = os.getenv("GCS_OPENSTAX_PREFIX", "openstax_modules/") # GitHub configuration -GITHUB_RAW_BASE = ( - "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" -) +GITHUB_RAW_BASE = "https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules" # CNXML namespace CNXML_NS = {"cnxml": "http://cnx.rice.edu/cnxml"} @@ -152,15 +147,15 @@ def parse_cnxml_to_text(cnxml_content: str) -> str: full_text = "\n".join(text_parts) # Clean up excessive whitespace - full_text = re.sub(r"\n{3,}", "\n\n", full_text) - full_text = re.sub(r" {2,}", " ", full_text) + full_text = re.sub(r'\n{3,}', '\n\n', full_text) + full_text = re.sub(r' {2,}', ' ', full_text) return full_text.strip() except ET.ParseError as e: logger.error(f"Failed to parse CNXML: {e}") # Return raw content as fallback (stripped of XML tags) - return re.sub(r"<[^>]+>", " ", cnxml_content).strip() + return re.sub(r'<[^>]+>', ' ', cnxml_content).strip() def _extract_text_from_element(elem) -> str: @@ -224,10 +219,8 @@ def fetch_module_from_github(module_id: str) -> Optional[str]: url = f"{GITHUB_RAW_BASE}/{module_id}/index.cnxml" try: - with urllib.request.urlopen( - url, timeout=10, context=_get_ssl_context() - ) as response: - content = response.read().decode("utf-8") + with urllib.request.urlopen(url, timeout=10, context=_get_ssl_context()) as response: + content = response.read().decode('utf-8') logger.info(f"Fetched module {module_id} from GitHub") return content except urllib.error.HTTPError as e: @@ -330,10 +323,8 @@ def fetch_chapter_content(chapter_slug: str) -> Optional[dict]: if len(module_ids) > 1: # Use parallel fetching for multiple modules with ThreadPoolExecutor(max_workers=min(len(module_ids), 5)) as executor: - futures = { - executor.submit(fetch_module_content_cached, mid): mid - for mid in module_ids - } + futures = {executor.submit(fetch_module_content_cached, mid): mid + for mid in module_ids} for future in futures: try: result = future.result() @@ -382,9 +373,8 @@ def fetch_multiple_chapters(chapter_slugs: list[str]) -> list[dict]: # Parallel fetch for multiple chapters results = [] with ThreadPoolExecutor(max_workers=min(len(chapter_slugs), 3)) as executor: - futures = { - executor.submit(fetch_chapter_content, slug): slug for slug in chapter_slugs - } + futures = {executor.submit(fetch_chapter_content, slug): slug + for slug in chapter_slugs} for future in futures: try: result = future.result() @@ -440,9 +430,7 @@ async def fetch_modules_for_topic(topic: str, max_modules: int = 3) -> dict: # Search for matching modules using keyword matching logger.info("Step 1: Searching for modules using keyword matching...") matched_modules = search_modules(topic, max_results=max_modules) - logger.info( - f"Keyword matching found {len(matched_modules)} modules: {[m.get('id', m.get('title', 'unknown')) for m in matched_modules]}" - ) + logger.info(f"Keyword matching found {len(matched_modules)} modules: {[m.get('id', m.get('title', 'unknown')) for m in matched_modules]}") if not matched_modules: # Fall back to LLM matching for chapter, then get first module @@ -452,26 +440,21 @@ async def fetch_modules_for_topic(topic: str, max_modules: int = 3) -> dict: if chapter_slugs: # Import chapter-to-module mapping as fallback from .openstax_chapters import CHAPTER_TO_MODULES - if chapter_slugs[0] in CHAPTER_TO_MODULES: module_ids = CHAPTER_TO_MODULES[chapter_slugs[0]][:max_modules] logger.info(f"Found modules from chapter mapping: {module_ids}") for mid in module_ids: if mid in MODULE_INDEX: info = MODULE_INDEX[mid] - matched_modules.append( - { - "id": mid, - "title": info["title"], - "unit": info["unit"], - "chapter": info["chapter"], - "url": get_module_url(mid), - } - ) + matched_modules.append({ + "id": mid, + "title": info["title"], + "unit": info["unit"], + "chapter": info["chapter"], + "url": get_module_url(mid), + }) else: - logger.warning( - f"Chapter {chapter_slugs[0]} not found in CHAPTER_TO_MODULES mapping" - ) + logger.warning(f"Chapter {chapter_slugs[0]} not found in CHAPTER_TO_MODULES mapping") else: logger.warning("LLM matching also returned no chapters!") @@ -494,10 +477,8 @@ async def fetch_modules_for_topic(topic: str, max_modules: int = 3) -> dict: # Parallel fetch for multiple modules contents = [] with ThreadPoolExecutor(max_workers=min(len(module_ids), 5)) as executor: - futures = { - executor.submit(fetch_module_content_cached, mid): mid - for mid in module_ids - } + futures = {executor.submit(fetch_module_content_cached, mid): mid + for mid in module_ids} for future in futures: try: result = future.result() @@ -563,11 +544,7 @@ async def fetch_content_for_topic(topic: str, max_chapters: int = 3) -> dict: return { "topic": result["topic"], "matched_chapters": [ - { - "slug": m.get("id", ""), - "title": m.get("title", ""), - "url": m.get("url", ""), - } + {"slug": m.get("id", ""), "title": m.get("title", ""), "url": m.get("url", "")} for m in result.get("matched_modules", []) ], "combined_content": result.get("combined_content", ""), diff --git a/samples/personalized_learning/agent/openstax_modules.py b/samples/personalized_learning/agent/openstax_modules.py index 409b99485..8a0714599 100644 --- a/samples/personalized_learning/agent/openstax_modules.py +++ b/samples/personalized_learning/agent/openstax_modules.py @@ -284,1035 +284,215 @@ # Complete module index with titles, units, and chapters # Generated from the collection XML MODULE_INDEX = { - "m45849": { - "title": "The Periodic Table of Elements", - "unit": "Front Matter", - "chapter": "Front Matter", - }, - "m60107": { - "title": "Geological Time", - "unit": "Front Matter", - "chapter": "Front Matter", - }, - "m62716": { - "title": "Introduction", - "unit": "The Chemistry of Life", - "chapter": "The Study of Life", - }, - "m62717": { - "title": "The Science of Biology", - "unit": "The Chemistry of Life", - "chapter": "The Study of Life", - }, - "m62718": { - "title": "Themes and Concepts of Biology", - "unit": "The Chemistry of Life", - "chapter": "The Study of Life", - }, - "m62719": { - "title": "Introduction", - "unit": "The Chemistry of Life", - "chapter": "The Chemical Foundation of Life", - }, - "m62720": { - "title": "Atoms, Isotopes, Ions, and Molecules: The Building Blocks", - "unit": "The Chemistry of Life", - "chapter": "The Chemical Foundation of Life", - }, - "m62721": { - "title": "Water", - "unit": "The Chemistry of Life", - "chapter": "The Chemical Foundation of Life", - }, - "m62722": { - "title": "Carbon", - "unit": "The Chemistry of Life", - "chapter": "The Chemical Foundation of Life", - }, - "m62723": { - "title": "Introduction", - "unit": "The Chemistry of Life", - "chapter": "Biological Macromolecules", - }, - "m62724": { - "title": "Synthesis of Biological Macromolecules", - "unit": "The Chemistry of Life", - "chapter": "Biological Macromolecules", - }, - "m62726": { - "title": "Carbohydrates", - "unit": "The Chemistry of Life", - "chapter": "Biological Macromolecules", - }, - "m62730": { - "title": "Lipids", - "unit": "The Chemistry of Life", - "chapter": "Biological Macromolecules", - }, - "m62733": { - "title": "Proteins", - "unit": "The Chemistry of Life", - "chapter": "Biological Macromolecules", - }, - "m62735": { - "title": "Nucleic Acids", - "unit": "The Chemistry of Life", - "chapter": "Biological Macromolecules", - }, - "m62736": { - "title": "Introduction", - "unit": "The Cell", - "chapter": "Cell Structure", - }, - "m62738": { - "title": "Studying Cells", - "unit": "The Cell", - "chapter": "Cell Structure", - }, - "m62740": { - "title": "Prokaryotic Cells", - "unit": "The Cell", - "chapter": "Cell Structure", - }, - "m62742": { - "title": "Eukaryotic Cells", - "unit": "The Cell", - "chapter": "Cell Structure", - }, - "m62743": { - "title": "The Endomembrane System and Proteins", - "unit": "The Cell", - "chapter": "Cell Structure", - }, - "m62744": { - "title": "Cytoskeleton", - "unit": "The Cell", - "chapter": "Cell Structure", - }, - "m62746": { - "title": "Connections between Cells and Cellular Activities", - "unit": "The Cell", - "chapter": "Cell Structure", - }, - "m62753": { - "title": "Passive Transport", - "unit": "The Cell", - "chapter": "Structure and Function of Plasma Membranes", - }, + "m45849": {"title": "The Periodic Table of Elements", "unit": "Front Matter", "chapter": "Front Matter"}, + "m60107": {"title": "Geological Time", "unit": "Front Matter", "chapter": "Front Matter"}, + "m62716": {"title": "Introduction", "unit": "The Chemistry of Life", "chapter": "The Study of Life"}, + "m62717": {"title": "The Science of Biology", "unit": "The Chemistry of Life", "chapter": "The Study of Life"}, + "m62718": {"title": "Themes and Concepts of Biology", "unit": "The Chemistry of Life", "chapter": "The Study of Life"}, + "m62719": {"title": "Introduction", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, + "m62720": {"title": "Atoms, Isotopes, Ions, and Molecules: The Building Blocks", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, + "m62721": {"title": "Water", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, + "m62722": {"title": "Carbon", "unit": "The Chemistry of Life", "chapter": "The Chemical Foundation of Life"}, + "m62723": {"title": "Introduction", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, + "m62724": {"title": "Synthesis of Biological Macromolecules", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, + "m62726": {"title": "Carbohydrates", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, + "m62730": {"title": "Lipids", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, + "m62733": {"title": "Proteins", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, + "m62735": {"title": "Nucleic Acids", "unit": "The Chemistry of Life", "chapter": "Biological Macromolecules"}, + "m62736": {"title": "Introduction", "unit": "The Cell", "chapter": "Cell Structure"}, + "m62738": {"title": "Studying Cells", "unit": "The Cell", "chapter": "Cell Structure"}, + "m62740": {"title": "Prokaryotic Cells", "unit": "The Cell", "chapter": "Cell Structure"}, + "m62742": {"title": "Eukaryotic Cells", "unit": "The Cell", "chapter": "Cell Structure"}, + "m62743": {"title": "The Endomembrane System and Proteins", "unit": "The Cell", "chapter": "Cell Structure"}, + "m62744": {"title": "Cytoskeleton", "unit": "The Cell", "chapter": "Cell Structure"}, + "m62746": {"title": "Connections between Cells and Cellular Activities", "unit": "The Cell", "chapter": "Cell Structure"}, + "m62753": {"title": "Passive Transport", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, "m62761": {"title": "Introduction", "unit": "The Cell", "chapter": "Metabolism"}, - "m62763": { - "title": "Energy and Metabolism", - "unit": "The Cell", - "chapter": "Metabolism", - }, - "m62764": { - "title": "Potential, Kinetic, Free, and Activation Energy", - "unit": "The Cell", - "chapter": "Metabolism", - }, - "m62767": { - "title": "The Laws of Thermodynamics", - "unit": "The Cell", - "chapter": "Metabolism", - }, - "m62768": { - "title": "ATP: Adenosine Triphosphate", - "unit": "The Cell", - "chapter": "Metabolism", - }, - "m62770": { - "title": "Active Transport", - "unit": "The Cell", - "chapter": "Structure and Function of Plasma Membranes", - }, - "m62772": { - "title": "Bulk Transport", - "unit": "The Cell", - "chapter": "Structure and Function of Plasma Membranes", - }, - "m62773": { - "title": "Components and Structure", - "unit": "The Cell", - "chapter": "Structure and Function of Plasma Membranes", - }, + "m62763": {"title": "Energy and Metabolism", "unit": "The Cell", "chapter": "Metabolism"}, + "m62764": {"title": "Potential, Kinetic, Free, and Activation Energy", "unit": "The Cell", "chapter": "Metabolism"}, + "m62767": {"title": "The Laws of Thermodynamics", "unit": "The Cell", "chapter": "Metabolism"}, + "m62768": {"title": "ATP: Adenosine Triphosphate", "unit": "The Cell", "chapter": "Metabolism"}, + "m62770": {"title": "Active Transport", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, + "m62772": {"title": "Bulk Transport", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, + "m62773": {"title": "Components and Structure", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, "m62778": {"title": "Enzymes", "unit": "The Cell", "chapter": "Metabolism"}, - "m62780": { - "title": "Introduction", - "unit": "The Cell", - "chapter": "Structure and Function of Plasma Membranes", - }, - "m62784": { - "title": "Introduction", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62786": { - "title": "Energy in Living Systems", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62787": { - "title": "Glycolysis", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62788": { - "title": "Oxidation of Pyruvate and the Citric Acid Cycle", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62789": { - "title": "Oxidative Phosphorylation", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62790": { - "title": "Metabolism without Oxygen", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62791": { - "title": "Connections of Carbohydrate, Protein, and Lipid Metabolic Pathways", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62792": { - "title": "Regulation of Cellular Respiration", - "unit": "The Cell", - "chapter": "Cellular Respiration", - }, - "m62793": { - "title": "Introduction", - "unit": "The Cell", - "chapter": "Photosynthesis", - }, - "m62794": { - "title": "Overview of Photosynthesis", - "unit": "The Cell", - "chapter": "Photosynthesis", - }, - "m62795": { - "title": "The Light-Dependent Reaction of Photosynthesis", - "unit": "The Cell", - "chapter": "Photosynthesis", - }, - "m62796": { - "title": "Using Light to Make Organic Molecules", - "unit": "The Cell", - "chapter": "Photosynthesis", - }, - "m62797": { - "title": "Introduction", - "unit": "The Cell", - "chapter": "Cell Communication", - }, - "m62798": { - "title": "Signaling Molecules and Cellular Receptors", - "unit": "The Cell", - "chapter": "Cell Communication", - }, - "m62799": { - "title": "Propagation of the Signal", - "unit": "The Cell", - "chapter": "Cell Communication", - }, - "m62800": { - "title": "Response to the Signal", - "unit": "The Cell", - "chapter": "Cell Communication", - }, - "m62801": { - "title": "Signaling in Single-Celled Organisms", - "unit": "The Cell", - "chapter": "Cell Communication", - }, - "m62802": { - "title": "Introduction", - "unit": "The Cell", - "chapter": "Cell Reproduction", - }, - "m62803": { - "title": "Cell Division", - "unit": "The Cell", - "chapter": "Cell Reproduction", - }, - "m62804": { - "title": "The Cell Cycle", - "unit": "The Cell", - "chapter": "Cell Reproduction", - }, - "m62805": { - "title": "Control of the Cell Cycle", - "unit": "The Cell", - "chapter": "Cell Reproduction", - }, - "m62806": { - "title": "Cancer and the Cell Cycle", - "unit": "The Cell", - "chapter": "Cell Reproduction", - }, - "m62808": { - "title": "Prokaryotic Cell Division", - "unit": "The Cell", - "chapter": "Cell Reproduction", - }, - "m62809": { - "title": "Introduction", - "unit": "Genetics", - "chapter": "Meiosis and Sexual Reproduction", - }, - "m62810": { - "title": "The Process of Meiosis", - "unit": "Genetics", - "chapter": "Meiosis and Sexual Reproduction", - }, - "m62811": { - "title": "Sexual Reproduction", - "unit": "Genetics", - "chapter": "Meiosis and Sexual Reproduction", - }, - "m62812": { - "title": "Introduction", - "unit": "Genetics", - "chapter": "Mendel's Experiments and Heredity", - }, - "m62813": { - "title": "Mendel's Experiments and the Laws of Probability", - "unit": "Genetics", - "chapter": "Mendel's Experiments and Heredity", - }, - "m62817": { - "title": "Characteristics and Traits", - "unit": "Genetics", - "chapter": "Mendel's Experiments and Heredity", - }, - "m62819": { - "title": "Laws of Inheritance", - "unit": "Genetics", - "chapter": "Mendel's Experiments and Heredity", - }, - "m62820": { - "title": "Introduction", - "unit": "Genetics", - "chapter": "Modern Understandings of Inheritance", - }, - "m62821": { - "title": "Chromosomal Theory and Genetic Linkages", - "unit": "Genetics", - "chapter": "Modern Understandings of Inheritance", - }, - "m62822": { - "title": "Chromosomal Basis of Inherited Disorders", - "unit": "Genetics", - "chapter": "Modern Understandings of Inheritance", - }, - "m62823": { - "title": "Introduction", - "unit": "Genetics", - "chapter": "DNA Structure and Function", - }, - "m62824": { - "title": "Historical Basis of Modern Understanding", - "unit": "Genetics", - "chapter": "DNA Structure and Function", - }, - "m62825": { - "title": "DNA Structure and Sequencing", - "unit": "Genetics", - "chapter": "DNA Structure and Function", - }, - "m62826": { - "title": "Basics of DNA Replication", - "unit": "Genetics", - "chapter": "DNA Structure and Function", - }, - "m62828": { - "title": "DNA Replication in Prokaryotes", - "unit": "Genetics", - "chapter": "DNA Structure and Function", - }, - "m62829": { - "title": "DNA Replication in Eukaryotes", - "unit": "Genetics", - "chapter": "DNA Structure and Function", - }, - "m62830": { - "title": "DNA Repair", - "unit": "Genetics", - "chapter": "DNA Structure and Function", - }, - "m62833": { - "title": "Introduction", - "unit": "Genetics", - "chapter": "Genes and Proteins", - }, - "m62837": { - "title": "The Genetic Code", - "unit": "Genetics", - "chapter": "Genes and Proteins", - }, - "m62838": { - "title": "Prokaryotic Transcription", - "unit": "Genetics", - "chapter": "Genes and Proteins", - }, - "m62840": { - "title": "Eukaryotic Transcription", - "unit": "Genetics", - "chapter": "Genes and Proteins", - }, - "m62842": { - "title": "RNA Processing in Eukaryotes", - "unit": "Genetics", - "chapter": "Genes and Proteins", - }, - "m62843": { - "title": "Ribosomes and Protein Synthesis", - "unit": "Genetics", - "chapter": "Genes and Proteins", - }, - "m62844": { - "title": "Introduction", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62845": { - "title": "Regulation of Gene Expression", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62846": { - "title": "Prokaryotic Gene Regulation", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62847": { - "title": "Eukaryotic Epigenetic Gene Regulation", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62848": { - "title": "Eukaryotic Transcriptional Gene Regulation", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62849": { - "title": "Eukaryotic Post-transcriptional Gene Regulation", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62850": { - "title": "Eukaryotic Translational and Post-translational Gene Regulation", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62851": { - "title": "Cancer and Gene Regulation", - "unit": "Genetics", - "chapter": "Gene Regulation", - }, - "m62852": { - "title": "Introduction", - "unit": "Genetics", - "chapter": "Biotechnology and Genomics", - }, - "m62853": { - "title": "Biotechnology", - "unit": "Genetics", - "chapter": "Biotechnology and Genomics", - }, - "m62855": { - "title": "Mapping Genomes", - "unit": "Genetics", - "chapter": "Biotechnology and Genomics", - }, - "m62857": { - "title": "Whole-Genome Sequencing", - "unit": "Genetics", - "chapter": "Biotechnology and Genomics", - }, - "m62860": { - "title": "Applying Genomics", - "unit": "Genetics", - "chapter": "Biotechnology and Genomics", - }, - "m62861": { - "title": "Genomics and Proteomics", - "unit": "Genetics", - "chapter": "Biotechnology and Genomics", - }, - "m62862": { - "title": "Introduction", - "unit": "Evolutionary Processes", - "chapter": "Evolution and Origin of Species", - }, - "m62863": { - "title": "Understanding Evolution", - "unit": "Evolutionary Processes", - "chapter": "Evolution and Origin of Species", - }, - "m62864": { - "title": "Formation of New Species", - "unit": "Evolutionary Processes", - "chapter": "Evolution and Origin of Species", - }, - "m62865": { - "title": "Reconnection and Rates of Speciation", - "unit": "Evolutionary Processes", - "chapter": "Evolution and Origin of Species", - }, - "m62866": { - "title": "Introduction", - "unit": "Evolutionary Processes", - "chapter": "The Evolution of Populations", - }, - "m62868": { - "title": "Population Evolution", - "unit": "Evolutionary Processes", - "chapter": "The Evolution of Populations", - }, - "m62870": { - "title": "Population Genetics", - "unit": "Evolutionary Processes", - "chapter": "The Evolution of Populations", - }, - "m62871": { - "title": "Adaptive Evolution", - "unit": "Evolutionary Processes", - "chapter": "The Evolution of Populations", - }, - "m62873": { - "title": "Introduction", - "unit": "Evolutionary Processes", - "chapter": "Phylogenies and the History of Life", - }, - "m62874": { - "title": "Organizing Life on Earth", - "unit": "Evolutionary Processes", - "chapter": "Phylogenies and the History of Life", - }, - "m62876": { - "title": "Perspectives on the Phylogenetic Tree", - "unit": "Evolutionary Processes", - "chapter": "Phylogenies and the History of Life", - }, - "m62877": { - "title": "Introduction", - "unit": "Biological Diversity", - "chapter": "Viruses", - }, - "m62881": { - "title": "Viral Evolution, Morphology, and Classification", - "unit": "Biological Diversity", - "chapter": "Viruses", - }, - "m62882": { - "title": "Virus Infection and Hosts", - "unit": "Biological Diversity", - "chapter": "Viruses", - }, - "m62887": { - "title": "Other Acellular Entities: Prions and Viroids", - "unit": "Biological Diversity", - "chapter": "Viruses", - }, - "m62889": { - "title": "Introduction", - "unit": "Biological Diversity", - "chapter": "Prokaryotes: Bacteria and Archaea", - }, - "m62891": { - "title": "Prokaryotic Diversity", - "unit": "Biological Diversity", - "chapter": "Prokaryotes: Bacteria and Archaea", - }, - "m62893": { - "title": "Structure of Prokaryotes", - "unit": "Biological Diversity", - "chapter": "Prokaryotes: Bacteria and Archaea", - }, - "m62894": { - "title": "Prokaryotic Metabolism", - "unit": "Biological Diversity", - "chapter": "Prokaryotes: Bacteria and Archaea", - }, - "m62896": { - "title": "Bacterial Diseases in Humans", - "unit": "Biological Diversity", - "chapter": "Prokaryotes: Bacteria and Archaea", - }, - "m62897": { - "title": "Beneficial Prokaryotes", - "unit": "Biological Diversity", - "chapter": "Prokaryotes: Bacteria and Archaea", - }, - "m62899": { - "title": "Introduction", - "unit": "Plant Structure and Function", - "chapter": "Plant Form and Physiology", - }, - "m62903": { - "title": "Determining Evolutionary Relationships", - "unit": "Evolutionary Processes", - "chapter": "Phylogenies and the History of Life", - }, - "m62904": { - "title": "Prevention and Treatment of Viral Infections", - "unit": "Biological Diversity", - "chapter": "Viruses", - }, - "m62905": { - "title": "Stems", - "unit": "Plant Structure and Function", - "chapter": "Plant Form and Physiology", - }, - "m62906": { - "title": "Roots", - "unit": "Plant Structure and Function", - "chapter": "Plant Form and Physiology", - }, - "m62908": { - "title": "Leaves", - "unit": "Plant Structure and Function", - "chapter": "Plant Form and Physiology", - }, - "m62912": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "The Animal Body: Basic Form and Function", - }, - "m62916": { - "title": "Animal Form and Function", - "unit": "Animal Structure and Function", - "chapter": "The Animal Body: Basic Form and Function", - }, - "m62918": { - "title": "Animal Primary Tissues", - "unit": "Animal Structure and Function", - "chapter": "The Animal Body: Basic Form and Function", - }, - "m62919": { - "title": "Digestive Systems", - "unit": "Animal Structure and Function", - "chapter": "Animal Nutrition and the Digestive System", - }, - "m62920": { - "title": "Nutrition and Energy Production", - "unit": "Animal Structure and Function", - "chapter": "Animal Nutrition and the Digestive System", - }, - "m62921": { - "title": "Digestive System Processes", - "unit": "Animal Structure and Function", - "chapter": "Animal Nutrition and the Digestive System", - }, - "m62922": { - "title": "Digestive System Regulation", - "unit": "Animal Structure and Function", - "chapter": "Animal Nutrition and the Digestive System", - }, - "m62923": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "The Nervous System", - }, - "m62924": { - "title": "Neurons and Glial Cells", - "unit": "Animal Structure and Function", - "chapter": "The Nervous System", - }, - "m62925": { - "title": "How Neurons Communicate", - "unit": "Animal Structure and Function", - "chapter": "The Nervous System", - }, - "m62926": { - "title": "The Central Nervous System", - "unit": "Animal Structure and Function", - "chapter": "The Nervous System", - }, - "m62928": { - "title": "The Peripheral Nervous System", - "unit": "Animal Structure and Function", - "chapter": "The Nervous System", - }, - "m62929": { - "title": "Nervous System Disorders", - "unit": "Animal Structure and Function", - "chapter": "The Nervous System", - }, - "m62930": { - "title": "Plant Sensory Systems and Responses", - "unit": "Plant Structure and Function", - "chapter": "Plant Form and Physiology", - }, - "m62931": { - "title": "Homeostasis", - "unit": "Animal Structure and Function", - "chapter": "The Animal Body: Basic Form and Function", - }, - "m62933": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "Animal Nutrition and the Digestive System", - }, - "m62937": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "Sensory Systems", - }, - "m62946": { - "title": "Somatosensation", - "unit": "Animal Structure and Function", - "chapter": "Sensory Systems", - }, - "m62947": { - "title": "Taste and Smell", - "unit": "Animal Structure and Function", - "chapter": "Sensory Systems", - }, - "m62951": { - "title": "The Plant Body", - "unit": "Plant Structure and Function", - "chapter": "Plant Form and Physiology", - }, - "m62954": { - "title": "Hearing and Vestibular Sensation", - "unit": "Animal Structure and Function", - "chapter": "Sensory Systems", - }, - "m62957": { - "title": "Vision", - "unit": "Animal Structure and Function", - "chapter": "Sensory Systems", - }, - "m62959": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "The Endocrine System", - }, - "m62961": { - "title": "Types of Hormones", - "unit": "Animal Structure and Function", - "chapter": "The Endocrine System", - }, - "m62963": { - "title": "How Hormones Work", - "unit": "Animal Structure and Function", - "chapter": "The Endocrine System", - }, - "m62969": { - "title": "Transport of Water and Solutes in Plants", - "unit": "Plant Structure and Function", - "chapter": "Plant Form and Physiology", - }, - "m62971": { - "title": "Regulation of Hormone Production", - "unit": "Animal Structure and Function", - "chapter": "The Endocrine System", - }, - "m62976": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "The Musculoskeletal System", - }, - "m62977": { - "title": "Types of Skeletal Systems", - "unit": "Animal Structure and Function", - "chapter": "The Musculoskeletal System", - }, - "m62978": { - "title": "Bone", - "unit": "Animal Structure and Function", - "chapter": "The Musculoskeletal System", - }, - "m62979": { - "title": "Joints and Skeletal Movement", - "unit": "Animal Structure and Function", - "chapter": "The Musculoskeletal System", - }, - "m62980": { - "title": "Muscle Contraction and Locomotion", - "unit": "Animal Structure and Function", - "chapter": "The Musculoskeletal System", - }, - "m62981": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "The Respiratory System", - }, - "m62982": { - "title": "Systems of Gas Exchange", - "unit": "Animal Structure and Function", - "chapter": "The Respiratory System", - }, - "m62987": { - "title": "Breathing", - "unit": "Animal Structure and Function", - "chapter": "The Respiratory System", - }, - "m62988": { - "title": "Transport of Gases in Human Bodily Fluids", - "unit": "Animal Structure and Function", - "chapter": "The Respiratory System", - }, - "m62989": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "The Circulatory System", - }, - "m62990": { - "title": "Overview of the Circulatory System", - "unit": "Animal Structure and Function", - "chapter": "The Circulatory System", - }, - "m62991": { - "title": "Components of the Blood", - "unit": "Animal Structure and Function", - "chapter": "The Circulatory System", - }, - "m62992": { - "title": "Mammalian Heart and Blood Vessels", - "unit": "Animal Structure and Function", - "chapter": "The Circulatory System", - }, - "m62993": { - "title": "Blood Flow and Blood Pressure Regulation", - "unit": "Animal Structure and Function", - "chapter": "The Circulatory System", - }, - "m62994": { - "title": "Sensory Processes", - "unit": "Animal Structure and Function", - "chapter": "Sensory Systems", - }, - "m62995": { - "title": "Endocrine Glands", - "unit": "Animal Structure and Function", - "chapter": "The Endocrine System", - }, - "m62996": { - "title": "Regulation of Body Processes", - "unit": "Animal Structure and Function", - "chapter": "The Endocrine System", - }, - "m62997": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "Osmotic Regulation and Excretion", - }, - "m62998": { - "title": "Gas Exchange across Respiratory Surfaces", - "unit": "Animal Structure and Function", - "chapter": "The Respiratory System", - }, - "m63000": { - "title": "Osmoregulation and Osmotic Balance", - "unit": "Animal Structure and Function", - "chapter": "Osmotic Regulation and Excretion", - }, - "m63001": { - "title": "The Kidneys and Osmoregulatory Organs", - "unit": "Animal Structure and Function", - "chapter": "Osmotic Regulation and Excretion", - }, - "m63002": { - "title": "Excretion Systems", - "unit": "Animal Structure and Function", - "chapter": "Osmotic Regulation and Excretion", - }, - "m63003": { - "title": "Nitrogenous Wastes", - "unit": "Animal Structure and Function", - "chapter": "Osmotic Regulation and Excretion", - }, - "m63004": { - "title": "Hormonal Control of Osmoregulatory Functions", - "unit": "Animal Structure and Function", - "chapter": "Osmotic Regulation and Excretion", - }, - "m63005": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "The Immune System", - }, - "m63006": { - "title": "Innate Immune Response", - "unit": "Animal Structure and Function", - "chapter": "The Immune System", - }, - "m63007": { - "title": "Adaptive Immune Response", - "unit": "Animal Structure and Function", - "chapter": "The Immune System", - }, - "m63008": { - "title": "Antibodies", - "unit": "Animal Structure and Function", - "chapter": "The Immune System", - }, - "m63009": { - "title": "Disruptions in the Immune System", - "unit": "Animal Structure and Function", - "chapter": "The Immune System", - }, - "m63010": { - "title": "Introduction", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63011": { - "title": "Reproduction Methods", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63012": { - "title": "Fertilization", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63013": { - "title": "Human Reproductive Anatomy and Gametogenesis", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63014": { - "title": "Hormonal Control of Human Reproduction", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63016": { - "title": "Fertilization and Early Embryonic Development", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63018": { - "title": "Human Pregnancy and Birth", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63019": { - "title": "Introduction", - "unit": "Ecology", - "chapter": "Ecology and the Biosphere", - }, - "m63021": { - "title": "The Scope of Ecology", - "unit": "Ecology", - "chapter": "Ecology and the Biosphere", - }, - "m63023": { - "title": "Biogeography", - "unit": "Ecology", - "chapter": "Ecology and the Biosphere", - }, - "m63024": { - "title": "Terrestrial Biomes", - "unit": "Ecology", - "chapter": "Ecology and the Biosphere", - }, - "m63025": { - "title": "Aquatic Biomes", - "unit": "Ecology", - "chapter": "Ecology and the Biosphere", - }, - "m63026": { - "title": "Climate and the Effects of Global Climate Change", - "unit": "Ecology", - "chapter": "Ecology and the Biosphere", - }, - "m63027": { - "title": "Introduction", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, - "m63028": { - "title": "Population Demography", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, - "m63029": { - "title": "Life Histories and Natural Selection", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, - "m63030": { - "title": "Environmental Limits to Population Growth", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, - "m63031": { - "title": "Population Dynamics and Regulation", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, - "m63032": { - "title": "Human Population Growth", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, - "m63033": { - "title": "Community Ecology", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, - "m63034": { - "title": "Behavioral Biology: Proximate and Ultimate Causes of Behavior", - "unit": "Ecology", - "chapter": "Population and Community Ecology", - }, + "m62780": {"title": "Introduction", "unit": "The Cell", "chapter": "Structure and Function of Plasma Membranes"}, + "m62784": {"title": "Introduction", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62786": {"title": "Energy in Living Systems", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62787": {"title": "Glycolysis", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62788": {"title": "Oxidation of Pyruvate and the Citric Acid Cycle", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62789": {"title": "Oxidative Phosphorylation", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62790": {"title": "Metabolism without Oxygen", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62791": {"title": "Connections of Carbohydrate, Protein, and Lipid Metabolic Pathways", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62792": {"title": "Regulation of Cellular Respiration", "unit": "The Cell", "chapter": "Cellular Respiration"}, + "m62793": {"title": "Introduction", "unit": "The Cell", "chapter": "Photosynthesis"}, + "m62794": {"title": "Overview of Photosynthesis", "unit": "The Cell", "chapter": "Photosynthesis"}, + "m62795": {"title": "The Light-Dependent Reaction of Photosynthesis", "unit": "The Cell", "chapter": "Photosynthesis"}, + "m62796": {"title": "Using Light to Make Organic Molecules", "unit": "The Cell", "chapter": "Photosynthesis"}, + "m62797": {"title": "Introduction", "unit": "The Cell", "chapter": "Cell Communication"}, + "m62798": {"title": "Signaling Molecules and Cellular Receptors", "unit": "The Cell", "chapter": "Cell Communication"}, + "m62799": {"title": "Propagation of the Signal", "unit": "The Cell", "chapter": "Cell Communication"}, + "m62800": {"title": "Response to the Signal", "unit": "The Cell", "chapter": "Cell Communication"}, + "m62801": {"title": "Signaling in Single-Celled Organisms", "unit": "The Cell", "chapter": "Cell Communication"}, + "m62802": {"title": "Introduction", "unit": "The Cell", "chapter": "Cell Reproduction"}, + "m62803": {"title": "Cell Division", "unit": "The Cell", "chapter": "Cell Reproduction"}, + "m62804": {"title": "The Cell Cycle", "unit": "The Cell", "chapter": "Cell Reproduction"}, + "m62805": {"title": "Control of the Cell Cycle", "unit": "The Cell", "chapter": "Cell Reproduction"}, + "m62806": {"title": "Cancer and the Cell Cycle", "unit": "The Cell", "chapter": "Cell Reproduction"}, + "m62808": {"title": "Prokaryotic Cell Division", "unit": "The Cell", "chapter": "Cell Reproduction"}, + "m62809": {"title": "Introduction", "unit": "Genetics", "chapter": "Meiosis and Sexual Reproduction"}, + "m62810": {"title": "The Process of Meiosis", "unit": "Genetics", "chapter": "Meiosis and Sexual Reproduction"}, + "m62811": {"title": "Sexual Reproduction", "unit": "Genetics", "chapter": "Meiosis and Sexual Reproduction"}, + "m62812": {"title": "Introduction", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, + "m62813": {"title": "Mendel's Experiments and the Laws of Probability", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, + "m62817": {"title": "Characteristics and Traits", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, + "m62819": {"title": "Laws of Inheritance", "unit": "Genetics", "chapter": "Mendel's Experiments and Heredity"}, + "m62820": {"title": "Introduction", "unit": "Genetics", "chapter": "Modern Understandings of Inheritance"}, + "m62821": {"title": "Chromosomal Theory and Genetic Linkages", "unit": "Genetics", "chapter": "Modern Understandings of Inheritance"}, + "m62822": {"title": "Chromosomal Basis of Inherited Disorders", "unit": "Genetics", "chapter": "Modern Understandings of Inheritance"}, + "m62823": {"title": "Introduction", "unit": "Genetics", "chapter": "DNA Structure and Function"}, + "m62824": {"title": "Historical Basis of Modern Understanding", "unit": "Genetics", "chapter": "DNA Structure and Function"}, + "m62825": {"title": "DNA Structure and Sequencing", "unit": "Genetics", "chapter": "DNA Structure and Function"}, + "m62826": {"title": "Basics of DNA Replication", "unit": "Genetics", "chapter": "DNA Structure and Function"}, + "m62828": {"title": "DNA Replication in Prokaryotes", "unit": "Genetics", "chapter": "DNA Structure and Function"}, + "m62829": {"title": "DNA Replication in Eukaryotes", "unit": "Genetics", "chapter": "DNA Structure and Function"}, + "m62830": {"title": "DNA Repair", "unit": "Genetics", "chapter": "DNA Structure and Function"}, + "m62833": {"title": "Introduction", "unit": "Genetics", "chapter": "Genes and Proteins"}, + "m62837": {"title": "The Genetic Code", "unit": "Genetics", "chapter": "Genes and Proteins"}, + "m62838": {"title": "Prokaryotic Transcription", "unit": "Genetics", "chapter": "Genes and Proteins"}, + "m62840": {"title": "Eukaryotic Transcription", "unit": "Genetics", "chapter": "Genes and Proteins"}, + "m62842": {"title": "RNA Processing in Eukaryotes", "unit": "Genetics", "chapter": "Genes and Proteins"}, + "m62843": {"title": "Ribosomes and Protein Synthesis", "unit": "Genetics", "chapter": "Genes and Proteins"}, + "m62844": {"title": "Introduction", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62845": {"title": "Regulation of Gene Expression", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62846": {"title": "Prokaryotic Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62847": {"title": "Eukaryotic Epigenetic Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62848": {"title": "Eukaryotic Transcriptional Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62849": {"title": "Eukaryotic Post-transcriptional Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62850": {"title": "Eukaryotic Translational and Post-translational Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62851": {"title": "Cancer and Gene Regulation", "unit": "Genetics", "chapter": "Gene Regulation"}, + "m62852": {"title": "Introduction", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, + "m62853": {"title": "Biotechnology", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, + "m62855": {"title": "Mapping Genomes", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, + "m62857": {"title": "Whole-Genome Sequencing", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, + "m62860": {"title": "Applying Genomics", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, + "m62861": {"title": "Genomics and Proteomics", "unit": "Genetics", "chapter": "Biotechnology and Genomics"}, + "m62862": {"title": "Introduction", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, + "m62863": {"title": "Understanding Evolution", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, + "m62864": {"title": "Formation of New Species", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, + "m62865": {"title": "Reconnection and Rates of Speciation", "unit": "Evolutionary Processes", "chapter": "Evolution and Origin of Species"}, + "m62866": {"title": "Introduction", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, + "m62868": {"title": "Population Evolution", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, + "m62870": {"title": "Population Genetics", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, + "m62871": {"title": "Adaptive Evolution", "unit": "Evolutionary Processes", "chapter": "The Evolution of Populations"}, + "m62873": {"title": "Introduction", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, + "m62874": {"title": "Organizing Life on Earth", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, + "m62876": {"title": "Perspectives on the Phylogenetic Tree", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, + "m62877": {"title": "Introduction", "unit": "Biological Diversity", "chapter": "Viruses"}, + "m62881": {"title": "Viral Evolution, Morphology, and Classification", "unit": "Biological Diversity", "chapter": "Viruses"}, + "m62882": {"title": "Virus Infection and Hosts", "unit": "Biological Diversity", "chapter": "Viruses"}, + "m62887": {"title": "Other Acellular Entities: Prions and Viroids", "unit": "Biological Diversity", "chapter": "Viruses"}, + "m62889": {"title": "Introduction", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, + "m62891": {"title": "Prokaryotic Diversity", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, + "m62893": {"title": "Structure of Prokaryotes", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, + "m62894": {"title": "Prokaryotic Metabolism", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, + "m62896": {"title": "Bacterial Diseases in Humans", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, + "m62897": {"title": "Beneficial Prokaryotes", "unit": "Biological Diversity", "chapter": "Prokaryotes: Bacteria and Archaea"}, + "m62899": {"title": "Introduction", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, + "m62903": {"title": "Determining Evolutionary Relationships", "unit": "Evolutionary Processes", "chapter": "Phylogenies and the History of Life"}, + "m62904": {"title": "Prevention and Treatment of Viral Infections", "unit": "Biological Diversity", "chapter": "Viruses"}, + "m62905": {"title": "Stems", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, + "m62906": {"title": "Roots", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, + "m62908": {"title": "Leaves", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, + "m62912": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, + "m62916": {"title": "Animal Form and Function", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, + "m62918": {"title": "Animal Primary Tissues", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, + "m62919": {"title": "Digestive Systems", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, + "m62920": {"title": "Nutrition and Energy Production", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, + "m62921": {"title": "Digestive System Processes", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, + "m62922": {"title": "Digestive System Regulation", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, + "m62923": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, + "m62924": {"title": "Neurons and Glial Cells", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, + "m62925": {"title": "How Neurons Communicate", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, + "m62926": {"title": "The Central Nervous System", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, + "m62928": {"title": "The Peripheral Nervous System", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, + "m62929": {"title": "Nervous System Disorders", "unit": "Animal Structure and Function", "chapter": "The Nervous System"}, + "m62930": {"title": "Plant Sensory Systems and Responses", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, + "m62931": {"title": "Homeostasis", "unit": "Animal Structure and Function", "chapter": "The Animal Body: Basic Form and Function"}, + "m62933": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Animal Nutrition and the Digestive System"}, + "m62937": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, + "m62946": {"title": "Somatosensation", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, + "m62947": {"title": "Taste and Smell", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, + "m62951": {"title": "The Plant Body", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, + "m62954": {"title": "Hearing and Vestibular Sensation", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, + "m62957": {"title": "Vision", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, + "m62959": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, + "m62961": {"title": "Types of Hormones", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, + "m62963": {"title": "How Hormones Work", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, + "m62969": {"title": "Transport of Water and Solutes in Plants", "unit": "Plant Structure and Function", "chapter": "Plant Form and Physiology"}, + "m62971": {"title": "Regulation of Hormone Production", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, + "m62976": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, + "m62977": {"title": "Types of Skeletal Systems", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, + "m62978": {"title": "Bone", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, + "m62979": {"title": "Joints and Skeletal Movement", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, + "m62980": {"title": "Muscle Contraction and Locomotion", "unit": "Animal Structure and Function", "chapter": "The Musculoskeletal System"}, + "m62981": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, + "m62982": {"title": "Systems of Gas Exchange", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, + "m62987": {"title": "Breathing", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, + "m62988": {"title": "Transport of Gases in Human Bodily Fluids", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, + "m62989": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, + "m62990": {"title": "Overview of the Circulatory System", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, + "m62991": {"title": "Components of the Blood", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, + "m62992": {"title": "Mammalian Heart and Blood Vessels", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, + "m62993": {"title": "Blood Flow and Blood Pressure Regulation", "unit": "Animal Structure and Function", "chapter": "The Circulatory System"}, + "m62994": {"title": "Sensory Processes", "unit": "Animal Structure and Function", "chapter": "Sensory Systems"}, + "m62995": {"title": "Endocrine Glands", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, + "m62996": {"title": "Regulation of Body Processes", "unit": "Animal Structure and Function", "chapter": "The Endocrine System"}, + "m62997": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, + "m62998": {"title": "Gas Exchange across Respiratory Surfaces", "unit": "Animal Structure and Function", "chapter": "The Respiratory System"}, + "m63000": {"title": "Osmoregulation and Osmotic Balance", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, + "m63001": {"title": "The Kidneys and Osmoregulatory Organs", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, + "m63002": {"title": "Excretion Systems", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, + "m63003": {"title": "Nitrogenous Wastes", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, + "m63004": {"title": "Hormonal Control of Osmoregulatory Functions", "unit": "Animal Structure and Function", "chapter": "Osmotic Regulation and Excretion"}, + "m63005": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, + "m63006": {"title": "Innate Immune Response", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, + "m63007": {"title": "Adaptive Immune Response", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, + "m63008": {"title": "Antibodies", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, + "m63009": {"title": "Disruptions in the Immune System", "unit": "Animal Structure and Function", "chapter": "The Immune System"}, + "m63010": {"title": "Introduction", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63011": {"title": "Reproduction Methods", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63012": {"title": "Fertilization", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63013": {"title": "Human Reproductive Anatomy and Gametogenesis", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63014": {"title": "Hormonal Control of Human Reproduction", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63016": {"title": "Fertilization and Early Embryonic Development", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63018": {"title": "Human Pregnancy and Birth", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63019": {"title": "Introduction", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, + "m63021": {"title": "The Scope of Ecology", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, + "m63023": {"title": "Biogeography", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, + "m63024": {"title": "Terrestrial Biomes", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, + "m63025": {"title": "Aquatic Biomes", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, + "m63026": {"title": "Climate and the Effects of Global Climate Change", "unit": "Ecology", "chapter": "Ecology and the Biosphere"}, + "m63027": {"title": "Introduction", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m63028": {"title": "Population Demography", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m63029": {"title": "Life Histories and Natural Selection", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m63030": {"title": "Environmental Limits to Population Growth", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m63031": {"title": "Population Dynamics and Regulation", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m63032": {"title": "Human Population Growth", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m63033": {"title": "Community Ecology", "unit": "Ecology", "chapter": "Population and Community Ecology"}, + "m63034": {"title": "Behavioral Biology: Proximate and Ultimate Causes of Behavior", "unit": "Ecology", "chapter": "Population and Community Ecology"}, "m63035": {"title": "Introduction", "unit": "Ecology", "chapter": "Ecosystems"}, - "m63036": { - "title": "Ecology for Ecosystems", - "unit": "Ecology", - "chapter": "Ecosystems", - }, - "m63037": { - "title": "Energy Flow through Ecosystems", - "unit": "Ecology", - "chapter": "Ecosystems", - }, - "m63040": { - "title": "Biogeochemical Cycles", - "unit": "Ecology", - "chapter": "Ecosystems", - }, - "m63043": { - "title": "Organogenesis and Vertebrate Axis Formation", - "unit": "Animal Structure and Function", - "chapter": "Animal Reproduction and Development", - }, - "m63047": { - "title": "Introduction", - "unit": "Ecology", - "chapter": "Conservation Biology and Biodiversity", - }, - "m63048": { - "title": "The Biodiversity Crisis", - "unit": "Ecology", - "chapter": "Conservation Biology and Biodiversity", - }, - "m63049": { - "title": "The Importance of Biodiversity to Human Life", - "unit": "Ecology", - "chapter": "Conservation Biology and Biodiversity", - }, - "m63050": { - "title": "Threats to Biodiversity", - "unit": "Ecology", - "chapter": "Conservation Biology and Biodiversity", - }, - "m63051": { - "title": "Preserving Biodiversity", - "unit": "Ecology", - "chapter": "Conservation Biology and Biodiversity", - }, + "m63036": {"title": "Ecology for Ecosystems", "unit": "Ecology", "chapter": "Ecosystems"}, + "m63037": {"title": "Energy Flow through Ecosystems", "unit": "Ecology", "chapter": "Ecosystems"}, + "m63040": {"title": "Biogeochemical Cycles", "unit": "Ecology", "chapter": "Ecosystems"}, + "m63043": {"title": "Organogenesis and Vertebrate Axis Formation", "unit": "Animal Structure and Function", "chapter": "Animal Reproduction and Development"}, + "m63047": {"title": "Introduction", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, + "m63048": {"title": "The Biodiversity Crisis", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, + "m63049": {"title": "The Importance of Biodiversity to Human Life", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, + "m63050": {"title": "Threats to Biodiversity", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, + "m63051": {"title": "Preserving Biodiversity", "unit": "Ecology", "chapter": "Conservation Biology and Biodiversity"}, "m64279": {"title": "Preface", "unit": "Front Matter", "chapter": "Front Matter"}, - "m66717": { - "title": "Measurements and the Metric System", - "unit": "Front Matter", - "chapter": "Front Matter", - }, + "m66717": {"title": "Measurements and the Metric System", "unit": "Front Matter", "chapter": "Front Matter"}, } # Expanded keyword mappings to module IDs @@ -1329,6 +509,7 @@ "life": ["m62718"], "living things": ["m62718"], "characteristics of life": ["m62718"], + # ========================================================================== # CHAPTER 2: THE CHEMICAL FOUNDATION OF LIFE # ========================================================================== @@ -1360,6 +541,7 @@ "organic molecule": ["m62722"], "hydrocarbon": ["m62722"], "functional group": ["m62722"], + # ========================================================================== # CHAPTER 3: BIOLOGICAL MACROMOLECULES # ========================================================================== @@ -1405,6 +587,7 @@ "nucleic acids": ["m62735"], "nucleotide": ["m62735"], "nucleotides": ["m62735"], + # ========================================================================== # CHAPTER 4: CELL STRUCTURE # ========================================================================== @@ -1453,6 +636,7 @@ "tight junction": ["m62746"], "gap junction": ["m62746"], "plasmodesmata": ["m62746"], + # ========================================================================== # CHAPTER 5: STRUCTURE AND FUNCTION OF PLASMA MEMBRANES # ========================================================================== @@ -1478,6 +662,7 @@ "phagocytosis": ["m62772"], "pinocytosis": ["m62772"], "bulk transport": ["m62772"], + # ========================================================================== # CHAPTER 6: METABOLISM # ========================================================================== @@ -1511,6 +696,7 @@ "noncompetitive inhibition": ["m62778"], "allosteric": ["m62778"], "feedback inhibition": ["m62778"], + # ========================================================================== # CHAPTER 7: CELLULAR RESPIRATION # ========================================================================== @@ -1538,6 +724,7 @@ "anaerobic respiration": ["m62790"], "lactic acid fermentation": ["m62790"], "alcohol fermentation": ["m62790"], + # ========================================================================== # CHAPTER 8: PHOTOSYNTHESIS # ========================================================================== @@ -1557,6 +744,7 @@ "c3 plant": ["m62796"], "c4 plant": ["m62796"], "cam plant": ["m62796"], + # ========================================================================== # CHAPTER 9: CELL COMMUNICATION # ========================================================================== @@ -1575,6 +763,7 @@ "phosphatase": ["m62799"], "apoptosis": ["m62800"], "programmed cell death": ["m62800"], + # ========================================================================== # CHAPTER 10: CELL REPRODUCTION # ========================================================================== @@ -1602,6 +791,7 @@ "tumor suppressor": ["m62806"], "p53": ["m62806"], "binary fission": ["m62808"], + # ========================================================================== # CHAPTER 11: MEIOSIS AND SEXUAL REPRODUCTION # ========================================================================== @@ -1622,6 +812,7 @@ "sexual reproduction": ["m62811"], "asexual reproduction": ["m62811"], "genetic variation": ["m62811"], + # ========================================================================== # CHAPTER 12: MENDEL'S EXPERIMENTS AND HEREDITY # ========================================================================== @@ -1645,6 +836,7 @@ "monohybrid cross": ["m62813"], "dihybrid cross": ["m62819"], "test cross": ["m62813"], + # ========================================================================== # CHAPTER 13: MODERN UNDERSTANDINGS OF INHERITANCE # ========================================================================== @@ -1669,6 +861,7 @@ "duplication": ["m62822"], "inversion": ["m62822"], "translocation": ["m62822"], + # ========================================================================== # CHAPTER 14: DNA STRUCTURE AND FUNCTION # ========================================================================== @@ -1699,6 +892,7 @@ "dna repair": ["m62830"], "mismatch repair": ["m62830"], "mutation": ["m62830"], + # ========================================================================== # CHAPTER 15: GENES AND PROTEINS # ========================================================================== @@ -1727,6 +921,7 @@ "transfer rna": ["m62843"], "rrna": ["m62843"], "ribosomal rna": ["m62843"], + # ========================================================================== # CHAPTER 16: GENE EXPRESSION # ========================================================================== @@ -1751,6 +946,7 @@ "microrna": ["m62849"], "sirna": ["m62849"], "rna interference": ["m62849"], + # ========================================================================== # CHAPTER 17: BIOTECHNOLOGY AND GENOMICS # ========================================================================== @@ -1779,6 +975,7 @@ "human genome project": ["m62857"], "proteomics": ["m62861"], "bioinformatics": ["m62860"], + # ========================================================================== # CHAPTER 18: EVOLUTION AND THE ORIGIN OF SPECIES # ========================================================================== @@ -1800,6 +997,7 @@ "convergent evolution": ["m62865"], "divergent evolution": ["m62865"], "coevolution": ["m62865"], + # ========================================================================== # CHAPTER 19: THE EVOLUTION OF POPULATIONS # ========================================================================== @@ -1819,6 +1017,7 @@ "stabilizing selection": ["m62871"], "disruptive selection": ["m62871"], "balancing selection": ["m62871"], + # ========================================================================== # CHAPTER 20: PHYLOGENIES AND THE HISTORY OF LIFE # ========================================================================== @@ -1840,6 +1039,7 @@ "homology": ["m62903"], "analogy": ["m62903"], "molecular clock": ["m62903"], + # ========================================================================== # CHAPTER 21: VIRUSES # ========================================================================== @@ -1860,6 +1060,7 @@ "antiviral": ["m62904"], "prion": ["m62887"], "viroid": ["m62887"], + # ========================================================================== # CHAPTER 22: PROKARYOTES: BACTERIA AND ARCHAEA # ========================================================================== @@ -1878,6 +1079,7 @@ "bacterial disease": ["m62896"], "antibiotic": ["m62896"], "antibiotic resistance": ["m62896"], + # ========================================================================== # CHAPTER 23: PLANT FORM AND PHYSIOLOGY # ========================================================================== @@ -1911,6 +1113,7 @@ "phototropism": ["m62930"], "gravitropism": ["m62930"], "photoperiodism": ["m62930"], + # ========================================================================== # CHAPTER 24: THE ANIMAL BODY # ========================================================================== @@ -1929,6 +1132,7 @@ "negative feedback": ["m62931"], "positive feedback": ["m62931"], "thermoregulation": ["m62931"], + # ========================================================================== # CHAPTER 25: NUTRITION AND THE DIGESTIVE SYSTEM # ========================================================================== @@ -1953,6 +1157,7 @@ "peristalsis": ["m62921"], "absorption": ["m62921"], "villi": ["m62921"], + # ========================================================================== # CHAPTER 26: THE NERVOUS SYSTEM # ========================================================================== @@ -1985,6 +1190,7 @@ "parasympathetic": ["m62928"], "somatic nervous system": ["m62928"], "reflex": ["m62928"], + # ========================================================================== # CHAPTER 27: SENSORY SYSTEMS # ========================================================================== @@ -2014,6 +1220,7 @@ "lens": ["m62957"], "cornea": ["m62957"], "photoreceptor": ["m62957"], + # ========================================================================== # CHAPTER 28: THE ENDOCRINE SYSTEM # ========================================================================== @@ -2044,6 +1251,7 @@ "estrogen": ["m62995"], "progesterone": ["m62995"], "feedback loop": ["m62971"], + # ========================================================================== # CHAPTER 29: THE MUSCULOSKELETAL SYSTEM # ========================================================================== @@ -2068,6 +1276,7 @@ "actin": ["m62980"], "myosin": ["m62980"], "sliding filament": ["m62980"], + # ========================================================================== # CHAPTER 30: THE RESPIRATORY SYSTEM # ========================================================================== @@ -2089,6 +1298,7 @@ "hemoglobin": ["m62988"], "oxygen transport": ["m62988"], "carbon dioxide transport": ["m62988"], + # ========================================================================== # CHAPTER 31: THE CIRCULATORY SYSTEM # ========================================================================== @@ -2112,6 +1322,7 @@ "diastole": ["m62992"], "atrium": ["m62992"], "ventricle": ["m62992"], + # ========================================================================== # CHAPTER 32: OSMOTIC REGULATION AND EXCRETION # ========================================================================== @@ -2135,6 +1346,7 @@ "antidiuretic hormone": ["m63004"], "adh": ["m63004"], "aldosterone": ["m63004"], + # ========================================================================== # CHAPTER 33: THE IMMUNE SYSTEM # ========================================================================== @@ -2166,6 +1378,7 @@ "autoimmune": ["m63009"], "autoimmune disease": ["m63009"], "immunodeficiency": ["m63009"], + # ========================================================================== # CHAPTER 34: ANIMAL REPRODUCTION AND DEVELOPMENT # ========================================================================== @@ -2204,6 +1417,7 @@ "fetus": ["m63018"], "labor": ["m63018"], "birth": ["m63018"], + # ========================================================================== # CHAPTER 35: ECOLOGY AND THE BIOSPHERE # ========================================================================== @@ -2232,6 +1446,7 @@ "global warming": ["m63026"], "greenhouse effect": ["m63026"], "greenhouse gas": ["m63026"], + # ========================================================================== # CHAPTER 36: POPULATION AND COMMUNITY ECOLOGY # ========================================================================== @@ -2268,6 +1483,7 @@ "animal behavior": ["m63034"], "innate behavior": ["m63034"], "learned behavior": ["m63034"], + # ========================================================================== # CHAPTER 37: ECOSYSTEMS # ========================================================================== @@ -2294,6 +1510,7 @@ "phosphorus cycle": ["m63040"], "water cycle": ["m63040"], "hydrologic cycle": ["m63040"], + # ========================================================================== # CHAPTER 38: CONSERVATION BIOLOGY AND BIODIVERSITY # ========================================================================== @@ -2341,12 +1558,12 @@ def get_module_url(module_id: str) -> str: title = info["title"] # Generate slug from title as last resort - slug = re.sub(r"[^a-z0-9]+", "-", title.lower()).strip("-") + slug = re.sub(r'[^a-z0-9]+', '-', title.lower()).strip('-') # For introduction pages, use chapter name if title == "Introduction": chapter = info["chapter"] - slug = re.sub(r"[^a-z0-9]+", "-", chapter.lower()).strip("-") + slug = re.sub(r'[^a-z0-9]+', '-', chapter.lower()).strip('-') return f"{OPENSTAX_BASE_URL}/{slug}" @@ -2363,7 +1580,6 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: List of module info dicts with id, title, unit, chapter, and url """ import logging - logger = logging.getLogger(__name__) logger.info("=" * 50) @@ -2381,23 +1597,21 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: for keyword, module_ids in KEYWORD_TO_MODULES.items(): # Use word boundary matching for single-word keywords # For multi-word keywords, require exact substring match - if " " in keyword: + if ' ' in keyword: # Multi-word keyword - exact substring match is fine if keyword in topic_lower: matched_ids.update(module_ids) matched_keywords.append(keyword) else: # Single-word keyword - require word boundaries - pattern = r"\b" + re.escape(keyword) + r"\b" + pattern = r'\b' + re.escape(keyword) + r'\b' if re.search(pattern, topic_lower): matched_ids.update(module_ids) matched_keywords.append(keyword) if matched_keywords: logger.info(f"KEYWORD MATCHES FOUND: {matched_keywords}") - logger.info( - f"Matched module IDs: {list(matched_ids)[:10]}{'...' if len(matched_ids) > 10 else ''}" - ) + logger.info(f"Matched module IDs: {list(matched_ids)[:10]}{'...' if len(matched_ids) > 10 else ''}") else: logger.info("No keyword matches found, falling back to title search...") @@ -2408,9 +1622,9 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: chapter_lower = info["chapter"].lower() # Check if any word from topic is in title or chapter - topic_words = set(re.findall(r"\b\w+\b", topic_lower)) - title_words = set(re.findall(r"\b\w+\b", title_lower)) - chapter_words = set(re.findall(r"\b\w+\b", chapter_lower)) + topic_words = set(re.findall(r'\b\w+\b', topic_lower)) + title_words = set(re.findall(r'\b\w+\b', title_lower)) + chapter_words = set(re.findall(r'\b\w+\b', chapter_lower)) if topic_words & title_words or topic_words & chapter_words: matched_ids.add(module_id) @@ -2428,15 +1642,13 @@ def search_modules(topic: str, max_results: int = 3) -> list[dict]: # Skip introduction modules unless specifically requested if info["title"] == "Introduction" and "introduction" not in topic_lower: continue - results.append( - { - "id": mid, - "title": info["title"], - "unit": info["unit"], - "chapter": info["chapter"], - "url": get_module_url(mid), - } - ) + results.append({ + "id": mid, + "title": info["title"], + "unit": info["unit"], + "chapter": info["chapter"], + "url": get_module_url(mid), + }) logger.info(f"Returning {len(results)} results: {[r['id'] for r in results]}") return results[:max_results] diff --git a/samples/personalized_learning/deploy.py b/samples/personalized_learning/deploy.py index b91ef72c0..edd677746 100644 --- a/samples/personalized_learning/deploy.py +++ b/samples/personalized_learning/deploy.py @@ -38,7 +38,6 @@ try: import certifi - _HAS_CERTIFI = True except ImportError: _HAS_CERTIFI = False @@ -82,9 +81,7 @@ def main(): args = parser.parse_args() if not args.project: - print( - "ERROR: --project flag or GOOGLE_CLOUD_PROJECT environment variable is required" - ) + print("ERROR: --project flag or GOOGLE_CLOUD_PROJECT environment variable is required") sys.exit(1) # Set context bucket (default to {project}-learner-context) @@ -122,7 +119,7 @@ def main(): # ========================================================================= # CREATE THE ADK AGENT # ========================================================================= - # Create an Agent, wrap it in AdkApp, and deploy the AdkApp directly. + # Create an Agent, wrap it in AdkApp, and deploy the AdkApp directly. # AdkApp is designed to be picklable. # ========================================================================= @@ -356,9 +353,7 @@ def main(): "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle": ["m62788"], "7-4-oxidative-phosphorylation": ["m62789"], "7-5-metabolism-without-oxygen": ["m62790"], - "7-6-connections-of-carbohydrate-protein-and-lipid-metabolic-pathways": [ - "m62791" - ], + "7-6-connections-of-carbohydrate-protein-and-lipid-metabolic-pathways": ["m62791"], "7-7-regulation-of-cellular-respiration": ["m62792"], "8-1-overview-of-photosynthesis": ["m62794"], "8-2-the-light-dependent-reaction-of-photosynthesis": ["m62795"], @@ -395,9 +390,7 @@ def main(): "16-3-eukaryotic-epigenetic-gene-regulation": ["m62847"], "16-4-eukaryotic-transcriptional-gene-regulation": ["m62848"], "16-5-eukaryotic-post-transcriptional-gene-regulation": ["m62849"], - "16-6-eukaryotic-translational-and-post-translational-gene-regulation": [ - "m62850" - ], + "16-6-eukaryotic-translational-and-post-translational-gene-regulation": ["m62850"], "16-7-cancer-and-gene-regulation": ["m62851"], "17-1-biotechnology": ["m62853"], "17-2-mapping-genomes": ["m62855"], @@ -512,24 +505,12 @@ def main(): "oxidative phosphorylation": ["7-4-oxidative-phosphorylation"], "fermentation": ["7-5-metabolism-without-oxygen"], "anaerobic": ["7-5-metabolism-without-oxygen"], - "cellular respiration": [ - "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", - "7-4-oxidative-phosphorylation", - ], - "mitochondria": [ - "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", - "7-4-oxidative-phosphorylation", - ], - "mitochondrion": [ - "7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", - "7-4-oxidative-phosphorylation", - ], + "cellular respiration": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", "7-4-oxidative-phosphorylation"], + "mitochondria": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", "7-4-oxidative-phosphorylation"], + "mitochondrion": ["7-3-oxidation-of-pyruvate-and-the-citric-acid-cycle", "7-4-oxidative-phosphorylation"], "atp": ["6-4-atp-adenosine-triphosphate", "7-4-oxidative-phosphorylation"], "adenosine triphosphate": ["6-4-atp-adenosine-triphosphate"], - "photosynthesis": [ - "8-1-overview-of-photosynthesis", - "8-2-the-light-dependent-reaction-of-photosynthesis", - ], + "photosynthesis": ["8-1-overview-of-photosynthesis", "8-2-the-light-dependent-reaction-of-photosynthesis"], "plants make food": ["8-1-overview-of-photosynthesis"], "chloroplast": ["8-1-overview-of-photosynthesis", "4-3-eukaryotic-cells"], "chlorophyll": ["8-2-the-light-dependent-reaction-of-photosynthesis"], @@ -544,33 +525,21 @@ def main(): # Molecular Biology "dna": ["14-2-dna-structure-and-sequencing", "14-3-basics-of-dna-replication"], "rna": ["15-4-rna-processing-in-eukaryotes", "3-5-nucleic-acids"], - "mrna": [ - "15-4-rna-processing-in-eukaryotes", - "15-5-ribosomes-and-protein-synthesis", - ], + "mrna": ["15-4-rna-processing-in-eukaryotes", "15-5-ribosomes-and-protein-synthesis"], "trna": ["15-5-ribosomes-and-protein-synthesis"], "rrna": ["15-5-ribosomes-and-protein-synthesis"], - "transcription": [ - "15-2-prokaryotic-transcription", - "15-3-eukaryotic-transcription", - ], + "transcription": ["15-2-prokaryotic-transcription", "15-3-eukaryotic-transcription"], "translation": ["15-5-ribosomes-and-protein-synthesis"], "protein synthesis": ["15-5-ribosomes-and-protein-synthesis"], "protein": ["3-4-proteins", "15-5-ribosomes-and-protein-synthesis"], "enzyme": ["6-5-enzymes"], "gene expression": ["16-1-regulation-of-gene-expression"], "genetic code": ["15-1-the-genetic-code"], - "central dogma": [ - "15-1-the-genetic-code", - "15-5-ribosomes-and-protein-synthesis", - ], + "central dogma": ["15-1-the-genetic-code", "15-5-ribosomes-and-protein-synthesis"], "codon": ["15-1-the-genetic-code"], "anticodon": ["15-5-ribosomes-and-protein-synthesis"], "ribosome": ["15-5-ribosomes-and-protein-synthesis", "4-3-eukaryotic-cells"], - "replication": [ - "14-3-basics-of-dna-replication", - "14-4-dna-replication-in-prokaryotes", - ], + "replication": ["14-3-basics-of-dna-replication", "14-4-dna-replication-in-prokaryotes"], # Cell Structure "cell membrane": ["5-1-components-and-structure"], "plasma membrane": ["5-1-components-and-structure"], @@ -580,10 +549,7 @@ def main(): "diffusion": ["5-2-passive-transport"], "active transport": ["5-3-active-transport"], "cytoskeleton": ["4-5-cytoskeleton"], - "organelle": [ - "4-3-eukaryotic-cells", - "4-4-the-endomembrane-system-and-proteins", - ], + "organelle": ["4-3-eukaryotic-cells", "4-4-the-endomembrane-system-and-proteins"], "nucleus": ["4-3-eukaryotic-cells"], "endoplasmic reticulum": ["4-4-the-endomembrane-system-and-proteins"], "golgi": ["4-4-the-endomembrane-system-and-proteins"], @@ -591,17 +557,11 @@ def main(): "vesicle": ["5-4-bulk-transport", "4-4-the-endomembrane-system-and-proteins"], "endocytosis": ["5-4-bulk-transport"], "exocytosis": ["5-4-bulk-transport"], - "signal transduction": [ - "9-1-signaling-molecules-and-cellular-receptors", - "9-2-propagation-of-the-signal", - ], + "signal transduction": ["9-1-signaling-molecules-and-cellular-receptors", "9-2-propagation-of-the-signal"], "cell signaling": ["9-1-signaling-molecules-and-cellular-receptors"], # Nervous System "neuron": ["26-1-neurons-and-glial-cells", "26-2-how-neurons-communicate"], - "nervous system": [ - "26-1-neurons-and-glial-cells", - "26-3-the-central-nervous-system", - ], + "nervous system": ["26-1-neurons-and-glial-cells", "26-3-the-central-nervous-system"], "brain": ["26-3-the-central-nervous-system"], "action potential": ["26-2-how-neurons-communicate"], "synapse": ["26-2-how-neurons-communicate"], @@ -609,14 +569,8 @@ def main(): "vision": ["27-5-vision"], "hearing": ["27-4-hearing-and-vestibular-sensation"], # Circulatory System - "heart": [ - "31-1-overview-of-the-circulatory-system", - "31-3-mammalian-heart-and-blood-vessels", - ], - "blood": [ - "31-2-components-of-the-blood", - "31-1-overview-of-the-circulatory-system", - ], + "heart": ["31-1-overview-of-the-circulatory-system", "31-3-mammalian-heart-and-blood-vessels"], + "blood": ["31-2-components-of-the-blood", "31-1-overview-of-the-circulatory-system"], "circulatory": ["31-1-overview-of-the-circulatory-system"], "cardiovascular": ["31-1-overview-of-the-circulatory-system"], # Immune System @@ -632,58 +586,31 @@ def main(): "stomach": ["25-1-digestive-systems"], "intestine": ["25-3-digestive-system-processes"], "hormone": ["28-1-types-of-hormones", "28-2-how-hormones-work"], - "endocrine": [ - "28-5-endocrine-glands", - "28-1-types-of-hormones", - "28-2-how-hormones-work", - ], - "endocrine system": [ - "28-5-endocrine-glands", - "28-1-types-of-hormones", - "28-2-how-hormones-work", - ], + "endocrine": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work"], + "endocrine system": ["28-5-endocrine-glands", "28-1-types-of-hormones", "28-2-how-hormones-work"], "muscle": ["29-4-muscle-contraction-and-locomotion"], "bone": ["29-2-bone"], "skeleton": ["29-1-types-of-skeletal-systems"], "kidney": ["32-2-the-kidneys-and-osmoregulatory-organs"], "excretion": ["32-3-excretion-systems"], - "reproduction": [ - "34-1-reproduction-methods", - "34-3-human-reproductive-anatomy-and-gametogenesis", - ], - "reproductive": [ - "34-1-reproduction-methods", - "34-3-human-reproductive-anatomy-and-gametogenesis", - ], - "reproductive system": [ - "34-1-reproduction-methods", - "34-3-human-reproductive-anatomy-and-gametogenesis", - "34-4-hormonal-control-of-human-reproduction", - ], + "reproduction": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], + "reproductive": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis"], + "reproductive system": ["34-1-reproduction-methods", "34-3-human-reproductive-anatomy-and-gametogenesis", "34-4-hormonal-control-of-human-reproduction"], "pregnancy": ["34-7-human-pregnancy-and-birth"], "embryo": ["34-5-fertilization-and-early-embryonic-development"], # Evolution & Genetics "evolution": ["18-1-understanding-evolution", "19-1-population-evolution"], "darwin": ["18-1-understanding-evolution"], - "natural selection": [ - "19-3-adaptive-evolution", - "36-2-life-histories-and-natural-selection", - ], + "natural selection": ["19-3-adaptive-evolution", "36-2-life-histories-and-natural-selection"], "speciation": ["18-2-formation-of-new-species"], - "genetics": [ - "12-1-mendels-experiments-and-the-laws-of-probability", - "12-3-laws-of-inheritance", - ], + "genetics": ["12-1-mendels-experiments-and-the-laws-of-probability", "12-3-laws-of-inheritance"], "mendel": ["12-1-mendels-experiments-and-the-laws-of-probability"], "inheritance": ["12-3-laws-of-inheritance"], "heredity": ["12-3-laws-of-inheritance"], "mutation": ["14-6-dna-repair"], "phylogen": ["20-2-determining-evolutionary-relationships"], # Microorganisms - "virus": [ - "21-1-viral-evolution-morphology-and-classification", - "21-2-virus-infection-and-hosts", - ], + "virus": ["21-1-viral-evolution-morphology-and-classification", "21-2-virus-infection-and-hosts"], "bacteria": ["22-1-prokaryotic-diversity", "22-4-bacterial-diseases-in-humans"], "prokaryote": ["4-2-prokaryotic-cells", "22-1-prokaryotic-diversity"], "eukaryote": ["4-3-eukaryotic-cells"], @@ -696,23 +623,14 @@ def main(): "phloem": ["23-5-transport-of-water-and-solutes-in-plants"], # Ecology "ecology": ["35-1-the-scope-of-ecology", "36-6-community-ecology"], - "ecosystem": [ - "37-1-ecology-for-ecosystems", - "37-2-energy-flow-through-ecosystems", - ], + "ecosystem": ["37-1-ecology-for-ecosystems", "37-2-energy-flow-through-ecosystems"], "food chain": ["37-2-energy-flow-through-ecosystems"], "food web": ["37-2-energy-flow-through-ecosystems"], "biome": ["35-3-terrestrial-biomes", "35-4-aquatic-biomes"], - "population": [ - "36-1-population-demography", - "36-3-environmental-limits-to-population-growth", - ], + "population": ["36-1-population-demography", "36-3-environmental-limits-to-population-growth"], "climate": ["35-5-climate-and-the-effects-of-global-climate-change"], "climate change": ["35-5-climate-and-the-effects-of-global-climate-change"], - "biodiversity": [ - "38-1-the-biodiversity-crisis", - "38-4-preserving-biodiversity", - ], + "biodiversity": ["38-1-the-biodiversity-crisis", "38-4-preserving-biodiversity"], "carbon cycle": ["37-3-biogeochemical-cycles"], "nitrogen cycle": ["37-3-biogeochemical-cycles"], # Chemistry Basics @@ -763,10 +681,10 @@ def extract_text(elem): text_parts.append(para_text.strip()) full_text = "\n".join(text_parts) - full_text = re.sub(r"\n{3,}", "\n\n", full_text) + full_text = re.sub(r'\n{3,}', '\n\n', full_text) return full_text.strip() except Exception: - return re.sub(r"<[^>]+>", " ", cnxml_content).strip() + return re.sub(r'<[^>]+>', ' ', cnxml_content).strip() def get_chapter_list_for_llm() -> str: """Return a formatted list of all chapters for LLM context. @@ -849,16 +767,14 @@ def fetch_openstax_content(topic: str) -> dict: import urllib.error topic_lower = topic.lower() - matched_slugs = ( - [] - ) # Use list to preserve order (first match = highest priority) + matched_slugs = [] # Use list to preserve order (first match = highest priority) # First try keyword matching (fast path) # Use word boundary matching to avoid false positives like "vision" in "cell division" for keyword, slugs in KEYWORD_HINTS.items(): # Check for word boundary match using regex # This ensures "vision" doesn't match "cell division" - pattern = r"\b" + re.escape(keyword) + r"\b" + pattern = r'\b' + re.escape(keyword) + r'\b' if re.search(pattern, topic_lower): for slug in slugs: if slug not in matched_slugs: @@ -877,7 +793,7 @@ def fetch_openstax_content(topic: str) -> dict: return { "content": "", "sources": [], - "note": f"I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum.", + "note": f"I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum." } chapter_slugs = list(matched_slugs)[:2] @@ -903,10 +819,8 @@ def fetch_openstax_content(topic: str) -> dict: for module_id in module_ids: github_url = f"https://raw.githubusercontent.com/openstax/osbooks-biology-bundle/main/modules/{module_id}/index.cnxml" try: - with urllib.request.urlopen( - github_url, timeout=10, context=ssl_ctx - ) as response: - cnxml = response.read().decode("utf-8") + with urllib.request.urlopen(github_url, timeout=10, context=ssl_ctx) as response: + cnxml = response.read().decode('utf-8') text = parse_cnxml_to_text(cnxml) if text: content_parts.append(f"## {title}\n\n{text}") @@ -916,13 +830,7 @@ def fetch_openstax_content(topic: str) -> dict: # Only add source if we actually got content for this chapter if chapter_content_found: - sources.append( - { - "title": title, - "url": url, - "provider": "OpenStax Biology for AP Courses", - } - ) + sources.append({"title": title, "url": url, "provider": "OpenStax Biology for AP Courses"}) return { "content": "\n\n---\n\n".join(content_parts) if content_parts else "", @@ -963,77 +871,31 @@ async def generate_flashcards( # If no OpenStax content found, return an error message instead of making up content if not textbook_context or not sources: components = [ - { - "id": "mainColumn", - "component": { - "Column": { - "children": {"explicitList": ["header", "message"]}, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "header", - "component": { - "Text": { - "text": {"literalString": f"No Content Available: {topic}"}, - "usageHint": "h3", - } - }, - }, - { - "id": "message", - "component": { - "Text": { - "text": { - "literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms." - } - } - }, - }, + {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "message"]}, "distribution": "start", "alignment": "stretch"}}}, + {"id": "header", "component": {"Text": {"text": {"literalString": f"No Content Available: {topic}"}, "usageHint": "h3"}}}, + {"id": "message", "component": {"Text": {"text": {"literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms."}}}}, ] a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, {"surfaceUpdate": {"surfaceId": SURFACE_ID, "components": components}}, ] - return json.dumps( - { - "format": "flashcards", - "a2ui": a2ui, - "surfaceId": SURFACE_ID, - "source": { - "title": "No content found", - "url": "", - "provider": "OpenStax Biology for AP Courses", - }, - } - ) + return json.dumps({"format": "flashcards", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": {"title": "No content found", "url": "", "provider": "OpenStax Biology for AP Courses"}}) - prompt = f"""Create 4 MCAT study flashcards about "{topic}" for Maria (pre-med, loves gym analogies). + prompt = f'''Create 4 MCAT study flashcards about "{topic}" for Maria (pre-med, loves gym analogies). Use gym/sports analogies in the answers where appropriate. IMPORTANT: Base all content ONLY on the textbook content provided below. Do not add information not present in the source. Textbook source content: -{textbook_context[:4000]}""" +{textbook_context[:4000]}''' flashcard_schema = { "type": "array", "items": { "type": "object", "properties": { - "front": { - "type": "string", - "description": "The question on the front of the flashcard", - }, - "back": { - "type": "string", - "description": "The answer on the back, using gym analogies", - }, - "category": { - "type": "string", - "description": "Category like Biochemistry", - }, + "front": {"type": "string", "description": "The question on the front of the flashcard"}, + "back": {"type": "string", "description": "The answer on the back, using gym analogies"}, + "category": {"type": "string", "description": "Category like Biochemistry"}, }, "required": ["front", "back", "category"], }, @@ -1051,72 +913,40 @@ async def generate_flashcards( # Handle case where LLM returns empty or invalid response if not cards or not isinstance(cards, list) or len(cards) == 0: - logger.warning( - f"LLM returned empty flashcards for topic: {topic}, sources: {[s.get('title') for s in sources]}" - ) + logger.warning(f"LLM returned empty flashcards for topic: {topic}, sources: {[s.get('title') for s in sources]}") # Create fallback flashcards - this usually means content mismatch - source_title = sources[0].get("title", topic) if sources else topic + source_title = sources[0].get('title', topic) if sources else topic cards = [ { "front": f"What are the key concepts in {source_title}?", "back": f"Review the OpenStax chapter on {source_title} for detailed information about {topic}.", - "category": "Biology", + "category": "Biology" }, { "front": f"Why is {topic} important in biology?", "back": f"Understanding {topic} is fundamental to biology. Check the source material for specific details.", - "category": "Biology", + "category": "Biology" }, ] # Build proper A2UI structure programmatically card_ids = [f"c{i+1}" for i in range(len(cards))] components = [ - { - "id": "mainColumn", - "component": { - "Column": { - "children": {"explicitList": ["header", "row"]}, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "header", - "component": { - "Text": { - "text": {"literalString": f"Study Flashcards: {topic}"}, - "usageHint": "h3", - } - }, - }, - { - "id": "row", - "component": { - "Row": { - "children": {"explicitList": card_ids}, - "distribution": "start", - "alignment": "stretch", - } - }, - }, + {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "row"]}, "distribution": "start", "alignment": "stretch"}}}, + {"id": "header", "component": {"Text": {"text": {"literalString": f"Study Flashcards: {topic}"}, "usageHint": "h3"}}}, + {"id": "row", "component": {"Row": {"children": {"explicitList": card_ids}, "distribution": "start", "alignment": "stretch"}}}, ] for i, card in enumerate(cards): - components.append( - { - "id": card_ids[i], - "component": { - "Flashcard": { - "front": {"literalString": card.get("front", "")}, - "back": {"literalString": card.get("back", "")}, - "category": { - "literalString": card.get("category", "Biochemistry") - }, - } - }, + components.append({ + "id": card_ids[i], + "component": { + "Flashcard": { + "front": {"literalString": card.get("front", "")}, + "back": {"literalString": card.get("back", "")}, + "category": {"literalString": card.get("category", "Biochemistry")}, + } } - ) + }) a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, @@ -1130,14 +960,7 @@ async def generate_flashcards( "provider": sources[0].get("provider", "OpenStax Biology for AP Courses"), } - return json.dumps( - { - "format": "flashcards", - "a2ui": a2ui, - "surfaceId": SURFACE_ID, - "source": source_info, - } - ) + return json.dumps({"format": "flashcards", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": source_info}) async def generate_quiz( tool_context: ToolContext, @@ -1169,99 +992,44 @@ async def generate_quiz( # If no OpenStax content found, return an error message instead of making up content if not textbook_context or not sources: components = [ - { - "id": "mainColumn", - "component": { - "Column": { - "children": {"explicitList": ["header", "message"]}, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "header", - "component": { - "Text": { - "text": {"literalString": f"No Content Available: {topic}"}, - "usageHint": "h3", - } - }, - }, - { - "id": "message", - "component": { - "Text": { - "text": { - "literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms." - } - } - }, - }, + {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "message"]}, "distribution": "start", "alignment": "stretch"}}}, + {"id": "header", "component": {"Text": {"text": {"literalString": f"No Content Available: {topic}"}, "usageHint": "h3"}}}, + {"id": "message", "component": {"Text": {"text": {"literalString": f"Sorry, I couldn't find any OpenStax Biology content related to '{topic}'. This topic may not be covered in the AP Biology curriculum, or try rephrasing your request with more specific biology terms."}}}}, ] a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, {"surfaceUpdate": {"surfaceId": SURFACE_ID, "components": components}}, ] - return json.dumps( - { - "format": "quiz", - "a2ui": a2ui, - "surfaceId": SURFACE_ID, - "source": { - "title": "No content found", - "url": "", - "provider": "OpenStax Biology for AP Courses", - }, - } - ) + return json.dumps({"format": "quiz", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": {"title": "No content found", "url": "", "provider": "OpenStax Biology for AP Courses"}}) - prompt = f"""Create 2 MCAT quiz questions about "{topic}" for Maria (pre-med, loves gym analogies). + prompt = f'''Create 2 MCAT quiz questions about "{topic}" for Maria (pre-med, loves gym analogies). Each question should have 4 options (a, b, c, d) with exactly one correct answer. Use gym/sports analogies in explanations where appropriate. IMPORTANT: Base all content ONLY on the textbook content provided below. Do not add information not present in the source. Textbook source content: -{textbook_context[:4000]}""" +{textbook_context[:4000]}''' quiz_schema = { "type": "array", "items": { "type": "object", "properties": { - "question": { - "type": "string", - "description": "The MCAT-style question", - }, + "question": {"type": "string", "description": "The MCAT-style question"}, "options": { "type": "array", "items": { "type": "object", "properties": { - "label": { - "type": "string", - "description": "The option text", - }, - "value": { - "type": "string", - "description": "Option identifier (a, b, c, or d)", - }, - "isCorrect": { - "type": "boolean", - "description": "True if this is the correct answer", - }, + "label": {"type": "string", "description": "The option text"}, + "value": {"type": "string", "description": "Option identifier (a, b, c, or d)"}, + "isCorrect": {"type": "boolean", "description": "True if this is the correct answer"}, }, "required": ["label", "value", "isCorrect"], }, }, - "explanation": { - "type": "string", - "description": "Detailed explanation with gym analogy", - }, - "category": { - "type": "string", - "description": "Category like Biochemistry", - }, + "explanation": {"type": "string", "description": "Detailed explanation with gym analogy"}, + "category": {"type": "string", "description": "Category like Biochemistry"}, }, "required": ["question", "options", "explanation", "category"], }, @@ -1281,97 +1049,45 @@ async def generate_quiz( if not quizzes or not isinstance(quizzes, list) or len(quizzes) == 0: logger.warning(f"LLM returned empty quiz for topic: {topic}") # Create a default quiz question based on the source content - quizzes = [ - { - "question": f"Which of the following best describes {topic}?", - "options": [ - { - "label": f"A key concept in {sources[0].get('title', 'biology')}", - "value": "a", - "isCorrect": True, - }, - { - "label": "A topic not covered in AP Biology", - "value": "b", - "isCorrect": False, - }, - { - "label": "An unrelated scientific concept", - "value": "c", - "isCorrect": False, - }, - { - "label": "None of the above", - "value": "d", - "isCorrect": False, - }, - ], - "explanation": f"Review the OpenStax chapter on {sources[0].get('title', topic)} for more details.", - "category": "Biology", - } - ] + quizzes = [{ + "question": f"Which of the following best describes {topic}?", + "options": [ + {"label": f"A key concept in {sources[0].get('title', 'biology')}", "value": "a", "isCorrect": True}, + {"label": "A topic not covered in AP Biology", "value": "b", "isCorrect": False}, + {"label": "An unrelated scientific concept", "value": "c", "isCorrect": False}, + {"label": "None of the above", "value": "d", "isCorrect": False}, + ], + "explanation": f"Review the OpenStax chapter on {sources[0].get('title', topic)} for more details.", + "category": "Biology" + }] # Build proper A2UI structure programmatically quiz_ids = [f"q{i+1}" for i in range(len(quizzes))] components = [ - { - "id": "mainColumn", - "component": { - "Column": { - "children": {"explicitList": ["header", "row"]}, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "header", - "component": { - "Text": { - "text": {"literalString": f"Quick Quiz: {topic}"}, - "usageHint": "h3", - } - }, - }, - { - "id": "row", - "component": { - "Row": { - "children": {"explicitList": quiz_ids}, - "distribution": "start", - "alignment": "stretch", - } - }, - }, + {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "row"]}, "distribution": "start", "alignment": "stretch"}}}, + {"id": "header", "component": {"Text": {"text": {"literalString": f"Quick Quiz: {topic}"}, "usageHint": "h3"}}}, + {"id": "row", "component": {"Row": {"children": {"explicitList": quiz_ids}, "distribution": "start", "alignment": "stretch"}}}, ] for i, quiz in enumerate(quizzes): # Transform options to A2UI format options = [] for opt in quiz.get("options", []): - options.append( - { - "label": {"literalString": opt.get("label", "")}, - "value": opt.get("value", ""), - "isCorrect": opt.get("isCorrect", False), + options.append({ + "label": {"literalString": opt.get("label", "")}, + "value": opt.get("value", ""), + "isCorrect": opt.get("isCorrect", False), + }) + components.append({ + "id": quiz_ids[i], + "component": { + "QuizCard": { + "question": {"literalString": quiz.get("question", "")}, + "options": options, + "explanation": {"literalString": quiz.get("explanation", "")}, + "category": {"literalString": quiz.get("category", "Biochemistry")}, } - ) - components.append( - { - "id": quiz_ids[i], - "component": { - "QuizCard": { - "question": {"literalString": quiz.get("question", "")}, - "options": options, - "explanation": { - "literalString": quiz.get("explanation", "") - }, - "category": { - "literalString": quiz.get("category", "Biochemistry") - }, - } - }, } - ) + }) a2ui = [ {"beginRendering": {"surfaceId": SURFACE_ID, "root": "mainColumn"}}, @@ -1385,14 +1101,7 @@ async def generate_quiz( "provider": sources[0].get("provider", "OpenStax Biology for AP Courses"), } - return json.dumps( - { - "format": "quiz", - "a2ui": a2ui, - "surfaceId": SURFACE_ID, - "source": source_info, - } - ) + return json.dumps({"format": "quiz", "a2ui": a2ui, "surfaceId": SURFACE_ID, "source": source_info}) async def get_textbook_content( tool_context: ToolContext, @@ -1412,31 +1121,25 @@ async def get_textbook_content( sources = openstax_data.get("sources", []) if not content: - return json.dumps( - { - "content": f"No specific textbook content found for '{topic}'. Please use general biology knowledge.", - "sources": [], - } - ) + return json.dumps({ + "content": f"No specific textbook content found for '{topic}'. Please use general biology knowledge.", + "sources": [] + }) # Format source citations source_citations = [] for src in sources: - source_citations.append( - { - "title": src.get("title", ""), - "url": src.get("url", ""), - "provider": src.get("provider", "OpenStax Biology for AP Courses"), - } - ) - - return json.dumps( - { - # Limit content length. Okay for a demo but could be improved - "content": content[:4000], - "sources": source_citations, - } - ) + source_citations.append({ + "title": src.get("title", ""), + "url": src.get("url", ""), + "provider": src.get("provider", "OpenStax Biology for AP Courses"), + }) + + return json.dumps({ + # Limit content length. Okay for a demo but could be improved + "content": content[:4000], + "sources": source_citations + }) # GCS media URLs (publicly accessible) # Media bucket follows pattern: {PROJECT_ID}-media @@ -1455,46 +1158,10 @@ async def get_audio_content(tool_context: ToolContext) -> str: A2UI JSON string for AudioPlayer component """ components = [ - { - "id": "mainColumn", - "component": { - "Column": { - "children": {"explicitList": ["header", "descText", "player"]}, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "header", - "component": { - "Text": { - "text": {"literalString": "Personalized Learning Podcast"}, - "usageHint": "h3", - } - }, - }, - { - "id": "descText", - "component": { - "Text": { - "text": { - "literalString": "A podcast tailored for Maria covering ATP, bond energy, and common MCAT misconceptions. Uses gym and sports analogies to explain complex biochemistry concepts." - } - } - }, - }, - { - "id": "player", - "component": { - "AudioPlayer": { - "url": {"literalString": PODCAST_URL}, - "description": { - "literalString": "ATP & Bond Energy - MCAT Review" - }, - } - }, - }, + {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "descText", "player"]}, "distribution": "start", "alignment": "stretch"}}}, + {"id": "header", "component": {"Text": {"text": {"literalString": "Personalized Learning Podcast"}, "usageHint": "h3"}}}, + {"id": "descText", "component": {"Text": {"text": {"literalString": "A podcast tailored for Maria covering ATP, bond energy, and common MCAT misconceptions. Uses gym and sports analogies to explain complex biochemistry concepts."}}}}, + {"id": "player", "component": {"AudioPlayer": {"url": {"literalString": PODCAST_URL}, "description": {"literalString": "ATP & Bond Energy - MCAT Review"}}}}, ] a2ui = [ @@ -1512,41 +1179,10 @@ async def get_video_content(tool_context: ToolContext) -> str: A2UI JSON string for Video component """ components = [ - { - "id": "mainColumn", - "component": { - "Column": { - "children": { - "explicitList": ["header", "descText", "videoPlayer"] - }, - "distribution": "start", - "alignment": "stretch", - } - }, - }, - { - "id": "header", - "component": { - "Text": { - "text": {"literalString": "Video Lesson"}, - "usageHint": "h3", - } - }, - }, - { - "id": "descText", - "component": { - "Text": { - "text": { - "literalString": "A visual explanation of ATP hydrolysis and bond energy concepts, designed for visual learners preparing for the MCAT." - } - } - }, - }, - { - "id": "videoPlayer", - "component": {"Video": {"url": {"literalString": VIDEO_URL}}}, - }, + {"id": "mainColumn", "component": {"Column": {"children": {"explicitList": ["header", "descText", "videoPlayer"]}, "distribution": "start", "alignment": "stretch"}}}, + {"id": "header", "component": {"Text": {"text": {"literalString": "Video Lesson"}, "usageHint": "h3"}}}, + {"id": "descText", "component": {"Text": {"text": {"literalString": "A visual explanation of ATP hydrolysis and bond energy concepts, designed for visual learners preparing for the MCAT."}}}}, + {"id": "videoPlayer", "component": {"Video": {"url": {"literalString": VIDEO_URL}}}}, ] a2ui = [ @@ -1587,13 +1223,7 @@ async def get_video_content(tool_context: ToolContext) -> str: - Visual-kinesthetic learner Always use gym/sports analogies where appropriate. Be encouraging and supportive.""", - tools=[ - generate_flashcards, - generate_quiz, - get_textbook_content, - get_audio_content, - get_video_content, - ], + tools=[generate_flashcards, generate_quiz, get_textbook_content, get_audio_content, get_video_content], ) # Wrap agent in AdkApp for deployment (skip App wrapper to avoid version issues) @@ -1622,11 +1252,9 @@ async def get_video_content(tool_context: ToolContext) -> str: print("Next steps:") print(" 1. Copy the Resource ID above") print(" 2. Paste it into the notebook's AGENT_RESOURCE_ID variable") - print( - f" 3. Upload learner context files to gs://{context_bucket}/learner_context/" - ) + print(f" 3. Upload learner context files to gs://{context_bucket}/learner_context/") print(" 4. Run the remaining notebook cells to configure and start the demo") if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/samples/personalized_learning/deploy_hosting.py b/samples/personalized_learning/deploy_hosting.py index be7ad8e79..80ff9f1ef 100755 --- a/samples/personalized_learning/deploy_hosting.py +++ b/samples/personalized_learning/deploy_hosting.py @@ -60,9 +60,7 @@ DEFAULT_REGION = "us-central1" -def run_command( - cmd: list[str], check: bool = True, capture: bool = False -) -> subprocess.CompletedProcess: +def run_command(cmd: list[str], check: bool = True, capture: bool = False) -> subprocess.CompletedProcess: """Run a shell command and optionally capture output.""" print(f" → {' '.join(cmd)}") return subprocess.run( @@ -128,11 +126,7 @@ def prepare_build_context(demo_dir: Path) -> Path: shutil.rmtree(web_core_dest) print(f" Copying {web_core_source} → {web_core_dest}") - shutil.copytree( - web_core_source, - web_core_dest, - ignore=shutil.ignore_patterns("node_modules", ".git"), - ) + shutil.copytree(web_core_source, web_core_dest, ignore=shutil.ignore_patterns("node_modules", ".git")) # Copy lit (the main web-lib) a2ui_source = renderers_dir / "lit" @@ -148,18 +142,13 @@ def prepare_build_context(demo_dir: Path) -> Path: # Copy the dependency (excluding node_modules, but keeping dist/ for pre-built output) print(f" Copying {a2ui_source} → {a2ui_dest}") - shutil.copytree( - a2ui_source, a2ui_dest, ignore=shutil.ignore_patterns("node_modules", ".git") - ) + shutil.copytree(a2ui_source, a2ui_dest, ignore=shutil.ignore_patterns("node_modules", ".git")) # Update lit's package.json to point to the local web_core copy lit_package_json = a2ui_dest / "package.json" if lit_package_json.exists(): content = lit_package_json.read_text() - content = content.replace( - '"@a2ui/web_core": "file:../web_core"', - '"@a2ui/web_core": "file:../a2ui-web-core"', - ) + content = content.replace('"@a2ui/web_core": "file:../web_core"', '"@a2ui/web_core": "file:../a2ui-web-core"') lit_package_json.write_text(content) print(" Updated lit package.json to reference local web_core") @@ -191,37 +180,23 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: # Enable required APIs first and wait for propagation print("\nEnabling required APIs...") - run_command( - [ - "gcloud", - "services", - "enable", - "run.googleapis.com", - "cloudbuild.googleapis.com", - "artifactregistry.googleapis.com", - "iap.googleapis.com", - "aiplatform.googleapis.com", # For Gemini API access - "--project", - project_id, - "--quiet", - ], - check=False, - ) # Don't fail if already enabled + run_command([ + "gcloud", "services", "enable", + "run.googleapis.com", + "cloudbuild.googleapis.com", + "artifactregistry.googleapis.com", + "iap.googleapis.com", + "aiplatform.googleapis.com", # For Gemini API access + "--project", project_id, + "--quiet", + ], check=False) # Don't fail if already enabled # Get project number for IAM bindings print("\nConfiguring IAM permissions for Cloud Build...") - result = run_command( - [ - "gcloud", - "projects", - "describe", - project_id, - "--format", - "value(projectNumber)", - ], - capture=True, - check=False, - ) + result = run_command([ + "gcloud", "projects", "describe", project_id, + "--format", "value(projectNumber)", + ], capture=True, check=False) project_number = result.stdout.strip() if result.returncode == 0 else None if project_number: @@ -229,105 +204,57 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: compute_sa = f"{project_number}-compute@developer.gserviceaccount.com" # Grant storage admin to the compute service account - run_command( - [ - "gcloud", - "projects", - "add-iam-policy-binding", - project_id, - "--member", - f"serviceAccount:{compute_sa}", - "--role", - "roles/storage.objectViewer", - "--quiet", - ], - check=False, - ) + run_command([ + "gcloud", "projects", "add-iam-policy-binding", project_id, + "--member", f"serviceAccount:{compute_sa}", + "--role", "roles/storage.objectViewer", + "--quiet", + ], check=False) # Grant logging permissions so we can see build logs - run_command( - [ - "gcloud", - "projects", - "add-iam-policy-binding", - project_id, - "--member", - f"serviceAccount:{compute_sa}", - "--role", - "roles/logging.logWriter", - "--quiet", - ], - check=False, - ) + run_command([ + "gcloud", "projects", "add-iam-policy-binding", project_id, + "--member", f"serviceAccount:{compute_sa}", + "--role", "roles/logging.logWriter", + "--quiet", + ], check=False) # Grant Artifact Registry writer permission to compute service account # Cloud Run source deployments use the compute SA to push Docker images - run_command( - [ - "gcloud", - "projects", - "add-iam-policy-binding", - project_id, - "--member", - f"serviceAccount:{compute_sa}", - "--role", - "roles/artifactregistry.writer", - "--quiet", - ], - check=False, - ) + run_command([ + "gcloud", "projects", "add-iam-policy-binding", project_id, + "--member", f"serviceAccount:{compute_sa}", + "--role", "roles/artifactregistry.writer", + "--quiet", + ], check=False) # Also grant Cloud Build service account permissions cloudbuild_sa = f"{project_number}@cloudbuild.gserviceaccount.com" - run_command( - [ - "gcloud", - "projects", - "add-iam-policy-binding", - project_id, - "--member", - f"serviceAccount:{cloudbuild_sa}", - "--role", - "roles/storage.objectViewer", - "--quiet", - ], - check=False, - ) + run_command([ + "gcloud", "projects", "add-iam-policy-binding", project_id, + "--member", f"serviceAccount:{cloudbuild_sa}", + "--role", "roles/storage.objectViewer", + "--quiet", + ], check=False) # Grant Artifact Registry writer permission for pushing Docker images # This is required for Cloud Run source deployments - run_command( - [ - "gcloud", - "projects", - "add-iam-policy-binding", - project_id, - "--member", - f"serviceAccount:{cloudbuild_sa}", - "--role", - "roles/artifactregistry.writer", - "--quiet", - ], - check=False, - ) + run_command([ + "gcloud", "projects", "add-iam-policy-binding", project_id, + "--member", f"serviceAccount:{cloudbuild_sa}", + "--role", "roles/artifactregistry.writer", + "--quiet", + ], check=False) # Grant Vertex AI User permission to the compute service account # This allows Cloud Run to call the Gemini API print("\nGranting Vertex AI permissions to Cloud Run service account...") - run_command( - [ - "gcloud", - "projects", - "add-iam-policy-binding", - project_id, - "--member", - f"serviceAccount:{compute_sa}", - "--role", - "roles/aiplatform.user", - "--quiet", - ], - check=False, - ) + run_command([ + "gcloud", "projects", "add-iam-policy-binding", project_id, + "--member", f"serviceAccount:{compute_sa}", + "--role", "roles/aiplatform.user", + "--quiet", + ], check=False) print("Waiting for API and IAM permissions to propagate (30 seconds)...") time.sleep(30) @@ -354,21 +281,13 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: # We use --allow-unauthenticated since Firebase Auth handles access control. # The app requires @google.com sign-in (configurable in src/firebase-auth.ts). cmd = [ - "gcloud", - "run", - "deploy", - service_name, - "--source", - str(demo_dir), - "--region", - region, - "--project", - project_id, + "gcloud", "run", "deploy", service_name, + "--source", str(demo_dir), + "--region", region, + "--project", project_id, "--allow-unauthenticated", # Firebase Auth handles access control - "--memory", - "1Gi", - "--timeout", - "300", + "--memory", "1Gi", + "--timeout", "300", "--quiet", # Auto-confirm prompts (e.g., enabling APIs) ] @@ -379,22 +298,12 @@ def deploy_cloud_run(project_id: str, service_name: str, region: str) -> str: run_command(cmd) # Get the service URL - result = run_command( - [ - "gcloud", - "run", - "services", - "describe", - service_name, - "--region", - region, - "--project", - project_id, - "--format", - "value(status.url)", - ], - capture=True, - ) + result = run_command([ + "gcloud", "run", "services", "describe", service_name, + "--region", region, + "--project", project_id, + "--format", "value(status.url)", + ], capture=True) service_url = result.stdout.strip() print(f"\nCloud Run URL: {service_url}") @@ -448,38 +357,23 @@ def configure_iap_access( print(" The service will be protected but no one can access it yet.") print("\n To grant access later, use:") print(f" gcloud run services add-iam-policy-binding {service_name} \\") - print( - f" --region={region} --member='user:EMAIL' --role='roles/run.invoker'" - ) + print(f" --region={region} --member='user:EMAIL' --role='roles/run.invoker'") print("\n Or for a domain:") print(f" gcloud run services add-iam-policy-binding {service_name} \\") - print( - f" --region={region} --member='domain:DOMAIN' --role='roles/run.invoker'" - ) + print(f" --region={region} --member='domain:DOMAIN' --role='roles/run.invoker'") return # Grant Cloud Run Invoker role to each member for member in members_to_add: print(f"\n Granting Cloud Run Invoker to {member}...") - run_command( - [ - "gcloud", - "run", - "services", - "add-iam-policy-binding", - service_name, - "--region", - region, - "--project", - project_id, - "--member", - member, - "--role", - "roles/run.invoker", - "--quiet", - ], - check=False, - ) + run_command([ + "gcloud", "run", "services", "add-iam-policy-binding", service_name, + "--region", region, + "--project", project_id, + "--member", member, + "--role", "roles/run.invoker", + "--quiet", + ], check=False) print("\n IAP access configured successfully.") @@ -491,10 +385,20 @@ def update_firebase_config(service_name: str, region: str): config = { "hosting": { "public": "public", - "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], - "rewrites": [ - {"source": "**", "run": {"serviceId": service_name, "region": region}} + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" ], + "rewrites": [ + { + "source": "**", + "run": { + "serviceId": service_name, + "region": region + } + } + ] } } @@ -509,7 +413,11 @@ def update_firebaserc(project_id: str): """Update .firebaserc with the project ID.""" firebaserc_path = Path(__file__).parent / ".firebaserc" - config = {"projects": {"default": project_id}} + config = { + "projects": { + "default": project_id + } + } with open(firebaserc_path, "w") as f: json.dump(config, f, indent=2) @@ -528,17 +436,11 @@ def deploy_firebase_hosting(project_id: str): print() # Deploy hosting only - run_command( - [ - "firebase", - "deploy", - "--only", - "hosting", - "--project", - project_id, - ], - check=True, - ) + run_command([ + "firebase", "deploy", + "--only", "hosting", + "--project", project_id, + ], check=True) def main(): @@ -604,9 +506,7 @@ def main(): sys.exit(1) if not args.cloud_run_only and not tools["firebase"]: - print( - "ERROR: firebase CLI not found. Install with: npm install -g firebase-tools" - ) + print("ERROR: firebase CLI not found. Install with: npm install -g firebase-tools") sys.exit(1) # Change to the demo directory @@ -645,9 +545,7 @@ def main(): if not args.cloud_run_only: print(f"\n✅ Demo is live at: https://{project_id}.web.app") print("\nAccess is controlled by Firebase Authentication.") - print( - "Users must sign in with a @google.com account (configurable in src/firebase-auth.ts)." - ) + print("Users must sign in with a @google.com account (configurable in src/firebase-auth.ts).") if args.cloud_run_only: print(f"\nCloud Run service: {args.service_name}") @@ -660,12 +558,8 @@ def main(): print(f" Allowed users: {args.allow_users}") else: print("\n⚠️ Cloud Run deployed with --no-allow-unauthenticated.") - print( - f" Grant access with: gcloud run services add-iam-policy-binding {args.service_name} \\" - ) - print( - f" --region={args.region} --member='user:EMAIL' --role='roles/run.invoker'" - ) + print(f" Grant access with: gcloud run services add-iam-policy-binding {args.service_name} \\") + print(f" --region={args.region} --member='user:EMAIL' --role='roles/run.invoker'") print() diff --git a/specification/scripts/validate.py b/specification/scripts/validate.py index b819902f4..b5c32ebb5 100755 --- a/specification/scripts/validate.py +++ b/specification/scripts/validate.py @@ -21,87 +21,55 @@ import sys import shutil - def run_ajv(schema_path, data_paths, refs=None): """Runs ajv validate via subprocess. Batch validates multiple data paths.""" repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) # Try to find local ajv in specification/v0_9/test first - local_ajv = os.path.join( - repo_root, "specification", "v0_9", "test", "node_modules", ".bin", "ajv" - ) - + local_ajv = os.path.join(repo_root, "specification", "v0_9", "test", "node_modules", ".bin", "ajv") + if os.path.exists(local_ajv): - cmd = [ - local_ajv, - "validate", - "-s", - schema_path, - "--spec=draft2020", - "--strict=false", - "-c", - "ajv-formats", - ] + cmd = [local_ajv, "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats"] else: # Fallback to pnpm dlx with both packages - cmd = [ - "pnpm", - "dlx", - "--package=ajv-cli", - "--package=ajv-formats", - "ajv", - "validate", - "-s", - schema_path, - "--spec=draft2020", - "--strict=false", - "-c", - "ajv-formats", - ] - + cmd = ["pnpm", "dlx", "--package=ajv-cli", "--package=ajv-formats", "ajv", "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats"] + if refs: for ref in refs: cmd.extend(["-r", ref]) - + for data_path in data_paths: cmd.extend(["-d", data_path]) - + result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0, result.stdout + result.stderr - def validate_messages(root_schema, example_files, refs=None, temp_dir="temp_val"): """Validates a list of JSON files where each file contains a list of messages.""" os.makedirs(temp_dir, exist_ok=True) success = True - + for example_file in sorted(example_files): print(f" Validating {os.path.basename(example_file)}...") - with open(example_file, "r") as f: + with open(example_file, 'r') as f: try: messages = json.load(f) except json.JSONDecodeError as e: print(f" [FAIL] Invalid JSON: {e}") success = False continue - - if ( - isinstance(messages, dict) - and "messages" in messages - and isinstance(messages["messages"], list) - ): + + if isinstance(messages, dict) and "messages" in messages and isinstance(messages["messages"], list): messages = messages["messages"] elif not isinstance(messages, list): - messages = [messages] + messages = [messages] temp_data_paths = [] for i, msg in enumerate(messages): - temp_data_path = os.path.join( - temp_dir, f"msg_{os.path.basename(example_file)}_{i}.json" - ) - with open(temp_data_path, "w") as f: + temp_data_path = os.path.join(temp_dir, f"msg_{os.path.basename(example_file)}_{i}.json") + with open(temp_data_path, 'w') as f: json.dump(msg, f) temp_data_paths.append(temp_data_path) - + if not temp_data_paths: print(" [SKIP] No messages to validate") continue @@ -116,70 +84,65 @@ def validate_messages(root_schema, example_files, refs=None, temp_dir="temp_val" return success - def main(): repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) - + overall_success = True - + # Configuration for versions configs = { "v0_8": { "root_schema": "specification/v0_8/json/server_to_client_with_standard_catalog.json", "refs": [], - "examples": "specification/v0_8/json/catalogs/basic/examples/*.json", + "examples": "specification/v0_8/json/catalogs/basic/examples/*.json" }, "v0_9": { "root_schema": "specification/v0_9/json/server_to_client.json", "refs": [ "specification/v0_9/json/common_types.json", - "specification/v0_9/json/basic_catalog.json", + "specification/v0_9/json/basic_catalog.json" ], - "examples": "specification/v0_9/json/catalogs/basic/examples/*.json", - }, + "examples": "specification/v0_9/json/catalogs/basic/examples/*.json" + } } - + for version, config in configs.items(): print(f"\n=== Validating {version} ===") - + version_temp_dir = os.path.join(repo_root, f"temp_val_{version}") if os.path.exists(version_temp_dir): shutil.rmtree(version_temp_dir) os.makedirs(version_temp_dir, exist_ok=True) - + root_schema = os.path.join(repo_root, config["root_schema"]) if not os.path.exists(root_schema): print(f"Error: Root schema not found at {root_schema}") overall_success = False continue - + refs = [] for ref in config["refs"]: ref_path = os.path.join(repo_root, ref) if "basic_catalog.json" in ref: # v0.9 basic_catalog needs aliasing to catalog.json as expected by server_to_client.json - with open(ref_path, "r") as f: + with open(ref_path, 'r') as f: catalog = json.load(f) if "$id" in catalog: - catalog["$id"] = catalog["$id"].replace( - "basic_catalog.json", "catalog.json" - ) + catalog["$id"] = catalog["$id"].replace("basic_catalog.json", "catalog.json") alias_path = os.path.join(version_temp_dir, "catalog.json") - with open(alias_path, "w") as f: + with open(alias_path, 'w') as f: json.dump(catalog, f) refs.append(alias_path) else: refs.append(ref_path) - + example_pattern = os.path.join(repo_root, config["examples"]) example_files = glob.glob(example_pattern) - + if not example_files: print(f"No examples found for {version} matching {example_pattern}") else: - if not validate_messages( - root_schema, example_files, refs, version_temp_dir - ): + if not validate_messages(root_schema, example_files, refs, version_temp_dir): overall_success = False if os.path.exists(version_temp_dir): @@ -191,6 +154,5 @@ def main(): else: print("\nOverall Validation: PASSED") - if __name__ == "__main__": main() diff --git a/specification/v0_10/test/run_tests.py b/specification/v0_10/test/run_tests.py index 52fe95062..6d70f6be8 100755 --- a/specification/v0_10/test/run_tests.py +++ b/specification/v0_10/test/run_tests.py @@ -36,7 +36,6 @@ "client_to_server.json": os.path.join(SCHEMA_DIR, "client_to_server.json"), } - def setup_catalog_alias(catalog_file="basic_catalog.json"): """ Creates a temporary catalog.json from basic_catalog.json (or the @@ -51,7 +50,7 @@ def setup_catalog_alias(catalog_file="basic_catalog.json"): print(f"Error: Catalog file not found: {catalog_file}") sys.exit(1) - with open(basic_catalog_path, "r") as f: + with open(basic_catalog_path, 'r') as f: try: catalog = json.load(f) except json.JSONDecodeError as e: @@ -66,46 +65,21 @@ def setup_catalog_alias(catalog_file="basic_catalog.json"): base_url = catalog["$id"].rsplit("/", 1)[0] catalog["$id"] = f"{base_url}/catalog.json" - with open(TEMP_CATALOG_FILE, "w") as f: - json.dump(catalog, f, indent=2) + with open(TEMP_CATALOG_FILE, 'w') as f: + json.dump(catalog, f, indent=2) def cleanup_catalog_alias(): if os.path.exists(TEMP_CATALOG_FILE): os.remove(TEMP_CATALOG_FILE) - def validate_ajv(schema_path, data_path, all_schemas): """Runs ajv validate via subprocess.""" local_ajv = os.path.join(TEST_DIR, "node_modules", ".bin", "ajv") if os.path.exists(local_ajv): - cmd = [ - local_ajv, - "validate", - "-s", - schema_path, - "--spec=draft2020", - "--strict=false", - "-c", - "ajv-formats", - "-d", - data_path, - ] + cmd = [local_ajv, "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] else: - cmd = [ - "pnpm", - "dlx", - "ajv-cli", - "validate", - "-s", - schema_path, - "--spec=draft2020", - "--strict=false", - "-c", - "ajv-formats", - "-d", - data_path, - ] + cmd = ["pnpm", "dlx", "ajv-cli", "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] # Add all other schemas as references for name, path in all_schemas.items(): @@ -116,14 +90,11 @@ def validate_ajv(schema_path, data_path, all_schemas): result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0, result.stdout + result.stderr except FileNotFoundError: - print( - "Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install')." - ) + print("Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install').") sys.exit(1) - def run_suite(suite_path): - with open(suite_path, "r") as f: + with open(suite_path, 'r') as f: try: suite = json.load(f) except json.JSONDecodeError as e: @@ -154,7 +125,7 @@ def run_suite(suite_path): data = test.get("data") # Write data to temp file - with open(TEMP_FILE, "w") as f: + with open(TEMP_FILE, 'w') as f: json.dump(data, f) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -167,13 +138,12 @@ def run_suite(suite_path): print(f" [FAIL] {description}") print(f" Expected Valid: {expect_valid}, Got Valid: {is_valid}") if not is_valid: - print(f" Output: {output.strip()}") + print(f" Output: {output.strip()}") return passed, failed finally: cleanup_catalog_alias() - def validate_jsonl_example(jsonl_path): if not os.path.exists(jsonl_path): print(f"Error: Example file not found: {jsonl_path}") @@ -188,14 +158,14 @@ def validate_jsonl_example(jsonl_path): setup_catalog_alias() try: - with open(jsonl_path, "r") as f: + with open(jsonl_path, 'r') as f: for i, line in enumerate(f): line = line.strip() if not line: continue # Use temp file for each line - with open(TEMP_FILE, "w") as tf: + with open(TEMP_FILE, 'w') as tf: tf.write(line) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -211,7 +181,6 @@ def validate_jsonl_example(jsonl_path): finally: cleanup_catalog_alias() - def main(): if not os.path.exists(CASES_DIR): print(f"No cases directory found at {CASES_DIR}") @@ -235,7 +204,7 @@ def main(): total_passed += p total_failed += f - print("\n" + "=" * 30) + print("\n" + "="*30) print(f"Total Passed: {total_passed}") print(f"Total Failed: {total_failed}") @@ -246,6 +215,5 @@ def main(): if total_failed > 0: sys.exit(1) - if __name__ == "__main__": main() diff --git a/specification/v0_9/test/run_tests.py b/specification/v0_9/test/run_tests.py index 3bff4bccb..2df780450 100755 --- a/specification/v0_9/test/run_tests.py +++ b/specification/v0_9/test/run_tests.py @@ -36,7 +36,6 @@ "client_to_server.json": os.path.join(SCHEMA_DIR, "client_to_server.json"), } - def setup_catalog_alias(): """ Creates a temporary catalog.json from basic_catalog.json @@ -47,7 +46,7 @@ def setup_catalog_alias(): print(f"Error: basic_catalog.json not found at {basic_catalog_path}") sys.exit(1) - with open(basic_catalog_path, "r") as f: + with open(basic_catalog_path, 'r') as f: try: catalog = json.load(f) except json.JSONDecodeError as e: @@ -59,47 +58,21 @@ def setup_catalog_alias(): # and have it resolve to this schema content. if "$id" in catalog: catalog["$id"] = catalog["$id"].replace("basic_catalog.json", "catalog.json") - - with open(TEMP_CATALOG_FILE, "w") as f: + + with open(TEMP_CATALOG_FILE, 'w') as f: json.dump(catalog, f, indent=2) - def cleanup_catalog_alias(): if os.path.exists(TEMP_CATALOG_FILE): os.remove(TEMP_CATALOG_FILE) - def validate_ajv(schema_path, data_path, all_schemas): """Runs ajv validate via subprocess.""" local_ajv = os.path.join(TEST_DIR, "node_modules", ".bin", "ajv") if os.path.exists(local_ajv): - cmd = [ - local_ajv, - "validate", - "-s", - schema_path, - "--spec=draft2020", - "--strict=false", - "-c", - "ajv-formats", - "-d", - data_path, - ] + cmd = [local_ajv, "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] else: - cmd = [ - "pnpm", - "dlx", - "ajv-cli", - "validate", - "-s", - schema_path, - "--spec=draft2020", - "--strict=false", - "-c", - "ajv-formats", - "-d", - data_path, - ] + cmd = ["pnpm", "dlx", "ajv-cli", "validate", "-s", schema_path, "--spec=draft2020", "--strict=false", "-c", "ajv-formats", "-d", data_path] # Add all other schemas as references for name, path in all_schemas.items(): @@ -110,14 +83,11 @@ def validate_ajv(schema_path, data_path, all_schemas): result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0, result.stdout + result.stderr except FileNotFoundError: - print( - "Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install')." - ) + print("Error: 'ajv' command not found. Please ensure dependencies are installed (e.g., 'pnpm install').") sys.exit(1) - def run_suite(suite_path): - with open(suite_path, "r") as f: + with open(suite_path, 'r') as f: try: suite = json.load(f) except json.JSONDecodeError as e: @@ -144,7 +114,7 @@ def run_suite(suite_path): data = test.get("data") # Write data to temp file - with open(TEMP_FILE, "w") as f: + with open(TEMP_FILE, 'w') as f: json.dump(data, f) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -157,11 +127,10 @@ def run_suite(suite_path): print(f" [FAIL] {description}") print(f" Expected Valid: {expect_valid}, Got Valid: {is_valid}") if not is_valid: - print(f" Output: {output.strip()}") + print(f" Output: {output.strip()}") return passed, failed - def validate_jsonl_example(jsonl_path): if not os.path.exists(jsonl_path): print(f"Error: Example file not found: {jsonl_path}") @@ -174,14 +143,14 @@ def validate_jsonl_example(jsonl_path): failed = 0 schema_path = SCHEMAS["server_to_client.json"] - with open(jsonl_path, "r") as f: + with open(jsonl_path, 'r') as f: for i, line in enumerate(f): line = line.strip() if not line: continue # Use temp file for each line - with open(TEMP_FILE, "w") as tf: + with open(TEMP_FILE, 'w') as tf: tf.write(line) is_valid, output = validate_ajv(schema_path, TEMP_FILE, SCHEMAS) @@ -195,7 +164,6 @@ def validate_jsonl_example(jsonl_path): return passed, failed - def main(): if not os.path.exists(CASES_DIR): print(f"No cases directory found at {CASES_DIR}") @@ -222,7 +190,7 @@ def main(): total_passed += p total_failed += f - print("\n" + "=" * 30) + print("\n" + "="*30) print(f"Total Passed: {total_passed}") print(f"Total Failed: {total_failed}") @@ -235,6 +203,5 @@ def main(): if total_failed > 0: sys.exit(1) - if __name__ == "__main__": main() diff --git a/tools/build_catalog/build_catalog.py b/tools/build_catalog/build_catalog.py index 3fca13bff..e44487c98 100644 --- a/tools/build_catalog/build_catalog.py +++ b/tools/build_catalog/build_catalog.py @@ -24,26 +24,22 @@ from pathlib import Path from urllib.parse import urlparse - class SchemaBundler: - def __init__(self): - self.definitions = {} # Stores the content of bundled schemas - self.ref_mapping = ( - {} - ) # Maps (abs_file_path + fragment) -> internal #/$defs/ key - self.file_cache = {} # Cache loaded JSON files to avoid re-reading + self.definitions = {} # Stores the content of bundled schemas + self.ref_mapping = {} # Maps (abs_file_path + fragment) -> internal #/$defs/ key + self.file_cache = {} # Cache loaded JSON files to avoid re-reading def load_json(self, path: Path): path_str = str(path.resolve()) if path_str in self.file_cache: return self.file_cache[path_str] - + if not path.exists(): print(f"❌ Error: File not found: {path}") sys.exit(1) - with open(path, "r", encoding="utf-8") as f: + with open(path, 'r', encoding='utf-8') as f: data = json.load(f) self.file_cache[path_str] = data return data @@ -54,7 +50,7 @@ def resolve_json_pointer(self, schema, pointer): """ if not pointer or pointer == "#": return schema - + parts = pointer.lstrip("#/").split("/") current = schema try: @@ -76,68 +72,62 @@ def get_def_key(self, full_ref_id, file_stem, pointer): clean_pointer = pointer.replace("/", "_").replace("#", "").lstrip("_") if not clean_pointer: clean_pointer = "root" - + base_key = f"{file_stem}_{clean_pointer}" final_key = base_key - + # Prevent collisions for different references used_keys = set(self.ref_mapping.values()) counter = 1 while final_key in used_keys: final_key = f"{base_key}_{counter}" counter += 1 - + return final_key def process_schema(self, schema, current_file_path: Path): """ - Recursively walks the schema. - If it finds a remote $ref, it loads it, extracts the target, + Recursively walks the schema. + If it finds a remote $ref, it loads it, extracts the target, adds it to definitions, and rewrites the ref. """ if isinstance(schema, dict): # 1. Handle $ref if "$ref" in schema: ref = schema["$ref"] - + # Check if it's an external reference (doesn't start with #) if not ref.startswith("#"): # Parse URL to separate file path from fragment parsed = urlparse(ref) file_part = parsed.path fragment = parsed.fragment or "" - + # Resolve absolute path to the target file target_path = (current_file_path.parent / file_part).resolve() - + # Create a unique ID for this specific target (file + fragment) full_ref_id = f"{target_path}#{fragment}" - + if full_ref_id in self.ref_mapping: # We already bundled this, just point to it schema["$ref"] = f"#/$defs/{self.ref_mapping[full_ref_id]}" else: # New reference: Load and Process file_data = self.load_json(target_path) - + # Extract specific section if fragment exists - target_subschema = self.resolve_json_pointer( - file_data, fragment - ) - + target_subschema = self.resolve_json_pointer(file_data, fragment) + # Generate a key for $defs - def_key = self.get_def_key( - full_ref_id, target_path.stem, fragment - ) - + def_key = self.get_def_key(full_ref_id, target_path.stem, fragment) + # Store mapping immediately to handle recursion/cycles self.ref_mapping[full_ref_id] = def_key - + # Recursively process the LOADED content (it might have its own refs!) - processed_sub = self.process_schema( - target_subschema, target_path - ) - + processed_sub = self.process_schema(target_subschema, target_path) + self.definitions[def_key] = processed_sub schema["$ref"] = f"#/$defs/{def_key}" @@ -145,24 +135,24 @@ def process_schema(self, schema, current_file_path: Path): for key, value in schema.items(): if key != "$ref": schema[key] = self.process_schema(value, current_file_path) - + elif isinstance(schema, list): for i, item in enumerate(schema): schema[i] = self.process_schema(item, current_file_path) - + return schema def bundle(self, input_path): # Resolve path to ensure absolute consistency abs_input = input_path.resolve() - + # Load and process (populates self.definitions) root_data = self.load_json(abs_input) processed_root = self.process_schema(root_data, abs_input) - + # --- Construct Final Ordered Dictionary --- final_schema = {} - + # 1. Add $defs FIRST existing_defs = processed_root.get("$defs", {}) if existing_defs or self.definitions: @@ -173,44 +163,40 @@ def bundle(self, input_path): merged_defs[k] = v for k, v in self.definitions.items(): merged_defs[k] = v - + final_schema["$defs"] = merged_defs - + # 2. Add the rest of the schema properties for key, value in processed_root.items(): if key != "$defs": final_schema[key] = value - + return final_schema - def main(): - parser = argparse.ArgumentParser( - description="Bundle JSON Schema $refs into internal $defs." - ) + parser = argparse.ArgumentParser(description="Bundle JSON Schema $refs into internal $defs.") parser.add_argument("input_file", type=Path, help="Input schema file") parser.add_argument("-o", "--output", type=Path, help="Output file") - + args = parser.parse_args() - + # Default output path logic output_path = args.output if not output_path: output_path = args.input_file.parent / "dist" / args.input_file.name print(f"📦 Bundling: {args.input_file}") - + bundler = SchemaBundler() final_schema = bundler.bundle(args.input_file) - + # Ensure directory exists output_path.parent.mkdir(parents=True, exist_ok=True) - - with open(output_path, "w", encoding="utf-8") as f: + + with open(output_path, 'w', encoding='utf-8') as f: json.dump(final_schema, f, indent=2) - + print(f"✅ Created: {output_path}") - if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/tools/build_catalog/tests/test_build_catalog.py b/tools/build_catalog/tests/test_build_catalog.py index 465468b8b..63e5b3239 100644 --- a/tools/build_catalog/tests/test_build_catalog.py +++ b/tools/build_catalog/tests/test_build_catalog.py @@ -18,35 +18,32 @@ from build_catalog import SchemaBundler - def test_resolve_json_pointer(): bundler = SchemaBundler() - schema = {"definitions": {"User": {"type": "object"}}, "list": ["a", "b"]} - - # Test valid resolutions - assert bundler.resolve_json_pointer(schema, "/definitions/User") == { - "type": "object" + schema = { + "definitions": { + "User": { + "type": "object" + } + }, + "list": ["a", "b"] } + + # Test valid resolutions + assert bundler.resolve_json_pointer(schema, "/definitions/User") == {"type": "object"} assert bundler.resolve_json_pointer(schema, "/list/1") == "b" - + # Test root resolutions assert bundler.resolve_json_pointer(schema, "") == schema assert bundler.resolve_json_pointer(schema, "#") == schema - + # Test unescaping schema_with_escaped_keys = { "path/to/thing": "escaped slash", - "path~to~thing": "escaped tilde", + "path~to~thing": "escaped tilde" } - assert ( - bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~1to~1thing") - == "escaped slash" - ) - assert ( - bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~0to~0thing") - == "escaped tilde" - ) - + assert bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~1to~1thing") == "escaped slash" + assert bundler.resolve_json_pointer(schema_with_escaped_keys, "/path~0to~0thing") == "escaped tilde" def test_resolve_json_pointer_error(): bundler = SchemaBundler() @@ -59,127 +56,118 @@ def test_resolve_json_pointer_error(): with pytest.raises(SystemExit): bundler.resolve_json_pointer({"list": []}, "/list/0") - def test_get_def_key(): bundler = SchemaBundler() - assert ( - bundler.get_def_key( - "path/to/target.json#/definitions/User", "myfile", "/definitions/User" - ) - == "myfile_definitions_User" - ) + assert bundler.get_def_key("path/to/target.json#/definitions/User", "myfile", "/definitions/User") == "myfile_definitions_User" assert bundler.get_def_key("path/to/target.json#1", "myfile", "") == "myfile_root" assert bundler.get_def_key("path/to/target.json#2", "myfile", "#") == "myfile_root" - def test_get_def_key_collision(): bundler = SchemaBundler() bundler.ref_mapping["some_other_file.json#"] = "myfile_definitions_User" - - assert ( - bundler.get_def_key( - "path/to/target.json#/definitions/User", "myfile", "/definitions/User" - ) - == "myfile_definitions_User_1" - ) - + + assert bundler.get_def_key("path/to/target.json#/definitions/User", "myfile", "/definitions/User") == "myfile_definitions_User_1" + bundler.ref_mapping["yet_another_file.json#"] = "myfile_definitions_User_1" - assert ( - bundler.get_def_key( - "path/to/target.json#/definitions/User", "myfile", "/definitions/User" - ) - == "myfile_definitions_User_2" - ) - + assert bundler.get_def_key("path/to/target.json#/definitions/User", "myfile", "/definitions/User") == "myfile_definitions_User_2" def test_load_json_caching(tmp_path): # Setup dummy JSON file test_json_path = tmp_path / "test.json" test_json_path.write_text('{"hello": "world"}') - + bundler = SchemaBundler() - + # Load first time data1 = bundler.load_json(test_json_path) assert data1 == {"hello": "world"} - + # Modify file, but bundler should return cached version test_json_path.write_text('{"hello": "changed"}') data2 = bundler.load_json(test_json_path) assert data2 == {"hello": "world"} - def test_load_json_missing(tmp_path): bundler = SchemaBundler() with pytest.raises(SystemExit): bundler.load_json(tmp_path / "does_not_exist.json") - def test_process_schema_simple_ref(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"type": "string"}') - - main_schema = {"properties": {"name": {"$ref": "ext.json"}}} - + + main_schema = { + "properties": { + "name": {"$ref": "ext.json"} + } + } + bundler = SchemaBundler() processed = bundler.process_schema(main_schema, tmp_path / "main.json") - + assert processed["properties"]["name"]["$ref"] == "#/$defs/ext_root" assert "ext_root" in bundler.definitions assert bundler.definitions["ext_root"] == {"type": "string"} - def test_process_schema_with_fragment(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"definitions": {"MyString": {"type": "string"}}}') - - main_schema = {"properties": {"name": {"$ref": "ext.json#/definitions/MyString"}}} - + + main_schema = { + "properties": { + "name": {"$ref": "ext.json#/definitions/MyString"} + } + } + bundler = SchemaBundler() processed = bundler.process_schema(main_schema, tmp_path / "main.json") - + assert processed["properties"]["name"]["$ref"] == "#/$defs/ext_definitions_MyString" assert "ext_definitions_MyString" in bundler.definitions assert bundler.definitions["ext_definitions_MyString"] == {"type": "string"} - def test_process_schema_caches_refs(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"type": "string"}') - - main_schema = {"prop1": {"$ref": "ext.json"}, "prop2": {"$ref": "ext.json"}} - + + main_schema = { + "prop1": {"$ref": "ext.json"}, + "prop2": {"$ref": "ext.json"} + } + bundler = SchemaBundler() processed = bundler.process_schema(main_schema, tmp_path / "main.json") - + assert processed["prop1"]["$ref"] == "#/$defs/ext_root" assert processed["prop2"]["$ref"] == "#/$defs/ext_root" assert len(bundler.definitions) == 1 - def test_process_schema_recursive(): bundler = SchemaBundler() - schema = {"list": [{"a": 1}, {"b": 2}], "nested": {"c": 3}} + schema = { + "list": [{"a": 1}, {"b": 2}], + "nested": {"c": 3} + } processed = bundler.process_schema(schema, Path("dummy.json")) - assert processed == {"list": [{"a": 1}, {"b": 2}], "nested": {"c": 3}} - + assert processed == { + "list": [{"a": 1}, {"b": 2}], + "nested": {"c": 3} + } def test_bundle_merges_defs(tmp_path): ext_path = tmp_path / "ext.json" ext_path.write_text('{"type": "string"}') - + main_path = tmp_path / "main.json" - main_path.write_text( - '{"$defs": {"ExistingDef": {"type": "number"}}, "properties": {"a": {"$ref": "ext.json"}}}' - ) - + main_path.write_text('{"$defs": {"ExistingDef": {"type": "number"}}, "properties": {"a": {"$ref": "ext.json"}}}') + bundler = SchemaBundler() final_schema = bundler.bundle(main_path) - + assert "$defs" in final_schema assert "ExistingDef" in final_schema["$defs"] assert "ext_root" in final_schema["$defs"] assert final_schema["$defs"]["ExistingDef"] == {"type": "number"} assert final_schema["$defs"]["ext_root"] == {"type": "string"} - - assert final_schema["properties"]["a"]["$ref"] == "#/$defs/ext_root" + + assert final_schema["properties"]["a"]["$ref"] == "#/$defs/ext_root" \ No newline at end of file