diff --git a/README.md b/README.md index 3537cd0..d6129e1 100644 --- a/README.md +++ b/README.md @@ -1,465 +1,97 @@ -# Context Engineering for LLMs with Redis +# Redis Context Engineering Workshop -Learn to build production-ready AI agents with optimized context management, memory systems, and intelligent retrieval using Redis, LangGraph, and LangChain. - -[![Python](https://img.shields.io/badge/Python-3.11+-3776AB?logo=python&logoColor=white)](https://www.python.org/) -[![Redis](https://img.shields.io/badge/Redis-8.0+-DC382D?logo=redis&logoColor=white)](https://redis.io/) -[![LangChain](https://img.shields.io/badge/LangChain-0.3+-1C3C3C?logo=chainlink&logoColor=white)](https://python.langchain.com/) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) - ---- - -## What You'll Learn - -This hands-on course teaches practical context engineering patterns through building a **Course Advisor Agent**: - -- **RAG Fundamentals** — Build retrieval-augmented generation systems with Redis vector search -- **Context Engineering** — Optimize token efficiency using progressive disclosure and hierarchical context -- **LangGraph Agents** — Create observable, stateful workflows with tool calling -- **Hybrid Search** — Combine semantic search with exact-match retrieval using NER -- **Memory Systems** — Implement working memory and long-term memory for personalization -- **ReAct Pattern** — Build agents with explicit reasoning (Thought → Action → Observation) - ---- - -## Prerequisites - -| Requirement | Details | -|-------------|---------| -| **Python** | 3.11 or higher | -| **Redis Stack** | Local Docker or [Redis Cloud](https://redis.io/cloud/) | -| **OpenAI API Key** | For GPT-4o access | -| **Agent Memory Server** | For memory stages (5+) | -| **Docker** | For running Redis and Agent Memory Server | +This repository contains: +- **Workshop notebooks** in `workshop/` +- **Six staged agent demos** in `demos/` that cover baseline RAG → context engineering → full agent → ReAct → memory. --- -## Installation - -### 1. Clone the Repository - -```bash -git clone https://github.com/redis-developer/context-eng-matters.git -cd context-eng-matters -``` +## Workshop Setup -### 2. Create Virtual Environment +### Prerequisites -
-🐧 Linux / macOS +- **Python**: 3.11+ +- **Docker**: for Redis + Agent Memory Server +- **OpenAI API key**: set `OPENAI_API_KEY` +### Quick setup (recommended: `uv`) +Setup the Python environment: ```bash -# Using UV (recommended) -curl -LsSf https://astral.sh/uv/install.sh | sh uv sync - -# Or using pip -python -m venv .venv -source .venv/bin/activate -pip install -e . ``` -
- -
-🪟 Windows - -```powershell -# Using UV (recommended) - PowerShell -powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" -uv sync - -# Or using pip - PowerShell -python -m venv .venv -.venv\Scripts\Activate.ps1 -pip install -e . - -# Or using pip - Command Prompt -python -m venv .venv -.venv\Scripts\activate.bat -pip install -e . +Create an env file: ``` - -**Note:** If you get an execution policy error, run PowerShell as Administrator and execute: -```powershell -Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -``` - -**🔒 For Corporate/Intranet Environments:** - -If you encounter DNS errors or can't access GitHub (e.g., `No such host is known`), use the standard Python installation method instead: - -```powershell -# 1. Ensure Python 3.11+ is installed -python --version - -# 2. Create virtual environment with system Python -python -m venv .venv - -# 3. Activate virtual environment -.venv\Scripts\Activate.ps1 # PowerShell -# OR -.venv\Scripts\activate.bat # Command Prompt - -# 4. Upgrade pip (optional but recommended) -python -m pip install --upgrade pip - -# 5. Install dependencies -pip install -e . -``` - -**Alternative: Use `uv` with existing Python:** - -If you have `uv` installed but it can't download Python: -```powershell -# Tell uv to use your system Python instead of downloading -uv sync --python python -# OR specify exact Python path -uv sync --python C:\Python311\python.exe -``` - -**Troubleshooting Network Issues:** -- Ensure Python 3.11+ is installed from [python.org](https://www.python.org/downloads/) -- Check with your IT department about proxy settings if needed -- Use `pip` with your organization's internal PyPI mirror if available -
- -### 3. Set Environment Variables - -
-🐧 Linux / macOS - -```bash -# Create .env file from example cp .env.example .env - -# Edit .env and add your OpenAI API key -# Use your preferred editor: nano, vim, or code -nano .env -``` -
- -
-🪟 Windows - -```powershell -# PowerShell -Copy-Item .env.example .env - -# Edit .env and add your OpenAI API key -notepad .env - -# Or use VS Code -code .env -``` - -```cmd -# Command Prompt -copy .env.example .env - -# Edit .env and add your OpenAI API key -notepad .env ``` -
- -**Environment Variables:** - -| Variable | Required | Default | Description | -|----------|----------|---------|-------------| -| `OPENAI_API_KEY` | ✅ Yes | - | Your OpenAI API key for embeddings and LLM | -| `REDIS_URL` | No | `redis://localhost:6379` | Redis connection URL | -| `AGENT_MEMORY_SERVER_URL` | No | `http://localhost:8088` | Agent Memory Server URL | -| `REDIS_INDEX_NAME` | No | `course_catalog` | Redis index name for course data | -| `OPENAI_MODEL` | No | `gpt-4o` | OpenAI model to use | - -### 4. Start Services - -
-🐧 Linux / macOS - +Edit env file as needed. Start the docker infra stack: ```bash -# Start Redis and Agent Memory Server docker-compose up -d - -# Verify services are running -docker ps ``` -
- -
-🪟 Windows - -```powershell -# PowerShell or Command Prompt -docker-compose up -d - -# Verify services are running -docker ps -``` - -**Note:** Ensure Docker Desktop is installed and running on Windows. -- Download from: https://www.docker.com/products/docker-desktop/ -- WSL 2 backend is recommended for better performance -
- -### 5. Load Course Data into Redis - -The notebooks and progressive agents require course data in Redis. Load the hierarchical course data: - -
-🐧 Linux / macOS - +Load the workshop data: ```bash -# Load hierarchical courses into Redis (recommended) -uv run python -m redis_context_course.scripts.load_hierarchical_courses \ +uv run load-hierarchical-courses \ -i src/redis_context_course/data/hierarchical/hierarchical_courses.json \ --force ``` -
- -
-🪟 Windows - -```powershell -# PowerShell (use backtick for line continuation) -uv run python -m redis_context_course.scripts.load_hierarchical_courses ` - -i src/redis_context_course/data/hierarchical/hierarchical_courses.json ` - --force -``` - -```cmd -# Command Prompt (use caret for line continuation) -uv run python -m redis_context_course.scripts.load_hierarchical_courses ^ - -i src/redis_context_course/data/hierarchical/hierarchical_courses.json ^ - --force -``` - -**Or as a single line:** -```powershell -uv run python -m redis_context_course.scripts.load_hierarchical_courses -i src/redis_context_course/data/hierarchical/hierarchical_courses.json --force -``` - -**If not using `uv` (corporate/intranet environments):** -```powershell -# Ensure virtual environment is activated first -.venv\Scripts\Activate.ps1 # PowerShell -# OR -.venv\Scripts\activate.bat # Command Prompt - -# Then run the script -python -m redis_context_course.scripts.load_hierarchical_courses -i src/redis_context_course/data/hierarchical/hierarchical_courses.json --force -``` -
- -**Options:** -- `--force` / `-f`: Clear existing data before loading (use when reloading after data changes) -- `--summary-index` / `-s`: Custom index name (default: `course_summaries`) -- `--details-prefix` / `-d`: Custom details prefix (default: `course_details`) - -> **Alternative:** For backward compatibility with flat course format: -> ```bash -> uv run python -m redis_context_course.scripts.ingest_courses \ -> --catalog src/redis_context_course/data/courses.json \ -> --index-name hierarchical_courses \ -> --clear -> ``` -> **Note:** If you regenerate the course catalog, always use `--force` to reload Redis data. - -### 6. Verify Installation - -
-🐧 Linux / macOS +### Verification (optional) ```bash -# Run tests with uv uv run pytest tests/ -v - -# Or with pip (if virtual environment is activated) -pytest tests/ -v ``` -
- -
-🪟 Windows -```powershell -# With uv -uv run pytest tests/ -v - -# Or with pip (ensure virtual environment is activated) -.venv\Scripts\Activate.ps1 # PowerShell -pytest tests/ -v - -# Command Prompt -.venv\Scripts\activate.bat -pytest tests/ -v -``` -
+- **Troubleshooting**: see `SETUP.md` --- -## Quick Start +## Workshop Outline -Try the ReAct agent with visible reasoning in under 2 minutes: +This workshop guides you through the essential steps of building advanced agentic systems: starting with foundational context engineering concepts, progressing through RAG techniques, diving into practical data engineering, and culminating in the design of memory-enhanced AI agents. -```bash -cd progressive_agents/stage4_hybrid_search - -# Ask about a course with visible reasoning -python cli.py --show-reasoning "What are the prerequisites for CS002?" -``` - -**Windows (PowerShell/Command Prompt):** -```powershell -cd progressive_agents\stage4_hybrid_search -python cli.py --show-reasoning "What are the prerequisites for CS002?" -``` - -**Example output:** -``` -🧠 Reasoning Trace: -================================================================================ -💭 Thought: The user is asking about prerequisites. I'll use exact match. +### Sections -🔧 Action: search_courses - Input: {"query": "CS002", "intent": "PREREQUISITES", "search_strategy": "exact_match"} -👁️ Observation: Found CS002 - Data Structures and Algorithms... +| Module | Time | Notebook | Key Highlights | +|--------|------|----------|----------------| +| **1. Introduction** | 45 min | `01_introduction_to_context_engineering.ipynb` | Overview of context types, failures, and token budgeting strategies. | +| **2. RAG Essentials** | 60 min | `02_rag_essentials.ipynb` | Semantic search, embeddings, and RAG patterns. | +| **3. Data Engineering** | 75 min | `03_data_engineering_theory.ipynb` | Data pipelines, chunking methods, and preparing retrieval-ready data. | +| **4. Memory Systems** | 90 min | `04_memory_systems.ipynb` | Working vs. long-term memory and memory-augmented RAG for agents. | -💭 Thought: I found the course. Prerequisites: CS001 (Introduction to Programming). -✅ FINISH -================================================================================ +### Running notebooks -📝 Answer: -CS002 (Data Structures and Algorithms) requires CS001 (Introduction to Programming) as a prerequisite. -``` - ---- - -## Project Structure - -``` -context-eng-matters/ -├── src/redis_context_course/ # Core library -│ ├── course_manager.py # CourseManager - basic Redis vector search -│ ├── hierarchical_course_manager.py # HierarchicalCourseManager - two-tier retrieval -│ ├── hierarchical_context.py # HierarchicalContextAssembler - progressive disclosure -│ ├── models.py # Pydantic data models -│ └── scripts/ # Data generation utilities -│ -├── workshop/ # Comprehensive workshop (4 notebooks, ~4,560 lines) -│ ├── 01_introduction_to_context_engineering.ipynb # Context types, token budgeting -│ ├── 02_rag_essentials.ipynb # Vector embeddings, semantic search (~1,000 lines) -│ ├── 03_data_engineering.ipynb # Data pipelines, chunking strategies (~960 lines) -│ └── 04_memory_systems.ipynb # Working + long-term memory (~2,000 lines) -│ -├── progressive_agents/ # 6 agent implementations (learning path) -│ ├── stage1_baseline_rag/ -│ ├── stage2_context_engineered/ -│ ├── stage3_full_agent_without_memory/ -│ ├── stage4_hybrid_search/ # Hybrid search + ReAct -│ ├── stage5_working_memory/ # Session-based memory + ReAct -│ └── stage6_full_memory/ # Working + Long-term memory + ReAct -│ -├── notebooks/ # Full course (11 Jupyter notebooks) -│ ├── section-1-context-engineering-foundations/ -│ ├── section-2-retrieved-context-engineering/ -│ ├── section-3-memory-systems/ -│ └── section-4-tools-and-agents/ -│ -├── tests/ # Test suite -└── docker-compose.yml # Redis + Agent Memory Server -``` - ---- - -## Progressive Agents - -The `progressive_agents/` directory contains a learning path from basic RAG to production-ready agents: - -```mermaid -graph LR - S1[Stage 1
Baseline RAG] --> S2[Stage 2
Context Engineering] - S2 --> S3[Stage 3
Full Agent] - S3 --> S4[Stage 4
Hybrid Search] - S4 --> S5[Stage 5
Working Memory] - S5 --> S6[Stage 6
Full Memory] -``` - -| Stage | Key Feature | What's New | Reasoning | -|-------|-------------|------------|-----------| -| **1** | Baseline RAG | Information overload (~6,000 tokens) | Hidden | -| **2** | Context Engineering | Progressive disclosure (~539 tokens) | Hidden | -| **3** | Full Agent | LangGraph, intent classification, hierarchical retrieval | Hidden | -| **4** | Hybrid Search | Hybrid search + ReAct pattern | **Visible** | -| **5** | Working Memory | Session-based memory (1 tool) | **Visible** | -| **6** | Full Memory | Working + long-term memory (3 tools) | **Visible** | - -👉 **[See full documentation →](progressive_agents/README.md)** - ---- - -## Notebooks - -| Section | Topics | Duration | -|---------|--------|----------| -| **1. Context Engineering Foundations** | What is context engineering, assembly strategies | 2-3 hrs | -| **2. Retrieved Context Engineering** | RAG fundamentals, crafting & optimizing context | 2.5-3 hrs | -| **3. Memory Systems** | Working/long-term memory, compression strategies | 4-5 hrs | -| **4. Tools and Agents** | LangGraph, tool calling, semantic tool selection | 3.5-4.5 hrs | - -**Start learning:** ```bash -# With uv -uv run jupyter notebook notebooks/ - -# Or with pip (ensure virtual environment is activated) -jupyter notebook notebooks/ -``` - -**Windows:** -```powershell -# Activate virtual environment first -.venv\Scripts\Activate.ps1 # PowerShell +cd workshop -# Then start Jupyter -jupyter notebook notebooks/ +# Execute a specific notebook (optional) +jupyter execute 02_rag_essentials.ipynb --inplace ``` -Open: `section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb` +**Module 4 note:** the Redis `Agent Memory Server` must be running with `OPENAI_API_KEY` set (the provided `docker-compose.yml` loads it from your `.env`). --- -## Key Technologies +## Agent Demos -| Technology | Purpose | -|------------|---------| -| **Redis Stack** | Vector storage, semantic search, caching | -| **RedisVL** | Vector search library with FilterQuery | -| **LangGraph** | Stateful agent workflows | -| **LangChain** | LLM application framework | -| **Agent Memory Server** | Working and long-term memory management | -| **OpenAI GPT-4o** | Language model for reasoning | +Six CLI demos that progressively add capabilities. Use `--help` for all options, `--quiet` for minimal output, `--show-reasoning` for ReAct traces (stages 4–6). ---- - -## Documentation +```bash +# 1. Baseline RAG — naive retrieval, no optimization +uv run 1-baseline-rag "What machine learning courses are available?" -| Document | Description | -|----------|-------------| -| [SETUP.md](SETUP.md) | Detailed setup and troubleshooting | -| [workshop/README.md](workshop/README.md) | Intensive workshop guide | -| [progressive_agents/README.md](progressive_agents/README.md) | Agent stages documentation | -| [notebooks/README.md](notebooks/README.md) | Full course notebook guides | +# 2. Context-engineered — cleaned/transformed context, progressive disclosure +uv run 2-context-engineered "What machine learning courses are available?" ---- +# 3. LangGraph agent — structured workflow with intent routing +uv run 3-langgraph-agent "What courses teach machine learning?" -## Contributing +# 4. Hybrid + ReAct — adds NER-based hybrid search and visible reasoning +uv run 4-hybrid-react --show-reasoning "What are the prerequisites for CS002?" -Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. +# 5. Working memory — multi-turn conversations within a session +uv run 5-working-memory --student-id alice --session-id s1 "What is CS004?" ---- - -## License +# 6. Full memory — working + long-term memory with preference tracking +uv run 6-full-memory --student-id alice --show-reasoning "What courses do you recommend?" +``` -MIT License — See [LICENSE](LICENSE) for details. diff --git a/SETUP.md b/SETUP.md index 15e3c71..de6e59c 100644 --- a/SETUP.md +++ b/SETUP.md @@ -1,6 +1,6 @@ -# Setup Guide for Context Engineering Course +# Setup Guide for Context Engineering Workshop -This guide will help you set up everything you need to run the Context Engineering notebooks and progressive agents. +This guide will help you set up everything you need to run the workshop notebooks (`workshop/`) and the staged agent demos (`demos/`). ## Prerequisites @@ -70,8 +70,8 @@ pip install -e . ### Step 4: Load Course Data ```bash -# Load hierarchical courses into Redis (required for notebooks and progressive agents) -uv run python -m redis_context_course.scripts.load_hierarchical_courses \ +# Load hierarchical courses into Redis (required for workshop and demos) +uv run load-hierarchical-courses \ -i src/redis_context_course/data/hierarchical/hierarchical_courses.json \ --force @@ -84,13 +84,10 @@ uv run python -m redis_context_course.scripts.ingest_courses \ **Note:** Use `--force` to clear and reload data if you've regenerated the course catalog or if you're seeing duplicate courses. -### Step 5: Run the Notebooks +### Step 5: Run the Workshop Notebooks ```bash -# Start Jupyter -uv run jupyter notebook notebooks/ - -# Or for the workshop +# Start Jupyter for the workshop uv run jupyter notebook workshop/ ``` @@ -204,22 +201,15 @@ If you already have Redis running or want to use Redis Cloud: Once setup is complete: -**For the Workshop (condensed, ~6 hours):** +**For the Workshop (condensed):** 1. Start with **Module 1** (Introduction) to understand context types 2. Work through **Module 2** (RAG Essentials) for vector search fundamentals 3. Complete **Module 3** (Data Engineering) for data pipeline patterns 4. Master **Module 4** (Memory Systems) for working and long-term memory -5. Build agents in **Module 5** and compare in **Module 6** - -**For the Full Course (comprehensive, 15-20 hours):** -1. Start with **Section 1** notebooks to understand core concepts -2. Work through **Section 2** to learn RAG and context engineering -3. Complete **Section 3** to master memory management (requires Agent Memory Server) -4. Explore **Section 4** for tools and agent development +5. Explore the staged demos in `demos/` to see the same ideas evolve into increasingly capable agents ## Getting Help - Check the main [README.md](README.md) for course structure and learning path -- Review [workshop/README.md](workshop/README.md) for the condensed workshop -- Open an issue if you encounter problems with the setup +- Review the **Workshop Outline** and **Agent Demos (CLI)** sections in the main [README.md](README.md) diff --git a/progressive_agents/CONTENT_COVERAGE_GAP_ANALYSIS.md b/demos/CONTENT_COVERAGE_GAP_ANALYSIS.md similarity index 99% rename from progressive_agents/CONTENT_COVERAGE_GAP_ANALYSIS.md rename to demos/CONTENT_COVERAGE_GAP_ANALYSIS.md index 3b91d9e..3e40036 100644 --- a/progressive_agents/CONTENT_COVERAGE_GAP_ANALYSIS.md +++ b/demos/CONTENT_COVERAGE_GAP_ANALYSIS.md @@ -38,7 +38,7 @@ LONG_TERM_MEMORY=true # Enable long-term memory extraction **Evidence from codebase:** ```python -# From progressive_agents/stage6_full_memory/agent/nodes.py (lines 148-156) +# From demos/stage6_full_memory/agent/nodes.py (lines 148-156) async def save_working_memory_node(state: WorkflowState) -> WorkflowState: """ Save working memory to Agent Memory Server. @@ -280,7 +280,7 @@ The following notebook concepts are **intentionally not demonstrated** in progre ### Priority 4: Main README Update (Low Effort, Medium Value) -Add to main `progressive_agents/README.md`: +Add to main `README.md`: ```markdown ## Automatic Features (Handled by Infrastructure) diff --git a/demos/__init__.py b/demos/__init__.py new file mode 100644 index 0000000..0db1e3e --- /dev/null +++ b/demos/__init__.py @@ -0,0 +1 @@ +# Agent demo stages diff --git a/demos/stage1_baseline_rag/__init__.py b/demos/stage1_baseline_rag/__init__.py new file mode 100644 index 0000000..22c9514 --- /dev/null +++ b/demos/stage1_baseline_rag/__init__.py @@ -0,0 +1 @@ +# Stage 1: Baseline RAG Agent diff --git a/progressive_agents/stage1_baseline_rag/agent/__init__.py b/demos/stage1_baseline_rag/agent/__init__.py similarity index 100% rename from progressive_agents/stage1_baseline_rag/agent/__init__.py rename to demos/stage1_baseline_rag/agent/__init__.py diff --git a/progressive_agents/stage1_baseline_rag/agent/nodes.py b/demos/stage1_baseline_rag/agent/nodes.py similarity index 100% rename from progressive_agents/stage1_baseline_rag/agent/nodes.py rename to demos/stage1_baseline_rag/agent/nodes.py diff --git a/progressive_agents/stage1_baseline_rag/agent/setup.py b/demos/stage1_baseline_rag/agent/setup.py similarity index 100% rename from progressive_agents/stage1_baseline_rag/agent/setup.py rename to demos/stage1_baseline_rag/agent/setup.py diff --git a/progressive_agents/stage1_baseline_rag/agent/state.py b/demos/stage1_baseline_rag/agent/state.py similarity index 100% rename from progressive_agents/stage1_baseline_rag/agent/state.py rename to demos/stage1_baseline_rag/agent/state.py diff --git a/progressive_agents/stage1_baseline_rag/agent/workflow.py b/demos/stage1_baseline_rag/agent/workflow.py similarity index 100% rename from progressive_agents/stage1_baseline_rag/agent/workflow.py rename to demos/stage1_baseline_rag/agent/workflow.py diff --git a/progressive_agents/stage1_baseline_rag/cli.py b/demos/stage1_baseline_rag/cli.py similarity index 94% rename from progressive_agents/stage1_baseline_rag/cli.py rename to demos/stage1_baseline_rag/cli.py index bf34824..243bd71 100644 --- a/progressive_agents/stage1_baseline_rag/cli.py +++ b/demos/stage1_baseline_rag/cli.py @@ -37,17 +37,20 @@ logger = logging.getLogger("stage1-cli") -# Add parent directory to path for imports -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) - # Load environment variables from project root from dotenv import load_dotenv -env_path = Path(__file__).parent.parent / "src" / ".env" +env_path = Path(__file__).resolve().parents[2] / ".env" load_dotenv(env_path) -from agent import cleanup_courses, initialize_state, setup_agent -from agent.workflow import create_workflow +# Import agent module - try relative import first (when running as package), +# fall back to direct import (when running python cli.py from this directory) +try: + from .agent import cleanup_courses, initialize_state, setup_agent + from .agent.workflow import create_workflow +except ImportError: + from agent import cleanup_courses, initialize_state, setup_agent + from agent.workflow import create_workflow class BaselineRAGCLI: diff --git a/demos/stage2_context_engineered/__init__.py b/demos/stage2_context_engineered/__init__.py new file mode 100644 index 0000000..1800372 --- /dev/null +++ b/demos/stage2_context_engineered/__init__.py @@ -0,0 +1 @@ +# Stage 2: Context-Engineered Agent diff --git a/progressive_agents/stage2_context_engineered/agent/__init__.py b/demos/stage2_context_engineered/agent/__init__.py similarity index 100% rename from progressive_agents/stage2_context_engineered/agent/__init__.py rename to demos/stage2_context_engineered/agent/__init__.py diff --git a/progressive_agents/stage2_context_engineered/agent/context_engineering.py b/demos/stage2_context_engineered/agent/context_engineering.py similarity index 100% rename from progressive_agents/stage2_context_engineered/agent/context_engineering.py rename to demos/stage2_context_engineered/agent/context_engineering.py diff --git a/progressive_agents/stage2_context_engineered/agent/nodes.py b/demos/stage2_context_engineered/agent/nodes.py similarity index 100% rename from progressive_agents/stage2_context_engineered/agent/nodes.py rename to demos/stage2_context_engineered/agent/nodes.py diff --git a/progressive_agents/stage2_context_engineered/agent/setup.py b/demos/stage2_context_engineered/agent/setup.py similarity index 100% rename from progressive_agents/stage2_context_engineered/agent/setup.py rename to demos/stage2_context_engineered/agent/setup.py diff --git a/progressive_agents/stage2_context_engineered/agent/state.py b/demos/stage2_context_engineered/agent/state.py similarity index 100% rename from progressive_agents/stage2_context_engineered/agent/state.py rename to demos/stage2_context_engineered/agent/state.py diff --git a/progressive_agents/stage2_context_engineered/agent/workflow.py b/demos/stage2_context_engineered/agent/workflow.py similarity index 100% rename from progressive_agents/stage2_context_engineered/agent/workflow.py rename to demos/stage2_context_engineered/agent/workflow.py diff --git a/progressive_agents/stage2_context_engineered/cli.py b/demos/stage2_context_engineered/cli.py similarity index 94% rename from progressive_agents/stage2_context_engineered/cli.py rename to demos/stage2_context_engineered/cli.py index 4bd6e83..d6a73e4 100644 --- a/progressive_agents/stage2_context_engineered/cli.py +++ b/demos/stage2_context_engineered/cli.py @@ -37,17 +37,20 @@ logger = logging.getLogger("stage2-cli") -# Add parent directory to path for imports -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) - # Load environment variables from project root from dotenv import load_dotenv -env_path = Path(__file__).parent.parent / "src" / ".env" +env_path = Path(__file__).resolve().parents[2] / ".env" load_dotenv(env_path) -from agent import cleanup_courses, initialize_state, setup_agent -from agent.workflow import create_workflow +# Import agent module - try relative import first (when running as package), +# fall back to direct import (when running python cli.py from this directory) +try: + from .agent import cleanup_courses, initialize_state, setup_agent + from .agent.workflow import create_workflow +except ImportError: + from agent import cleanup_courses, initialize_state, setup_agent + from agent.workflow import create_workflow class ContextEngineeredCLI: diff --git a/demos/stage3_full_agent_without_memory/__init__.py b/demos/stage3_full_agent_without_memory/__init__.py new file mode 100644 index 0000000..aada7fe --- /dev/null +++ b/demos/stage3_full_agent_without_memory/__init__.py @@ -0,0 +1 @@ +# Stage 3: Full Agent Without Memory diff --git a/progressive_agents/stage3_full_agent_without_memory/agent/__init__.py b/demos/stage3_full_agent_without_memory/agent/__init__.py similarity index 100% rename from progressive_agents/stage3_full_agent_without_memory/agent/__init__.py rename to demos/stage3_full_agent_without_memory/agent/__init__.py diff --git a/progressive_agents/stage3_full_agent_without_memory/agent/edges.py b/demos/stage3_full_agent_without_memory/agent/edges.py similarity index 100% rename from progressive_agents/stage3_full_agent_without_memory/agent/edges.py rename to demos/stage3_full_agent_without_memory/agent/edges.py diff --git a/progressive_agents/stage3_full_agent_without_memory/agent/nodes.py b/demos/stage3_full_agent_without_memory/agent/nodes.py similarity index 100% rename from progressive_agents/stage3_full_agent_without_memory/agent/nodes.py rename to demos/stage3_full_agent_without_memory/agent/nodes.py diff --git a/progressive_agents/stage3_full_agent_without_memory/agent/setup.py b/demos/stage3_full_agent_without_memory/agent/setup.py similarity index 100% rename from progressive_agents/stage3_full_agent_without_memory/agent/setup.py rename to demos/stage3_full_agent_without_memory/agent/setup.py diff --git a/progressive_agents/stage3_full_agent_without_memory/agent/state.py b/demos/stage3_full_agent_without_memory/agent/state.py similarity index 100% rename from progressive_agents/stage3_full_agent_without_memory/agent/state.py rename to demos/stage3_full_agent_without_memory/agent/state.py diff --git a/progressive_agents/stage3_full_agent_without_memory/agent/tools.py b/demos/stage3_full_agent_without_memory/agent/tools.py similarity index 100% rename from progressive_agents/stage3_full_agent_without_memory/agent/tools.py rename to demos/stage3_full_agent_without_memory/agent/tools.py diff --git a/progressive_agents/stage3_full_agent_without_memory/agent/workflow.py b/demos/stage3_full_agent_without_memory/agent/workflow.py similarity index 100% rename from progressive_agents/stage3_full_agent_without_memory/agent/workflow.py rename to demos/stage3_full_agent_without_memory/agent/workflow.py diff --git a/progressive_agents/stage3_full_agent_without_memory/cli.py b/demos/stage3_full_agent_without_memory/cli.py similarity index 95% rename from progressive_agents/stage3_full_agent_without_memory/cli.py rename to demos/stage3_full_agent_without_memory/cli.py index 43443fa..fa4ff91 100644 --- a/progressive_agents/stage3_full_agent_without_memory/cli.py +++ b/demos/stage3_full_agent_without_memory/cli.py @@ -30,11 +30,14 @@ break current = current.parent -# Add agent module to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) - -from agent import create_workflow, run_agent, setup_agent -from agent.setup import cleanup_courses +# Import agent module - try relative import first (when running as package), +# fall back to direct import (when running python cli.py from this directory) +try: + from .agent import create_workflow, run_agent, setup_agent + from .agent.setup import cleanup_courses +except ImportError: + from agent import create_workflow, run_agent, setup_agent + from agent.setup import cleanup_courses class CourseQACLI: @@ -321,5 +324,10 @@ async def main(): await cli.interactive_mode() -if __name__ == "__main__": +def run(): + """Sync entry point for uv scripts.""" asyncio.run(main()) + + +if __name__ == "__main__": + run() diff --git a/progressive_agents/stage3_full_agent_without_memory/debug_search.py b/demos/stage3_full_agent_without_memory/debug_search.py similarity index 98% rename from progressive_agents/stage3_full_agent_without_memory/debug_search.py rename to demos/stage3_full_agent_without_memory/debug_search.py index 7d86a3b..5983499 100644 --- a/progressive_agents/stage3_full_agent_without_memory/debug_search.py +++ b/demos/stage3_full_agent_without_memory/debug_search.py @@ -14,7 +14,7 @@ load_dotenv(env_path) # Add agent module to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from agent.setup import setup_agent from agent.tools import search_courses diff --git a/progressive_agents/stage3_full_agent_without_memory/test_linear_algebra.py b/demos/stage3_full_agent_without_memory/test_linear_algebra.py similarity index 92% rename from progressive_agents/stage3_full_agent_without_memory/test_linear_algebra.py rename to demos/stage3_full_agent_without_memory/test_linear_algebra.py index f6b8f2b..ce86b4e 100644 --- a/progressive_agents/stage3_full_agent_without_memory/test_linear_algebra.py +++ b/demos/stage3_full_agent_without_memory/test_linear_algebra.py @@ -12,13 +12,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage3_full_agent_without_memory.agent.workflow import ( - create_workflow, -) +from agent.workflow import create_workflow # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage3_full_agent_without_memory/test_simple.py b/demos/stage3_full_agent_without_memory/test_simple.py similarity index 94% rename from progressive_agents/stage3_full_agent_without_memory/test_simple.py rename to demos/stage3_full_agent_without_memory/test_simple.py index 97b17fe..b3feb18 100644 --- a/progressive_agents/stage3_full_agent_without_memory/test_simple.py +++ b/demos/stage3_full_agent_without_memory/test_simple.py @@ -10,13 +10,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage3_full_agent_without_memory.agent.workflow import ( - create_workflow, -) +from agent.workflow import create_workflow # Configure logging logging.basicConfig( diff --git a/demos/stage4_hybrid_search/__init__.py b/demos/stage4_hybrid_search/__init__.py new file mode 100644 index 0000000..18e90d3 --- /dev/null +++ b/demos/stage4_hybrid_search/__init__.py @@ -0,0 +1 @@ +# Stage 4: Hybrid Search with ReAct diff --git a/progressive_agents/stage4_hybrid_search/agent/__init__.py b/demos/stage4_hybrid_search/agent/__init__.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/__init__.py rename to demos/stage4_hybrid_search/agent/__init__.py diff --git a/progressive_agents/stage4_hybrid_search/agent/react_agent.py b/demos/stage4_hybrid_search/agent/react_agent.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/react_agent.py rename to demos/stage4_hybrid_search/agent/react_agent.py diff --git a/progressive_agents/stage4_hybrid_search/agent/react_parser.py b/demos/stage4_hybrid_search/agent/react_parser.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/react_parser.py rename to demos/stage4_hybrid_search/agent/react_parser.py diff --git a/progressive_agents/stage4_hybrid_search/agent/react_prompts.py b/demos/stage4_hybrid_search/agent/react_prompts.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/react_prompts.py rename to demos/stage4_hybrid_search/agent/react_prompts.py diff --git a/progressive_agents/stage4_hybrid_search/agent/setup.py b/demos/stage4_hybrid_search/agent/setup.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/setup.py rename to demos/stage4_hybrid_search/agent/setup.py diff --git a/progressive_agents/stage4_hybrid_search/agent/state.py b/demos/stage4_hybrid_search/agent/state.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/state.py rename to demos/stage4_hybrid_search/agent/state.py diff --git a/progressive_agents/stage4_hybrid_search/agent/tools.py b/demos/stage4_hybrid_search/agent/tools.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/tools.py rename to demos/stage4_hybrid_search/agent/tools.py diff --git a/progressive_agents/stage4_hybrid_search/agent/workflow.py b/demos/stage4_hybrid_search/agent/workflow.py similarity index 100% rename from progressive_agents/stage4_hybrid_search/agent/workflow.py rename to demos/stage4_hybrid_search/agent/workflow.py diff --git a/progressive_agents/stage4_hybrid_search/cli.py b/demos/stage4_hybrid_search/cli.py similarity index 94% rename from progressive_agents/stage4_hybrid_search/cli.py rename to demos/stage4_hybrid_search/cli.py index 927a144..5dbb3e8 100644 --- a/progressive_agents/stage4_hybrid_search/cli.py +++ b/demos/stage4_hybrid_search/cli.py @@ -40,11 +40,14 @@ break current = current.parent -# Add agent module to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) - -from agent import create_workflow, run_agent_async, setup_agent -from agent.setup import cleanup_courses +# Import agent module - try relative import first (when running as package), +# fall back to direct import (when running python cli.py from this directory) +try: + from .agent import create_workflow, run_agent_async, setup_agent + from .agent.setup import cleanup_courses +except ImportError: + from agent import create_workflow, run_agent_async, setup_agent + from agent.setup import cleanup_courses # If quiet mode, ensure all loggers are suppressed after imports if _quiet_mode: @@ -243,6 +246,11 @@ async def main(): await cli.interactive_mode() -if __name__ == "__main__": +def run(): + """Sync entry point for uv scripts.""" asyncio.run(main()) + +if __name__ == "__main__": + run() + diff --git a/demos/stage5_working_memory/__init__.py b/demos/stage5_working_memory/__init__.py new file mode 100644 index 0000000..747522c --- /dev/null +++ b/demos/stage5_working_memory/__init__.py @@ -0,0 +1 @@ +# Stage 5: Working Memory diff --git a/progressive_agents/stage5_working_memory/agent/__init__.py b/demos/stage5_working_memory/agent/__init__.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/__init__.py rename to demos/stage5_working_memory/agent/__init__.py diff --git a/progressive_agents/stage5_working_memory/agent/edges.py b/demos/stage5_working_memory/agent/edges.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/edges.py rename to demos/stage5_working_memory/agent/edges.py diff --git a/progressive_agents/stage5_working_memory/agent/nodes.py b/demos/stage5_working_memory/agent/nodes.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/nodes.py rename to demos/stage5_working_memory/agent/nodes.py diff --git a/progressive_agents/stage5_working_memory/agent/react_agent.py b/demos/stage5_working_memory/agent/react_agent.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/react_agent.py rename to demos/stage5_working_memory/agent/react_agent.py diff --git a/progressive_agents/stage5_working_memory/agent/react_parser.py b/demos/stage5_working_memory/agent/react_parser.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/react_parser.py rename to demos/stage5_working_memory/agent/react_parser.py diff --git a/progressive_agents/stage5_working_memory/agent/react_prompts.py b/demos/stage5_working_memory/agent/react_prompts.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/react_prompts.py rename to demos/stage5_working_memory/agent/react_prompts.py diff --git a/progressive_agents/stage5_working_memory/agent/setup.py b/demos/stage5_working_memory/agent/setup.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/setup.py rename to demos/stage5_working_memory/agent/setup.py diff --git a/progressive_agents/stage5_working_memory/agent/state.py b/demos/stage5_working_memory/agent/state.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/state.py rename to demos/stage5_working_memory/agent/state.py diff --git a/progressive_agents/stage5_working_memory/agent/tools.py b/demos/stage5_working_memory/agent/tools.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/tools.py rename to demos/stage5_working_memory/agent/tools.py diff --git a/progressive_agents/stage5_working_memory/agent/workflow.py b/demos/stage5_working_memory/agent/workflow.py similarity index 100% rename from progressive_agents/stage5_working_memory/agent/workflow.py rename to demos/stage5_working_memory/agent/workflow.py diff --git a/progressive_agents/stage5_working_memory/cli.py b/demos/stage5_working_memory/cli.py similarity index 96% rename from progressive_agents/stage5_working_memory/cli.py rename to demos/stage5_working_memory/cli.py index 517e5a3..256df2e 100644 --- a/progressive_agents/stage5_working_memory/cli.py +++ b/demos/stage5_working_memory/cli.py @@ -43,11 +43,14 @@ break current = current.parent -# Add agent module to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) - -from agent import create_workflow, run_agent_async, setup_agent -from agent.setup import cleanup_courses +# Import agent module - try relative import first (when running as package), +# fall back to direct import (when running python cli.py from this directory) +try: + from .agent import create_workflow, run_agent_async, setup_agent + from .agent.setup import cleanup_courses +except ImportError: + from agent import create_workflow, run_agent_async, setup_agent + from agent.setup import cleanup_courses # If quiet mode, ensure all loggers are suppressed after imports if _quiet_mode: @@ -435,5 +438,10 @@ async def main(): await cli.interactive_mode() -if __name__ == "__main__": +def run(): + """Sync entry point for uv scripts.""" asyncio.run(main()) + + +if __name__ == "__main__": + run() diff --git a/progressive_agents/stage5_working_memory/debug_search.py b/demos/stage5_working_memory/debug_search.py similarity index 98% rename from progressive_agents/stage5_working_memory/debug_search.py rename to demos/stage5_working_memory/debug_search.py index 7d86a3b..5983499 100644 --- a/progressive_agents/stage5_working_memory/debug_search.py +++ b/demos/stage5_working_memory/debug_search.py @@ -14,7 +14,7 @@ load_dotenv(env_path) # Add agent module to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from agent.setup import setup_agent from agent.tools import search_courses diff --git a/progressive_agents/stage6_full_memory/test_agent_intents.py b/demos/stage5_working_memory/test_agent_intents.py similarity index 97% rename from progressive_agents/stage6_full_memory/test_agent_intents.py rename to demos/stage5_working_memory/test_agent_intents.py index 4647973..36c9cc1 100644 --- a/progressive_agents/stage6_full_memory/test_agent_intents.py +++ b/demos/stage5_working_memory/test_agent_intents.py @@ -14,14 +14,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage5_working_memory/test_exact_match.py b/demos/stage5_working_memory/test_exact_match.py similarity index 100% rename from progressive_agents/stage5_working_memory/test_exact_match.py rename to demos/stage5_working_memory/test_exact_match.py diff --git a/progressive_agents/stage5_working_memory/test_exact_match_react.py b/demos/stage5_working_memory/test_exact_match_react.py similarity index 94% rename from progressive_agents/stage5_working_memory/test_exact_match_react.py rename to demos/stage5_working_memory/test_exact_match_react.py index cc4e73f..831d565 100644 --- a/progressive_agents/stage5_working_memory/test_exact_match_react.py +++ b/demos/stage5_working_memory/test_exact_match_react.py @@ -8,8 +8,8 @@ from langchain_openai import ChatOpenAI from redis_context_course import CourseManager -from progressive_agents.stage5_working_memory.agent.react_agent import run_react_agent -from progressive_agents.stage5_working_memory.agent.tools import initialize_tools +from agent.react_agent import run_react_agent +from agent.tools import initialize_tools logging.basicConfig( level=logging.INFO, diff --git a/progressive_agents/stage6_full_memory/test_linear_algebra.py b/demos/stage5_working_memory/test_linear_algebra.py similarity index 90% rename from progressive_agents/stage6_full_memory/test_linear_algebra.py rename to demos/stage5_working_memory/test_linear_algebra.py index a1d4c7f..33ab143 100644 --- a/progressive_agents/stage6_full_memory/test_linear_algebra.py +++ b/demos/stage5_working_memory/test_linear_algebra.py @@ -10,14 +10,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging to show tool calls logging.basicConfig( diff --git a/progressive_agents/stage5_working_memory/test_react_multi_turn.py b/demos/stage5_working_memory/test_react_multi_turn.py similarity index 95% rename from progressive_agents/stage5_working_memory/test_react_multi_turn.py rename to demos/stage5_working_memory/test_react_multi_turn.py index edffdd6..cec0911 100644 --- a/progressive_agents/stage5_working_memory/test_react_multi_turn.py +++ b/demos/stage5_working_memory/test_react_multi_turn.py @@ -13,8 +13,8 @@ from langchain_openai import ChatOpenAI from redis_context_course import CourseManager -from progressive_agents.stage5_working_memory.agent.react_agent import run_react_agent -from progressive_agents.stage5_working_memory.agent.tools import initialize_tools +from agent.react_agent import run_react_agent +from agent.tools import initialize_tools # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage5_working_memory/test_react_simple.py b/demos/stage5_working_memory/test_react_simple.py similarity index 96% rename from progressive_agents/stage5_working_memory/test_react_simple.py rename to demos/stage5_working_memory/test_react_simple.py index 95fa2a6..07cc81c 100644 --- a/progressive_agents/stage5_working_memory/test_react_simple.py +++ b/demos/stage5_working_memory/test_react_simple.py @@ -12,8 +12,8 @@ from langchain_openai import ChatOpenAI from redis_context_course import CourseManager -from progressive_agents.stage5_working_memory.agent.react_agent import run_react_agent -from progressive_agents.stage5_working_memory.agent.tools import initialize_tools +from agent.react_agent import run_react_agent +from agent.tools import initialize_tools # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_simple.py b/demos/stage5_working_memory/test_simple.py similarity index 90% rename from progressive_agents/stage6_full_memory/test_simple.py rename to demos/stage5_working_memory/test_simple.py index 7a46b9d..045968e 100644 --- a/progressive_agents/stage6_full_memory/test_simple.py +++ b/demos/stage5_working_memory/test_simple.py @@ -8,14 +8,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/demos/stage6_full_memory/__init__.py b/demos/stage6_full_memory/__init__.py new file mode 100644 index 0000000..c883df1 --- /dev/null +++ b/demos/stage6_full_memory/__init__.py @@ -0,0 +1 @@ +# Stage 6: Full Memory (Working + Long-term) diff --git a/progressive_agents/stage6_full_memory/agent/__init__.py b/demos/stage6_full_memory/agent/__init__.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/__init__.py rename to demos/stage6_full_memory/agent/__init__.py diff --git a/progressive_agents/stage6_full_memory/agent/edges.py b/demos/stage6_full_memory/agent/edges.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/edges.py rename to demos/stage6_full_memory/agent/edges.py diff --git a/progressive_agents/stage6_full_memory/agent/nodes.py b/demos/stage6_full_memory/agent/nodes.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/nodes.py rename to demos/stage6_full_memory/agent/nodes.py diff --git a/progressive_agents/stage6_full_memory/agent/react_agent.py b/demos/stage6_full_memory/agent/react_agent.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/react_agent.py rename to demos/stage6_full_memory/agent/react_agent.py diff --git a/progressive_agents/stage6_full_memory/agent/react_parser.py b/demos/stage6_full_memory/agent/react_parser.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/react_parser.py rename to demos/stage6_full_memory/agent/react_parser.py diff --git a/progressive_agents/stage6_full_memory/agent/react_prompts.py b/demos/stage6_full_memory/agent/react_prompts.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/react_prompts.py rename to demos/stage6_full_memory/agent/react_prompts.py diff --git a/progressive_agents/stage6_full_memory/agent/setup.py b/demos/stage6_full_memory/agent/setup.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/setup.py rename to demos/stage6_full_memory/agent/setup.py diff --git a/progressive_agents/stage6_full_memory/agent/state.py b/demos/stage6_full_memory/agent/state.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/state.py rename to demos/stage6_full_memory/agent/state.py diff --git a/progressive_agents/stage6_full_memory/agent/tools.py b/demos/stage6_full_memory/agent/tools.py similarity index 99% rename from progressive_agents/stage6_full_memory/agent/tools.py rename to demos/stage6_full_memory/agent/tools.py index e9bc3d2..63fd10a 100644 --- a/progressive_agents/stage6_full_memory/agent/tools.py +++ b/demos/stage6_full_memory/agent/tools.py @@ -49,7 +49,7 @@ def initialize_tools(manager: CourseManager): # Load hierarchical courses with full syllabi try: - # OLD PATH (incorrect - looked in progressive_agents/stage7_react_loop/src/...): + # OLD PATH (incorrect - looked in demos/stage7_react_loop/src/...): # data_path = ( # Path(__file__).parent.parent / "src" # / "redis_context_course" diff --git a/progressive_agents/stage6_full_memory/agent/workflow.py b/demos/stage6_full_memory/agent/workflow.py similarity index 100% rename from progressive_agents/stage6_full_memory/agent/workflow.py rename to demos/stage6_full_memory/agent/workflow.py diff --git a/progressive_agents/stage6_full_memory/cli.py b/demos/stage6_full_memory/cli.py similarity index 96% rename from progressive_agents/stage6_full_memory/cli.py rename to demos/stage6_full_memory/cli.py index 826dbfe..8e595cf 100644 --- a/progressive_agents/stage6_full_memory/cli.py +++ b/demos/stage6_full_memory/cli.py @@ -44,11 +44,14 @@ break current = current.parent -# Add agent module to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) - -from agent import create_workflow, run_agent_async, setup_agent -from agent.setup import cleanup_courses +# Import agent module - try relative import first (when running as package), +# fall back to direct import (when running python cli.py from this directory) +try: + from .agent import create_workflow, run_agent_async, setup_agent + from .agent.setup import cleanup_courses +except ImportError: + from agent import create_workflow, run_agent_async, setup_agent + from agent.setup import cleanup_courses # If quiet mode, ensure all loggers are suppressed after imports if _quiet_mode: @@ -427,5 +430,10 @@ async def main(): await cli.interactive_mode() -if __name__ == "__main__": +def run(): + """Sync entry point for uv scripts.""" asyncio.run(main()) + + +if __name__ == "__main__": + run() diff --git a/progressive_agents/stage6_full_memory/debug_search.py b/demos/stage6_full_memory/debug_search.py similarity index 98% rename from progressive_agents/stage6_full_memory/debug_search.py rename to demos/stage6_full_memory/debug_search.py index 7d86a3b..5983499 100644 --- a/progressive_agents/stage6_full_memory/debug_search.py +++ b/demos/stage6_full_memory/debug_search.py @@ -14,7 +14,7 @@ load_dotenv(env_path) # Add agent module to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from agent.setup import setup_agent from agent.tools import search_courses diff --git a/progressive_agents/stage5_working_memory/test_agent_intents.py b/demos/stage6_full_memory/test_agent_intents.py similarity index 97% rename from progressive_agents/stage5_working_memory/test_agent_intents.py rename to demos/stage6_full_memory/test_agent_intents.py index db8e9e3..36c9cc1 100644 --- a/progressive_agents/stage5_working_memory/test_agent_intents.py +++ b/demos/stage6_full_memory/test_agent_intents.py @@ -14,14 +14,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage5_working_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_exact_match.py b/demos/stage6_full_memory/test_exact_match.py similarity index 86% rename from progressive_agents/stage6_full_memory/test_exact_match.py rename to demos/stage6_full_memory/test_exact_match.py index e28872e..2bd910c 100644 --- a/progressive_agents/stage6_full_memory/test_exact_match.py +++ b/demos/stage6_full_memory/test_exact_match.py @@ -1,5 +1,5 @@ """ -Test exact match with Stage 7 ReAct agent for CS002. +Test exact match with Stage 6 Full Memory agent (ReAct). """ import asyncio @@ -8,8 +8,8 @@ from langchain_openai import ChatOpenAI from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.react_agent import run_react_agent -from progressive_agents.stage6_full_memory.agent.tools import initialize_tools +from agent.react_agent import run_react_agent +from agent.tools import initialize_tools logging.basicConfig( level=logging.INFO, @@ -21,7 +21,7 @@ async def test_cs002(): """Test exact match for CS002.""" print("\n" + "=" * 80) - print("STAGE 7 TEST: Exact Match for CS002") + print("STAGE 6 TEST: Exact Match for CS002") print("=" * 80) # Initialize @@ -58,7 +58,7 @@ async def test_cs002(): async def test_cs001(): """Test exact match for CS001.""" print("\n" + "=" * 80) - print("STAGE 7 TEST: Exact Match for CS001") + print("STAGE 6 TEST: Exact Match for CS001") print("=" * 80) # Initialize @@ -97,7 +97,7 @@ async def main(): await test_cs001() print("\n" + "=" * 80) - print("STAGE 7 EXACT MATCH TESTS COMPLETE") + print("STAGE 6 EXACT MATCH TESTS COMPLETE") print("=" * 80) diff --git a/progressive_agents/stage5_working_memory/test_linear_algebra.py b/demos/stage6_full_memory/test_linear_algebra.py similarity index 90% rename from progressive_agents/stage5_working_memory/test_linear_algebra.py rename to demos/stage6_full_memory/test_linear_algebra.py index d1cd193..33ab143 100644 --- a/progressive_agents/stage5_working_memory/test_linear_algebra.py +++ b/demos/stage6_full_memory/test_linear_algebra.py @@ -10,14 +10,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage5_working_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging to show tool calls logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_memory_tools.py b/demos/stage6_full_memory/test_memory_tools.py similarity index 97% rename from progressive_agents/stage6_full_memory/test_memory_tools.py rename to demos/stage6_full_memory/test_memory_tools.py index 80fb587..b0c34e5 100644 --- a/progressive_agents/stage6_full_memory/test_memory_tools.py +++ b/demos/stage6_full_memory/test_memory_tools.py @@ -15,14 +15,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_react_intents.py b/demos/stage6_full_memory/test_react_intents.py similarity index 97% rename from progressive_agents/stage6_full_memory/test_react_intents.py rename to demos/stage6_full_memory/test_react_intents.py index 1c8e6d9..02be8f6 100644 --- a/progressive_agents/stage6_full_memory/test_react_intents.py +++ b/demos/stage6_full_memory/test_react_intents.py @@ -16,14 +16,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_react_linear_algebra.py b/demos/stage6_full_memory/test_react_linear_algebra.py similarity index 94% rename from progressive_agents/stage6_full_memory/test_react_linear_algebra.py rename to demos/stage6_full_memory/test_react_linear_algebra.py index 471d841..11b2b19 100644 --- a/progressive_agents/stage6_full_memory/test_react_linear_algebra.py +++ b/demos/stage6_full_memory/test_react_linear_algebra.py @@ -11,14 +11,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging to show tool calls logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_react_multi_turn.py b/demos/stage6_full_memory/test_react_multi_turn.py similarity index 98% rename from progressive_agents/stage6_full_memory/test_react_multi_turn.py rename to demos/stage6_full_memory/test_react_multi_turn.py index e70c498..d0212d0 100644 --- a/progressive_agents/stage6_full_memory/test_react_multi_turn.py +++ b/demos/stage6_full_memory/test_react_multi_turn.py @@ -14,14 +14,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_react_simple.py b/demos/stage6_full_memory/test_react_simple.py similarity index 95% rename from progressive_agents/stage6_full_memory/test_react_simple.py rename to demos/stage6_full_memory/test_react_simple.py index 57ff553..990ec1d 100644 --- a/progressive_agents/stage6_full_memory/test_react_simple.py +++ b/demos/stage6_full_memory/test_react_simple.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Simple test for Stage 7 ReAct Loop Agent. +Simple test for Stage 6 Full Memory agent (ReAct). Tests basic ReAct functionality with explicit reasoning traces. """ @@ -11,14 +11,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage5_working_memory/test_simple.py b/demos/stage6_full_memory/test_simple.py similarity index 90% rename from progressive_agents/stage5_working_memory/test_simple.py rename to demos/stage6_full_memory/test_simple.py index eef0866..045968e 100644 --- a/progressive_agents/stage5_working_memory/test_simple.py +++ b/demos/stage6_full_memory/test_simple.py @@ -8,14 +8,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage5_working_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/progressive_agents/stage6_full_memory/test_simple_memory.py b/demos/stage6_full_memory/test_simple_memory.py similarity index 92% rename from progressive_agents/stage6_full_memory/test_simple_memory.py rename to demos/stage6_full_memory/test_simple_memory.py index 26b087c..c266d1c 100644 --- a/progressive_agents/stage6_full_memory/test_simple_memory.py +++ b/demos/stage6_full_memory/test_simple_memory.py @@ -9,14 +9,11 @@ from pathlib import Path # Add parent directory to path -sys.path.insert(0, str(Path(__file__).parent.parent / "src")) +sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) from redis_context_course import CourseManager -from progressive_agents.stage6_full_memory.agent.workflow import ( - create_workflow, - run_agent_async, -) +from agent.workflow import create_workflow, run_agent_async # Configure logging logging.basicConfig( diff --git a/notebooks/README.md b/notebooks/README.md deleted file mode 100644 index 03ed610..0000000 --- a/notebooks/README.md +++ /dev/null @@ -1,611 +0,0 @@ -# Context Engineering Course - Notebooks - -**Hands-on Jupyter notebooks for learning production-ready context engineering.** - -> 📚 **Main Course Documentation**: See **[../README.md](../README.md)** for complete course overview, setup instructions, and syllabus. -> -> 🎯 **Workshop**: For a condensed version, see **[../workshop/README.md](../workshop/README.md)**. - ---- - -## 📖 About These Notebooks - -This directory contains the hands-on Jupyter notebooks for the Context Engineering course. The notebooks are organized into 4 sections that progressively build your skills from fundamentals to production deployment. - -### Quick Links -- **[Course Overview & Setup](../README.md)** - Start here for setup and course introduction -- **[Workshop](../workshop/README.md)** - Condensed workshop version -- **[Setup Guide](SETUP_GUIDE.md)** - Detailed setup instructions and troubleshooting - ---- - -## 🚀 Quick Start - -**Already set up?** Jump right in: - -```bash -# From the repository root -uv run jupyter notebook notebooks/ - -# Open: section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb -``` - -**Need to set up?** Follow the [Quick Start](../README.md#-quick-start-5-minutes) in the main README. - -**Having issues?** Check the [Setup Guide](SETUP_GUIDE.md) for detailed instructions and troubleshooting. - ---- - -## 📚 Notebook Sections Overview - -### Learning Journey - -``` -Section 1: Foundations → Section 2: RAG → Section 3: Memory → Section 4: Tools & Agents - ↓ ↓ ↓ ↓ -Basic Concepts → RAG Patterns → Memory Systems → Production Agents -``` - -**🏆 End Result**: A complete, production-ready AI agent with sophisticated memory, intelligent tool routing, and optimized performance. - -## ✨ What Makes This Approach Unique - -### 1. 📈 Progressive Complexity -- **Same agent evolves** through all sections - see your work compound -- **Each section builds directly** on the previous one -- **Clear progression** from educational concepts to production deployment -- **Investment in learning** pays off across all sections - -### 2. 🏗️ Professional Foundation -- **Reference-agent integration** - Built on production-ready architecture -- **Type-safe Pydantic models** throughout all sections -- **Industry best practices** from day one -- **Real-world patterns** that work in production systems - -### 3. 🛠️ Hands-On Learning -- **Working code** in every notebook cell -- **Jupyter-friendly** interactive development -- **Immediate results** and feedback -- **Experimentation encouraged** - modify and test variations - -### 4. 🌍 Real-World Relevance -- **Production patterns** used in enterprise AI systems -- **Scalable architecture** ready for deployment -- **Portfolio-worthy** final project -- **Career-relevant** skills and experience - -## 📚 Complete Course Syllabus - -### 🎯 **Section 1: Foundations** -**Goal**: Master context engineering basics and the four context types -**Duration**: ~2-3 hours -**Prerequisites**: Basic Python knowledge, familiarity with LLMs - -**What You'll Build**: -- Understanding of the four types of context (system, user, retrieved, conversation) -- Foundation patterns for context assembly and management -- Conceptual framework for building context-aware AI systems - -**Key Learning**: -- Context engineering fundamentals and why it matters -- The four context types and when to use each -- Foundation for building sophisticated AI systems - -**Notebooks**: -1. `01_what_is_context_engineering.ipynb` - Core concepts and why context engineering matters -2. `02_context_assembly_strategies.ipynb` - Hands-on exploration of each context type - -**Reference Agent Components Used**: None (conceptual foundation) - -### 🤖 **Section 2: Retrieved Context Engineering** -**Goal**: Build a complete RAG system with vector search and retrieval -**Duration**: ~3-4 hours -**Prerequisites**: Section 1 completed, Redis running, OpenAI API key - -**What You'll Build**: -- Complete RAG pipeline (Retrieval + Augmentation + Generation) -- Vector-based course search using Redis and RedisVL -- Context assembly from multiple information sources -- Course recommendation system with semantic search - -**Key Learning**: -- RAG architecture and implementation patterns -- Vector similarity search for intelligent retrieval -- Redis as a vector database for AI applications -- Course data generation and ingestion workflows - -**Notebooks**: -1. `01_rag_retrieved_context_in_practice.ipynb` - Complete RAG system with Redis University Course Advisor - -**Reference Agent Components Used**: -- `CourseGenerator` - Generate sample course data -- `CourseIngestionPipeline` - Ingest courses into Redis -- `CourseManager` - Course search and recommendations -- `redis_config` - Redis configuration and connection - -### 🧠 **Section 3: Memory Systems for Context Engineering** -**Goal**: Master memory management with Agent Memory Server -**Duration**: ~4-5 hours -**Prerequisites**: Section 2 completed, Agent Memory Server running - -**What You'll Build**: -- Dual memory system (working memory + long-term memory) -- Memory extraction strategies (discrete, summary, preferences) -- Memory-enhanced RAG with semantic retrieval -- Working memory compression for long conversations - -**Key Learning**: -- Working vs long-term memory patterns and use cases -- Memory extraction strategies and when to use each -- Agent Memory Server integration and configuration -- Memory compression strategies (truncation, priority-based, summarization) -- Session management and cross-session persistence - -**Notebooks**: -1. `01_working_and_longterm_memory.ipynb` - Memory basics and Agent Memory Server integration -2. `02_combining_memory_with_retrieved_context.ipynb` - Memory extraction strategies in practice -3. `03_manage_long_conversations_with_compression_strategies.ipynb` - Compression strategies for long conversations - -**Reference Agent Components Used**: -- `redis_config` - Redis configuration -- `CourseManager` - Course management -- `Course`, `StudentProfile` - Data models -- `DifficultyLevel`, `CourseFormat`, `Semester` - Enums - ---- - -### 🔧 **Section 4: Integrating Tools and Agents** -**Goal**: Build production agents with LangGraph and intelligent tool selection -**Duration**: ~5-6 hours -**Prerequisites**: Section 3 completed, understanding of LangGraph basics - -**What You'll Build**: -- LangGraph-based stateful agent workflows -- Course advisor agent with multiple tools -- Memory-integrated agent with Agent Memory Server -- Working memory compression for long conversations - -**Key Learning**: -- LangGraph StateGraph and agent workflows -- Tool creation and integration patterns -- Agent Memory Server integration with LangGraph -- Working memory compression strategies in production agents -- State management and conversation flow control - -**Notebooks**: -1. `01_tools_and_langgraph_fundamentals.ipynb` - LangGraph basics and tool integration -2. `02_building_course_advisor_agent.ipynb` - Complete course advisor agent -3. `03_agent_with_memory_compression.ipynb` - Agent with memory compression - -**Reference Agent Components Used**: -- `CourseManager` - Course search and recommendations -- `StudentProfile`, `DifficultyLevel`, `CourseFormat` - Data models - -**Note**: This section demonstrates building custom agents rather than using the reference `ClassAgent` directly, showing students how to build production agents from scratch. - ---- - -### ⚡ **Section 5: Optimization & Production** -**Goal**: Optimize agents for production deployment -**Duration**: ~4-5 hours -**Prerequisites**: Section 4 completed - -**What You'll Build**: -- Performance measurement and optimization techniques -- Semantic tool selection at scale -- Production readiness checklist and quality assurance -- Cost optimization and monitoring - -**Key Learning**: -- Performance profiling and optimization -- Semantic tool selection with embeddings -- Production deployment best practices -- Quality assurance and testing strategies -- Cost management and token optimization - ---- - -## 📦 Core Package - -The course uses the `redis_context_course` package, which provides production-ready components for building context-aware AI agents. - -### What's in the Package? - -**Core Components** (used in notebooks): -- `CourseManager` - Basic course search with Redis vector store -- `HierarchicalCourseManager` - Two-tier retrieval (summaries + details) -- `HierarchicalContextAssembler` - Progressive disclosure for context assembly -- Data models: `Course`, `StudentProfile`, `DifficultyLevel`, `CourseFormat`, `Semester` -- Scripts: `CourseGenerator`, `CourseIngestionPipeline` - -**Note:** The workshop modules use `HierarchicalCourseManager` throughout for consistency, while the source notebooks use `CourseManager`. - -### How the Course Uses the Package - -**Educational Approach**: The notebooks demonstrate **building agents from scratch** using package components as building blocks. - -**Why?** This approach helps you: -- ✅ Understand how agents work internally -- ✅ Learn to build custom agents for your use cases -- ✅ See production patterns in action -- ✅ Gain hands-on experience with LangGraph and memory systems - -**Component Usage by Section**: -- **Section 1**: None (conceptual foundation) -- **Section 2**: CourseManager, HierarchicalContextAssembler, data generation scripts -- **Section 3**: CourseManager, data models -- **Section 4**: CourseManager, data models, LangGraph integration - -**Workshop Modules** (use HierarchicalCourseManager): -- **Module 2-4**: HierarchicalCourseManager, HierarchicalContextAssembler for progressive disclosure - ---- - -## 🏗️ Technical Architecture Evolution - -### **Agent Architecture Progression** - -#### **Section 2: Basic RAG** -```python -class SimpleRAGAgent: - - CourseManager integration - - Vector similarity search - - Context assembly - - Basic conversation history -``` - -#### **Section 3: Memory-Enhanced** -```python -class MemoryEnhancedAgent: - - Redis-based persistence - - Working vs long-term memory - - Memory consolidation - - Cross-session continuity -``` - -#### **Section 4: Multi-Tool** -```python -class MultiToolAgent: - - Specialized tool suite - - Semantic tool selection - - Intent classification - - Memory-aware routing -``` - -#### **Section 5: Production-Optimized** -```python -class OptimizedProductionAgent: - - Context optimization - - Performance monitoring - - Caching system - - Cost tracking - - Scalability support -``` - -## 🎓 Learning Outcomes by Section - -### **After Section 1: Foundations** -Students can: -- ✅ Explain the four context types and when to use each -- ✅ Understand context engineering principles and best practices -- ✅ Design context strategies for AI applications -- ✅ Identify context engineering patterns in production systems - -### **After Section 2: Retrieved Context Engineering** -Students can: -- ✅ Build complete RAG systems with Redis and RedisVL -- ✅ Implement vector similarity search for intelligent retrieval -- ✅ Generate and ingest course data into Redis -- ✅ Create course recommendation systems with semantic search - -### **After Section 3: Memory Systems for Context Engineering** -Students can: -- ✅ Integrate Agent Memory Server with AI agents -- ✅ Implement dual memory systems (working + long-term) -- ✅ Apply memory extraction strategies (discrete, summary, preferences) -- ✅ Implement memory compression for long conversations -- ✅ Design cross-session conversation continuity - -### **After Section 4: Integrating Tools and Agents** -Students can: -- ✅ Build stateful agents with LangGraph StateGraph -- ✅ Create and integrate multiple tools in agents -- ✅ Implement memory-integrated agents with Agent Memory Server -- ✅ Apply working memory compression in production agents -- ✅ Design conversation flow control and state management - -### **After Section 5: Optimization & Production** -Students can: -- ✅ Measure and optimize agent performance -- ✅ Implement semantic tool selection at scale -- ✅ Apply production deployment best practices -- ✅ Build quality assurance and testing strategies -- ✅ Optimize costs and token usage - -### **Complete Program Outcomes** -Students will have: -- 🏆 **Production-ready AI agent** with memory, tools, and optimization -- 📈 **Hands-on experience** with Redis, LangGraph, and Agent Memory Server -- 🔧 **Real-world skills** applicable to enterprise AI systems -- 💼 **Portfolio project** demonstrating context engineering mastery - ---- - -## 📋 System Requirements - -### Required -- **Python 3.11+** (recommended) -- **Docker Desktop** (for Redis and Agent Memory Server) -- **OpenAI API Key** ([get one here](https://platform.openai.com/api-keys)) -- **8GB RAM minimum** (16GB recommended) -- **5GB disk space** for dependencies and data - -### Optional -- **Jupyter Lab** (alternative to Jupyter Notebook) -- **VS Code** with Jupyter extension -- **Redis Insight** for visualizing Redis data - ---- - -## 🛠️ Detailed Setup Instructions - -For complete setup instructions including troubleshooting, see [SETUP_GUIDE.md](SETUP_GUIDE.md). - -### Quick Setup Summary - -1. **Set environment variables** (`.env` file with OpenAI API key) -2. **Start services** (`docker-compose up -d`) -3. **Install dependencies** (`uv sync`) -4. **Load course data** (`uv run python -m redis_context_course.scripts.ingest_courses ...`) -5. **Start Jupyter** (`uv run jupyter notebook notebooks/`) - -### Verification - -After setup, verify everything works: - -```bash -# Check Redis -docker exec redis redis-cli ping # Should return: PONG - -# Check Agent Memory Server -curl http://localhost:8088/v1/health # Should return: {"now":} - -# Check Python packages -uv run python -c "import redis_context_course; print('✅ Package installed')" -``` - ---- - -## 📖 Recommended Learning Path - -### For Beginners -1. **Start with Section 1** - Build conceptual foundation -2. **Complete Section 2** - Get hands-on with RAG -3. **Work through Section 3** - Master memory systems -4. **Build in Section 4** - Create production agents - -### For Experienced Developers -- **Skip to Section 2** if familiar with context engineering basics -- **Jump to Section 3** if you've built RAG systems before -- **Start at Section 4** if you want to focus on LangGraph and agents - -### Time Commitment -- **Intensive**: 1 week (full-time, 8 hours/day) -- **Standard**: 3-4 weeks (part-time, 6-8 hours/week) -- **Relaxed**: 6-8 weeks (casual, 3-4 hours/week) - -### Learning Tips -1. **Start with Section 1** - Build foundational understanding -2. **Progress sequentially** - Each section builds on the previous -3. **Complete all exercises** - Hands-on practice is essential -4. **Experiment freely** - Modify code and test variations -5. **Build your own variations** - Apply patterns to your domain - ---- - -## 🔧 Troubleshooting - -### **Common Issues and Solutions** - -#### **OpenAI API Key Issues** -``` -Error: "OPENAI_API_KEY not found. Please create a .env file..." -``` -**Solutions:** -1. Create `.env` file with `OPENAI_API_KEY=your_key_here` -2. Set environment variable: `export OPENAI_API_KEY=your_key_here` -3. Get your API key from: https://platform.openai.com/api-keys - -#### **Redis Connection Issues** -``` -Error: "Connection refused" or "Redis not available" -``` -**Solutions:** -1. Start Redis: `docker run -d -p 6379:6379 redis/redis-stack` -2. Check Redis URL in `.env`: `REDIS_URL=redis://localhost:6379` -3. Some features may work without Redis (varies by notebook) - -#### **Import Errors** -``` -Error: "No module named 'redis_context_course'" -``` -**Solutions:** -1. Install reference agent: `pip install -e ../../../reference-agent` -2. Check Python path in notebook cells -3. Restart Jupyter kernel - -#### **Notebook JSON Errors** -``` -Error: "NotJSONError" or "Notebook does not appear to be JSON" -``` -**Solutions:** -1. All notebooks are now JSON-valid (fixed in this update) -2. Try refreshing the browser -3. Restart Jupyter server - -### **Getting Help** -- **Check notebook output** - Error messages include troubleshooting tips -- **Environment validation** - Notebooks validate setup and provide clear guidance -- **Standard tools** - Uses industry-standard `python-dotenv` for configuration - -## 🌍 Real-World Applications - -The patterns and techniques learned apply directly to: - -### **Enterprise AI Systems** -- **Customer service chatbots** with sophisticated memory and tool routing -- **Technical support agents** with intelligent knowledge retrieval -- **Sales assistants** with personalized recommendations and context -- **Knowledge management systems** with optimized context assembly - -### **Educational Technology** -- **Personalized learning assistants** that remember student progress -- **Academic advising systems** with comprehensive course knowledge -- **Intelligent tutoring systems** with adaptive responses -- **Student support chatbots** with institutional knowledge - -### **Production AI Services** -- **Multi-tenant SaaS AI platforms** with user isolation and scaling -- **API-based AI services** with cost optimization and monitoring -- **Scalable conversation systems** with memory persistence -- **Enterprise AI deployments** with comprehensive analytics - -## 📊 Expected Results and Benefits - -### **Measurable Improvements** -- **50-70% token reduction** through intelligent context optimization -- **Semantic tool selection** replacing brittle keyword matching -- **Cross-session memory** enabling natural conversation continuity -- **Production scalability** supporting thousands of concurrent users - -### **Cost Optimization** -- **Significant API cost savings** through context compression -- **Efficient caching** reducing redundant LLM calls -- **Smart token budgeting** preventing cost overruns -- **Performance monitoring** enabling continuous optimization - -### **Professional Skills** -- **Production-ready AI development** with industry best practices -- **Scalable system architecture** for enterprise deployment -- **Performance optimization** and cost management expertise -- **Advanced context engineering** techniques for complex applications - -## 📁 Project Structure - -``` -notebooks/ -├── README.md # This guide -├── SETUP_GUIDE.md # Detailed setup instructions -│ -├── section-1-context-engineering-foundations/ # Foundation concepts -│ ├── 01_what_is_context_engineering.ipynb -│ └── 02_context_assembly_strategies.ipynb -│ -├── section-2-retrieved-context-engineering/ # RAG patterns -│ ├── 01_rag_fundamentals_and_implementation.ipynb -│ └── 02_crafting_and_optimizing_context.ipynb -│ -├── section-3-memory-systems/ # Memory architecture -│ ├── 01_working_and_longterm_memory.ipynb -│ ├── 02_combining_memory_with_retrieved_context.ipynb -│ └── 03_manage_long_conversations_with_compression_strategies.ipynb -│ -└── section-4-tools-and-agents/ # Production agents - ├── 01_tools_and_langgraph_fundamentals.ipynb - ├── 02_building_course_advisor_agent.ipynb - ├── 03_agent_with_memory_compression.ipynb - └── 04_semantic_tool_selection.ipynb -``` - -## 🎯 Why This Progressive Approach Works - -### **1. Compound Learning** -- **Same agent evolves** - Students see their work improve continuously -- **Skills build on each other** - Each section leverages previous learning -- **Investment pays off** - Time spent early benefits all later sections -- **Natural progression** - Logical flow from simple to sophisticated - -### **2. Production Readiness** -- **Real architecture** - Built on production-ready reference-agent -- **Industry patterns** - Techniques used in enterprise systems -- **Scalable design** - Architecture that handles real-world complexity -- **Professional quality** - Code and patterns ready for production use - -### **3. Hands-On Mastery** -- **Working code** - Every concept demonstrated with runnable examples -- **Immediate feedback** - See results of every change instantly -- **Experimentation friendly** - Easy to modify and test variations -- **Problem-solving focus** - Learn by solving real challenges - -### **4. Measurable Impact** -- **Quantified improvements** - See exact performance gains -- **Cost optimization** - Understand business impact of optimizations -- **Performance metrics** - Track and optimize system behavior -- **Production monitoring** - Real-world performance indicators - -## 🏆 Success Metrics - -By completing this progressive learning path, you will have: - -### **Technical Achievements** -- ✅ Built production-ready AI agents with memory -- ✅ Implemented production-ready architecture patterns -- ✅ Mastered context engineering best practices -- ✅ Created scalable, cost-effective AI systems - -### **Professional Skills** -- ✅ Production AI development experience -- ✅ System optimization and performance tuning -- ✅ Cost management and efficiency optimization -- ✅ Enterprise-grade monitoring and analytics - -### **Portfolio Project** -- ✅ Complete Redis University Course Advisor -- ✅ Production-ready codebase with comprehensive features -- ✅ Demonstrated scalability and optimization -- ✅ Professional documentation and testing - -**🎉 Ready to transform your context engineering skills? Start your journey today!** - ---- - -## 📚 Additional Resources - -### Documentation -- **[SETUP_GUIDE.md](SETUP_GUIDE.md)** - Detailed setup instructions and troubleshooting -- **[Workshop](../workshop/README.md)** - Condensed workshop version -- **[Progressive Agents](../progressive_agents/README.md)** - 6-stage agent learning path -- **[Main Course README](../README.md)** - Top-level course documentation - -### External Resources -- **[Redis Documentation](https://redis.io/docs/)** - Redis official documentation -- **[LangChain Documentation](https://python.langchain.com/)** - LangChain framework docs -- **[LangGraph Documentation](https://langchain-ai.github.io/langgraph/)** - LangGraph stateful agents -- **[Agent Memory Server](https://github.com/redis/agent-memory-server)** - Memory management system -- **[OpenAI API Reference](https://platform.openai.com/docs/api-reference)** - OpenAI API documentation - -### Community -- **[Redis Discord](https://discord.gg/redis)** - Join the Redis community -- **[GitHub Issues](https://github.com/redis-developer/redis-ai-resources/issues)** - Report issues or ask questions -- **[Redis AI Resources](https://github.com/redis-developer/redis-ai-resources)** - More AI examples and recipes - ---- - -## 📝 Course Metadata - -**Version**: 2.0 -**Last Updated**: December 2024 -**Maintainer**: Redis AI Resources Team -**License**: MIT - -**Technologies**: -- Python 3.11+ -- Redis 8.0+ -- LangChain 0.3+ -- LangGraph 0.2+ -- Agent Memory Server 0.12.3+ -- OpenAI GPT-4 - ---- - -**This progressive learning path provides the most comprehensive, hands-on education in context engineering available - taking you from fundamentals to production-ready expertise through a single, evolving project that demonstrates real-world impact.** diff --git a/notebooks/SETUP_GUIDE.md b/notebooks/SETUP_GUIDE.md deleted file mode 100644 index 977d9b5..0000000 --- a/notebooks/SETUP_GUIDE.md +++ /dev/null @@ -1,151 +0,0 @@ -# 🚀 Setup Guide for Context Engineering Notebooks - -This guide helps you set up all required services for the Context Engineering course notebooks. - -## 📋 Prerequisites - -Before running any notebooks, you need: - -1. **Docker Desktop** - For Redis and Agent Memory Server -2. **Python 3.11+** - For running notebooks -3. **OpenAI API Key** - For LLM functionality - -## ⚡ Quick Setup (Recommended) - -From the repository root: - -```bash -# 1. Copy environment file and add your OpenAI API key -cp .env.example .env -# Edit .env and add your OPENAI_API_KEY - -# 2. Start services -docker-compose up -d - -# 3. Install dependencies -uv sync - -# 4. Load course data -uv run python -m redis_context_course.scripts.ingest_courses \ - --catalog src/redis_context_course/data/courses.json \ - --index-name hierarchical_courses \ - --clear - -# 5. Run notebooks -uv run jupyter notebook notebooks/ -``` - -## 🔧 Manual Setup - -If you prefer to set up services manually: - -### 1. Environment Variables - -Create a `.env` file in the repository root: - -```bash -# Create .env file -cat > .env << EOF -OPENAI_API_KEY=your_openai_api_key_here -REDIS_URL=redis://localhost:6379 -AGENT_MEMORY_SERVER_URL=http://localhost:8088 -OPENAI_MODEL=gpt-4o -EOF -``` - -### 2. Start Redis - -```bash -docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest -``` - -### 3. Start Agent Memory Server - -```bash -docker run -d --name agent-memory-server \ - -p 8088:8000 \ - -e REDIS_URL=redis://host.docker.internal:6379 \ - -e OPENAI_API_KEY="your_openai_api_key_here" \ - ghcr.io/redis/agent-memory-server:0.12.3 -``` - -## ✅ Verify Setup - -```bash -# Check Redis -docker exec redis redis-cli ping -# Should return: PONG - -# Check Agent Memory Server -curl http://localhost:8088/v1/health -# Should return: {"now":} - -# Check Docker containers -docker ps -# Should show both redis and agent-memory-server -``` - -## 🚨 Troubleshooting - -### Redis Connection Issues - -If you see Redis connection errors: - -```bash -# Stop and restart Agent Memory Server -docker stop agent-memory-server -docker rm agent-memory-server - -# Restart with correct Redis URL -docker run -d --name agent-memory-server \ - -p 8088:8000 \ - -e REDIS_URL=redis://host.docker.internal:6379 \ - -e OPENAI_API_KEY="your_openai_api_key_here" \ - ghcr.io/redis/agent-memory-server:0.12.3 -``` - -### Port Conflicts - -If ports 6379 or 8088 are in use: - -```bash -# Check what's using the ports -lsof -i :6379 -lsof -i :8088 - -# Stop conflicting services or use different ports -``` - -### Docker Issues - -If Docker commands fail: - -1. Make sure Docker Desktop is running -2. Check Docker has enough resources allocated -3. Try restarting Docker Desktop - -## 📚 Next Steps - -Once setup is complete: - -1. **Start with Section 1** if you're new to context engineering -2. **Jump to Section 4** if you want to learn about memory tools and agents -3. **Check the README** in each section for specific requirements - -## 🔗 Section-Specific Requirements - -### Section 3 & 4: Memory Systems & Tools/Agents -- ✅ Redis (for vector storage) -- ✅ Agent Memory Server (for memory management) -- ✅ OpenAI API key - -### Section 2: RAG Foundations -- ✅ Redis (for vector storage) -- ✅ OpenAI API key - -### Section 1: Context Foundations -- ✅ OpenAI API key only - ---- - -**Need help?** Check the troubleshooting section or review the setup scripts for detailed error handling. diff --git a/notebooks/section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb b/notebooks/section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb deleted file mode 100644 index 0d91cfe..0000000 --- a/notebooks/section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb +++ /dev/null @@ -1,696 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# What is Context Engineering?\n", - "\n", - "## The Problem\n", - "\n", - "Imagine you walk into a doctor's office. The doctor has never met you before, doesn't have access to your medical records, and can't remember anything you said five minutes ago. Every time you visit, it's like the first time all over again.\n", - "\n", - "Sound frustrating? That's what AI agents are like without context engineering.\n", - "\n", - "**Context Engineering** is the discipline of designing, implementing, and optimizing context management systems for AI agents. It's what transforms AI from a stateless question-answering machine into an intelligent assistant that:\n", - "\n", - "- Remembers who you are and what you've discussed\n", - "- Understands its role and capabilities\n", - "- Accesses relevant information from vast knowledge bases\n", - "- Maintains coherent, personalized interactions over time\n", - "\n", - "Consider context engineering as the **\"memory and awareness system\"** for AI agents.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Why Context Engineering Matters\n", - "\n", - "Let's explore this through a real-world example: a university course advisor.\n", - "\n", - "### Scenario: A Student Seeking Advice\n", - "\n", - "**Student Profile:**\n", - "- Name: Sarah Chen\n", - "- Major: Computer Science\n", - "- Year: Junior\n", - "- Completed: Intro to Programming (CS101), Data Structures (CS201), Calculus I\n", - "- Interests: Machine learning, data science\n", - "- Preferences: Prefers online courses, learns best with hands-on projects\n", - "- Goal: Build a career in AI\n", - "\n", - "### Without Context Engineering\n", - "\n", - "Here's what happens when an AI lacks proper context management:\n", - "\n", - "---\n", - "\n", - "**Turn 1:**\n", - "\n", - "*Student:* \"I'm interested in machine learning courses.\"\n", - "\n", - "*Agent:* \"Here are all machine learning courses available:\n", - "- CS301: Introduction to Machine Learning\n", - "- CS401: Advanced Machine Learning\n", - "- CS402: Deep Learning\n", - "- CS403: Natural Language Processing\n", - "- CS404: Computer Vision\n", - "\n", - "All courses meet twice per week on campus.\"\n", - "\n", - "---\n", - "\n", - "**Turn 2:**\n", - "\n", - "*Student:* \"I prefer online courses.\"\n", - "\n", - "*Agent:* \"Here are all machine learning courses available:\n", - "- CS301: Introduction to Machine Learning\n", - "- CS401: Advanced Machine Learning\n", - "\n", - " ...\n", - "\"\n", - "\n", - "*(Same list, ignoring the preference)*\n", - "\n", - "---\n", - "\n", - "**Turn 3:**\n", - "\n", - "*Student:* \"Can I take CS401?\"\n", - "\n", - "*Agent:* \"CS401 requires CS301 as a prerequisite. Do you meet this requirement?\"\n", - "\n", - "*(Doesn't know what courses the student has completed)*\n", - "\n", - "---\n", - "\n", - "**Turn 4:**\n", - "\n", - "*Student:* \"What about that intro course you mentioned earlier?\"\n", - "\n", - "*Agent:* \"I'm not sure which course you're referring to. Could you provide more details?\"\n", - "\n", - "*(Can't remember its own previous responses)*\n", - "\n", - "---\n", - "\n", - "### The Problems Are Clear\n", - "\n", - "**No Memory:**\n", - "- Can't remember what it just said\n", - "- Can't reference earlier parts of the conversation\n", - "- Forces the user to repeat information\n", - "\n", - "**No Personalization:**\n", - "- Ignores user preferences and background\n", - "- Gives generic responses regardless of the user's situation\n", - "- Can't tailor recommendations\n", - "\n", - "**No Awareness:**\n", - "- Doesn't know the user's history or capabilities\n", - "- Can't check prerequisites or eligibility\n", - "- Can't connect to other relevant information\n", - "\n", - "**Result:** A frustrating experience that wastes time and provides little value.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## With Context Engineering\n", - "\n", - "Now let's see the same conversation with proper context management:\n", - "\n", - "---\n", - "\n", - "**Turn 1:**\n", - "\n", - "*Student:* \"I'm interested in machine learning courses.\"\n", - "\n", - "*Agent:* \"Great! Based on your Computer Science major and the courses you've completed (CS101 and CS201), you're ready for CS301: Introduction to Machine Learning.\n", - "\n", - "Since you prefer online courses and hands-on learning, I should mention that CS301 has:\n", - "- A fully online section available\n", - "- Weekly programming assignments with real datasets\n", - "- A final project where you build your own ML system\n", - "\n", - "This course aligns perfectly with your goal of building an AI career and serves as the foundation for more advanced ML courses.\"\n", - "\n", - "---\n", - "\n", - "**Turn 2:**\n", - "\n", - "*Student:* \"That sounds perfect! What comes after that?\"\n", - "\n", - "*Agent:* \"After completing CS301, you'll have several great options:\n", - "\n", - "**Immediately Available:**\n", - "- CS402: Deep Learning (Online, project-based)\n", - " Focus: Neural networks, CNNs, RNNs\n", - " \n", - "- CS403: Natural Language Processing (Online, project-based)\n", - " Focus: Text analysis, transformers, LLMs\n", - "\n", - "**Recommended Path for AI Career:**\n", - "1. CS301 (Introduction) ← Start here\n", - "2. CS402 (Deep Learning) ← Most relevant to modern AI\n", - "3. CS403 (NLP) or CS404 (Computer Vision) ← Specialize\n", - "\n", - "Given your interest in data science, I'd especially recommend the NLP path - it combines well with your data structures background.\"\n", - "\n", - "---\n", - "\n", - "**Turn 3:**\n", - "\n", - "*Student:* \"How long will that path take?\"\n", - "\n", - "*Agent:* \"Let me break it down for you:\n", - "\n", - "**CS301:** 14 weeks (3 credits)\n", - "**CS402:** 14 weeks (3 credits) \n", - "**CS403:** 14 weeks (3 credits)\n", - "\n", - "If you take one course per semester:\n", - "- Fall 2024: CS301\n", - "- Spring 2025: CS402\n", - "- Fall 2025: CS403\n", - "\n", - "Since you're currently a Junior, this timeline would have you completing this sequence before graduation, with one semester remaining for an internship or capstone project.\n", - "\n", - "Alternatively, since these are online courses, you could potentially take CS301 this fall and CS402 in a winter intersession to accelerate your path.\"\n", - "\n", - "---\n", - "\n", - "**Turn 4:**\n", - "\n", - "*Student:* \"I like that accelerated option. Can I register now?\"\n", - "\n", - "*Agent:* \"Yes! Since you've met the prerequisites for CS301, I can guide you through registration. The online section (CS301-W01) has 15 seats remaining.\n", - "\n", - "Would you like me to:\n", - "1. Reserve a seat for you in CS301-W01 for Fall 2024?\n", - "2. Add you to the notification list for the Winter CS402 section (registration opens in October)?\n", - "3. Send you the course syllabus and professor information?\"\n", - "\n", - "---\n", - "\n", - "### The Difference is Dramatic\n", - "\n", - "**With context engineering, the AI:**\n", - "\n", - "✅ **Knows who Sarah is** - Major, year, completed courses, interests \n", - "✅ **Remembers the conversation** - References earlier discussion naturally \n", - "✅ **Provides personalized guidance** - Filters by online preference, learning style \n", - "✅ **Checks prerequisites** - Validates eligibility automatically \n", - "✅ **Plans ahead** - Creates a timeline aligned with graduation \n", - "✅ **Takes action** - Can complete registration, not just discuss it \n", - "\n", - "**Result:** An intelligent, helpful experience that saves time and provides genuine value.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The Business Impact\n", - "\n", - "Poor context management has real business consequences:\n", - "\n", - "### User Experience Degradation\n", - "\n", - "**Without Context Engineering:**\n", - "- Users must repeat information constantly\n", - "- Generic responses feel impersonal and unhelpful\n", - "- Users abandon interactions midway\n", - "- Low satisfaction scores, poor reviews\n", - "\n", - "**Metric Impact:**\n", - "- Low task abandonment rates\n", - "- Low average satisfaction ratings\n", - "- High support ticket volume for \"AI didn't understand me\"\n", - "\n", - "### Operational Inefficiency\n", - "\n", - "**Without Context Engineering:**\n", - "- AI can't complete multi-step workflows\n", - "- Human agents must intervene frequently\n", - "- Same questions asked repeatedly without learning\n", - "- Context is lost between channels (chat → email → phone)\n", - "\n", - "**Cost Impact:**\n", - "- 3-5x more interactions needed to complete tasks\n", - "- Higher escalation rate to human agents\n", - "- Lost productivity from context-switching\n", - "\n", - "### Limited Capabilities\n", - "\n", - "**Without Context Engineering:**\n", - "- Can't handle complex, multi-step tasks\n", - "- No learning or improvement over time\n", - "- Poor integration with existing systems\n", - "- Can't provide proactive assistance\n", - "\n", - "**Strategic Impact:**\n", - "- AI remains a \"nice-to-have\" rather than core capability\n", - "- Can't automate valuable workflows\n", - "- Competitive disadvantage vs. better AI implementations\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 🔬 The Context Rot Problem\n", - "\n", - "Recent research from Chroma (July 2025) reveals a critical challenge in working with LLMs: **context rot** - the phenomenon where LLM performance degrades non-uniformly as input context length increases, even on simple tasks.\n", - "\n", - "### Key Research Findings\n", - "\n", - "**1. Non-Uniform Performance Degradation**\n", - "- Models don't process the 10,000th token as reliably as the 100th token\n", - "- Performance drops aren't linear - they accelerate as context grows\n", - "- Even simple tasks like word repetition fail with long context\n", - "\n", - "**2. Needle-Question Similarity Matters**\n", - "- Lower similarity between questions and retrieved information causes faster performance degradation\n", - "- High semantic relevance is critical for maintaining accuracy\n", - "- Generic or loosely related context actively harms performance\n", - "\n", - "**3. Distractors Have Amplified Impact**\n", - "- Similar-but-wrong information (distractors) degrade performance more as context grows\n", - "- The negative impact of irrelevant information is non-linear\n", - "- Filtering out low-relevance content is as important as finding relevant content\n", - "\n", - "**4. Structure Affects Attention**\n", - "- How you organize context affects model performance\n", - "- Counterintuitively, shuffled text sometimes performs better than coherent text\n", - "- Context window position matters - information placement impacts retrieval accuracy\n", - "\n", - "### Why This Matters for Context Engineering\n", - "\n", - "The Context Rot research validates the core principles of this course:\n", - "\n", - "✅ **Quality Over Quantity**\n", - "More context isn't always better. Adding marginally relevant information can hurt performance more than it helps.\n", - "\n", - "✅ **Semantic Similarity is Critical**\n", - "High relevance between queries and retrieved context is essential. RAG systems must prioritize precision over recall.\n", - "\n", - "✅ **Structure Matters**\n", - "How you organize and present context affects LLM attention mechanisms. Context engineering isn't just about *what* information to include, but *how* to structure it.\n", - "\n", - "✅ **Distractor Removal**\n", - "Filtering out low-relevance information improves performance. Memory systems must be selective about what they store and retrieve.\n", - "\n", - "✅ **Context Window Management**\n", - "Understanding token limits isn't enough - you must understand how performance degrades within those limits.\n", - "\n", - "**This course teaches you techniques to engineer context effectively and avoid these pitfalls.**\n", - "\n", - "📚 **Read the full paper:** [Context Rot: How Increasing Input Tokens Impacts LLM Performance](https://research.trychroma.com/context-rot)\n", - "\n", - "**💡 Preview:** In Section 3, you'll learn compression strategies (truncation, summarization, priority-based) that directly address context rot by managing conversation length while preserving quality. These techniques solve the \"Lost in the Middle\" problem by keeping context focused and well-organized.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The Four Pillars of Context Engineering\n", - "\n", - "Context engineering involves managing four distinct types of context, each serving a different purpose:\n", - "\n", - "### 1. System Context: \"What Am I?\"\n", - "\n", - "Defines the AI's identity, capabilities, and knowledge.\n", - "\n", - "**Contains:**\n", - "- Role definition (\"You are a course advisor\")\n", - "- Available tools and actions\n", - "- Domain knowledge and business rules\n", - "- Behavioral guidelines\n", - "\n", - "**Example:**\n", - "```\n", - "You are a university course advisor specializing in Computer Science.\n", - "\n", - "Available courses: [course catalog]\n", - "Prerequisites rules: [prerequisite map]\n", - "Registration policies: [policy document]\n", - "\n", - "Always verify prerequisites before recommending courses.\n", - "Prioritize student goals when making recommendations.\n", - "```\n", - "\n", - "**Characteristics:** Static, universal, always present\n", - "\n", - "---\n", - "\n", - "### 2. User Context: \"Who Are You?\"\n", - "\n", - "Contains personal information about the specific user.\n", - "\n", - "**Contains:**\n", - "- Profile information (major, year, background)\n", - "- Preferences and learning style\n", - "- History and achievements\n", - "- Goals and constraints\n", - "\n", - "**Example:**\n", - "```\n", - "Student: Sarah Chen\n", - "Major: Computer Science (Junior)\n", - "Completed: CS101, CS201, MATH301\n", - "Interests: Machine learning, data science\n", - "Preferences: Online courses, hands-on projects\n", - "Goal: Build AI career\n", - "```\n", - "\n", - "**Characteristics:** Dynamic, personalized, retrieved from storage\n", - "\n", - "---\n", - "\n", - "### 3. Conversation Context: \"What Have We Discussed?\"\n", - "\n", - "The history of the current conversation.\n", - "\n", - "**Contains:**\n", - "- Previous user messages\n", - "- Previous AI responses\n", - "- Decisions and commitments made\n", - "- Topics explored\n", - "\n", - "**Example:**\n", - "```\n", - "Turn 1:\n", - "User: \"I'm interested in machine learning courses.\"\n", - "AI: \"I recommend CS301: Introduction to Machine Learning...\"\n", - "\n", - "Turn 2:\n", - "User: \"What comes after that?\"\n", - "AI: \"After CS301, you can take CS402 or CS403...\"\n", - "\n", - "Turn 3:\n", - "User: \"How long will that path take?\"\n", - "[Current query - needs context from Turn 2 to understand \"that path\"]\n", - "```\n", - "\n", - "**Characteristics:** Dynamic, session-specific, grows over time\n", - "\n", - "---\n", - "\n", - "### 4. Retrieved Context: \"What Information Is Relevant?\"\n", - "\n", - "Information fetched on-demand based on the current query.\n", - "\n", - "**Contains:**\n", - "- Database records (course details, schedules)\n", - "- Search results (relevant documents, FAQs)\n", - "- API responses (real-time data, availability)\n", - "- Computed information (eligibility checks, recommendations)\n", - "\n", - "**Example:**\n", - "```\n", - "[User asked about CS301]\n", - "\n", - "Retrieved:\n", - "- CS301 course details (description, prerequisites, format)\n", - "- Current availability (15 seats in online section)\n", - "- Professor ratings and reviews\n", - "- Prerequisite check result (✓ Eligible)\n", - "```\n", - "\n", - "**Characteristics:** Dynamic, query-specific, highly targeted\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The Fundamental Challenge: Context Windows\n", - "\n", - "Here's the constraint that makes context engineering necessary:\n", - "\n", - "### Every AI Model Has a Token Limit\n", - "\n", - "AI models can only process a fixed amount of text in a single request - called the **context window**.\n", - "\n", - "| Model | Context Window |\n", - "|-------|----------------|\n", - "| GPT-4o | 128,000 tokens (~96,000 words) |\n", - "| GPT-4o-mini | 128,000 tokens (~96,000 words) |\n", - "| Claude 3.5 Sonnet | 200,000 tokens (~150,000 words) |\n", - "\n", - "### What Competes for This Space?\n", - "\n", - "Everything must fit within this limit:\n", - "\n", - "```\n", - "┌─────────────────────────────────────┐\n", - "│ CONTEXT WINDOW (128K tokens) │\n", - "├─────────────────────────────────────┤\n", - "│ System Context │ 2,000 tokens │ ← AI's role and rules\n", - "│ User Context │ 1,000 tokens │ ← Your profile\n", - "│ Conversation │ 4,000 tokens │ ← What we've discussed\n", - "│ Retrieved Info │ 5,000 tokens │ ← Relevant data\n", - "│ Your Query │ 100 tokens │ ← Current question\n", - "│ Response Space │ 4,000 tokens │ ← AI's answer\n", - "├─────────────────────────────────────┤\n", - "│ TOTAL │ 16,100 tokens │\n", - "│ REMAINING │ 111,900 tokens │\n", - "└─────────────────────────────────────┘\n", - "```\n", - "\n", - "### The Core Trade-off\n", - "\n", - "**Every token spent on one thing is a token NOT available for another.**\n", - "\n", - "This means you must constantly decide:\n", - "- Which context is most relevant?\n", - "- What can be omitted without hurting quality?\n", - "- When to retrieve more vs. use what you have?\n", - "- How to compress long conversations?\n", - "\n", - "**Context engineering is optimization within constraints.**\n", - "\n", - "As conversations grow longer, systems accumulate more data, and applications become more sophisticated, context management becomes increasingly critical.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Real-World Applications\n", - "\n", - "Context engineering isn't just theoretical - it's essential for any production AI system:\n", - "\n", - "### Customer Support Agents\n", - "\n", - "**Context Needed:**\n", - "- Customer profile and purchase history (User Context)\n", - "- Previous support tickets and resolutions (Conversation Context)\n", - "- Product documentation and FAQs (Retrieved Context)\n", - "- Company policies and escalation procedures (System Context)\n", - "\n", - "**Without proper context:** Agent can't see order history, doesn't remember previous issues, can't access relevant documentation → frustrated customers, high escalation rates\n", - "\n", - "### Healthcare Assistants\n", - "\n", - "**Context Needed:**\n", - "- Patient medical history and conditions (User Context)\n", - "- Current conversation and symptoms (Conversation Context)\n", - "- Relevant medical guidelines and drug interactions (Retrieved Context)\n", - "- Clinical protocols and legal requirements (System Context)\n", - "\n", - "**Without proper context:** Can't consider patient history, might miss contraindications, can't follow proper diagnostic protocols → dangerous mistakes\n", - "\n", - "### Sales Assistants\n", - "\n", - "**Context Needed:**\n", - "- Customer demographics and past purchases (User Context)\n", - "- Current conversation and stated needs (Conversation Context)\n", - "- Product catalog and inventory (Retrieved Context)\n", - "- Pricing rules and promotional policies (System Context)\n", - "\n", - "**Without proper context:** Makes inappropriate recommendations, can't personalize offers, doesn't know what's in stock → lost sales\n", - "\n", - "### Research Assistants\n", - "\n", - "**Context Needed:**\n", - "- Researcher's field and prior work (User Context)\n", - "- Research question evolution (Conversation Context)\n", - "- Relevant papers and datasets (Retrieved Context)\n", - "- Methodological guidelines and ethics (System Context)\n", - "\n", - "**Without proper context:** Suggests irrelevant papers, doesn't build on previous research direction, can't filter by expertise level → wasted time\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## What Makes Context Engineering Hard?\n", - "\n", - "If context is so important, why don't all AI systems handle it well? Several challenges:\n", - "\n", - "### 1. Scale and Complexity\n", - "\n", - "- **User base:** Managing context for millions of users\n", - "- **Data volume:** Gigabytes of documents, conversation history, user profiles\n", - "- **Real-time constraints:** Must retrieve relevant context in milliseconds\n", - "- **Multi-modal:** Text, images, structured data, API responses\n", - "\n", - "### 2. Relevance Determination\n", - "\n", - "- **Semantic understanding:** \"ML courses\" and \"machine learning classes\" are the same\n", - "- **Context dependency:** Relevance changes based on user background and goals\n", - "- **Implicit needs:** User asks X but really needs Y\n", - "- **Conflicting signals:** Multiple pieces of context suggest different actions\n", - "\n", - "### 3. Memory Management\n", - "\n", - "- **What to remember:** Important facts vs. casual remarks\n", - "- **How long to remember:** Session vs. long-term memory\n", - "- **When to forget:** Outdated info, privacy requirements\n", - "- **How to summarize:** Compress long conversations without losing meaning\n", - "\n", - "### 4. Integration Challenges\n", - "\n", - "- **Multiple data sources:** CRM, databases, APIs, documents\n", - "- **Different formats:** JSON, text, tables, graphs\n", - "- **Access control:** Privacy, permissions, data sovereignty\n", - "- **Latency requirements:** Fast retrieval vs. comprehensive search\n", - "\n", - "### 5. Cost and Performance\n", - "\n", - "- **Token costs:** More context = higher API costs\n", - "- **Latency:** More retrieval = slower responses\n", - "- **Storage:** Maintaining user profiles and conversation history\n", - "- **Compute:** Embeddings, similarity search, real-time updates\n", - "\n", - "**This is why context engineering is a specialized discipline.**\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Your Learning Journey\n", - "\n", - "You now understand **why** context engineering matters. You've seen:\n", - "\n", - "✅ The dramatic difference between AI with and without proper context \n", - "✅ The business impact of poor context management \n", - "✅ The four core context types and their purposes \n", - "✅ The fundamental constraint of context windows \n", - "✅ Real-world applications across industries \n", - "✅ The challenges that make this discipline necessary \n", - "\n", - "### What Comes Next\n", - "\n", - "Now that you understand the \"why,\" it's time to learn the \"how.\"\n", - "\n", - "In the next notebook, you'll get hands-on experience with:\n", - "\n", - "**Context Types Deep Dive**\n", - "- Building each context type step-by-step\n", - "- Formatting context for LLMs\n", - "- Combining multiple context types\n", - "- Managing token budgets\n", - "- Implementing adaptive context strategies\n", - "\n", - "You'll build a working Redis University course advisor that uses all four context types to provide intelligent, personalized recommendations.\n", - "\n", - "**By the end of the next notebook, you'll be able to:**\n", - "- Build context-aware AI agents from scratch\n", - "- Choose the right context type for each piece of information\n", - "- Optimize context usage within token constraints\n", - "- Test and iterate on context strategies\n", - "\n", - "### The Path Forward\n", - "\n", - "This course follows a carefully designed progression:\n", - "\n", - "**Chapter 1: Foundations** ← You are here\n", - "- Understanding context engineering (✓)\n", - "- Implementing the four context types (Next →)\n", - "\n", - "**Chapter 2: RAG Systems**\n", - "\n", - "**Chapter 3: Incorporating Memory**\n", - "- Long-term memory with Redis Agent Memory Server\n", - "- Working memory patterns\n", - "- Multi-agent memory coordination\n", - "\n", - "**Chapter 4: Agent with tools**\n", - "Each chapter builds on the previous one, taking you from fundamentals to production-ready systems.\n", - "\n", - "---\n", - "\n", - "## Ready to Build?\n", - "\n", - "You've seen the power of context engineering and understand why it's critical for AI systems.\n", - "\n", - "Now it's time to build one yourself.\n", - "\n", - "**Continue to: `02_context_assembly_strategies.ipynb` →**\n", - "\n", - "In the next notebook, you'll write code, format context, make LLM calls, and see real results. You'll transform from understanding *why* context matters to knowing *how* to implement it effectively.\n", - "\n", - "Let's get started." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.7" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/notebooks/section-1-context-engineering-foundations/02_context_assembly_strategies.ipynb b/notebooks/section-1-context-engineering-foundations/02_context_assembly_strategies.ipynb deleted file mode 100644 index 135583d..0000000 --- a/notebooks/section-1-context-engineering-foundations/02_context_assembly_strategies.ipynb +++ /dev/null @@ -1,1768 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# Context Types Deep Dive\n", - "\n", - "## What You'll Learn\n", - "\n", - "In this notebook, you'll master the four core context types that power intelligent AI agents:\n", - "\n", - "1. **System Context** - The AI's role and domain knowledge\n", - "2. **User Context** - Personal profiles and preferences\n", - "3. **Conversation Context** - Dialogue history and flow\n", - "4. **Retrieved Context** - Dynamic information from external sources\n", - "\n", - "You'll learn both the **theory** (what each type is and when to use it) and the **practice** (how to build and combine them effectively).\n", - "\n", - "**Time to complete:** 20-25 minutes\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "Let's start with the essentials. You'll need an OpenAI API key to run the examples." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:12.604772Z", - "start_time": "2025-12-03T23:45:12.348407Z" - } - }, - "outputs": [], - "source": [ - "import os\n", - "\n", - "from dotenv import load_dotenv\n", - "from openai import OpenAI\n", - "\n", - "# Load environment variables\n", - "load_dotenv()\n", - "\n", - "# Initialize OpenAI client\n", - "client = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## Understanding the Context Window Constraint\n", - "\n", - "Before we dive into context types, you need to understand the fundamental limitation that shapes all context engineering decisions.\n", - "\n", - "### The Token Limit Reality\n", - "\n", - "Every AI model has a **context window** - a maximum amount of text it can process in a single request.\n", - "\n", - "| Model | Context Window | Approximate Words |\n", - "|-------|----------------|-------------------|\n", - "| GPT-4o | 128,000 tokens | ~96,000 words |\n", - "| GPT-4o-mini | 128,000 tokens | ~96,000 words |\n", - "| Claude 3.5 Sonnet | 200,000 tokens | ~150,000 words |\n", - "\n", - "**Note:** 1 token ≈ 0.75 words in English\n", - "\n", - "### What Competes for This Space?\n", - "\n", - "Every element of your request must fit within this limit:\n", - "\n", - "```\n", - "┌─────────────────────────────────────────┐\n", - "│ CONTEXT WINDOW (128K tokens) │\n", - "├─────────────────────────────────────────┤\n", - "│ System Instructions │ 2,000 │\n", - "│ Tool Definitions │ 3,000 │\n", - "│ User Profile │ 1,000 │\n", - "│ Conversation History │ 4,000 │\n", - "│ Retrieved Context │ 5,000 │\n", - "│ User Query │ 500 │\n", - "│ Response Space │ 4,000 │\n", - "├─────────────────────────────────────────┤\n", - "│ TOTAL USED │ 19,500 │\n", - "│ REMAINING │ 108,500 │\n", - "└─────────────────────────────────────────┘\n", - "```\n", - "\n", - "### The Core Trade-off\n", - "\n", - "**Every token spent on one thing is a token NOT available for another.**\n", - "\n", - "This means context engineering requires constant decision-making:\n", - "- Is this information relevant to the current query?\n", - "- Does including this improve response quality?\n", - "- Is the improvement worth the token cost?\n", - "\n", - "**All three must be \"yes\" or don't include it.**\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The Four Core Context Types\n", - "\n", - "Every context-aware AI system uses these four components. Let's explore each one, understand when to use it, and learn how to implement it.\n", - "\n", - "Throughout this notebook, we'll build a **Redis University course advisor** that helps students choose the right courses based on their background, goals, and learning path.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. System Context: The AI's Identity\n", - "\n", - "### What Is System Context?\n", - "\n", - "System context defines **what the AI is** and **what it knows**. This is static information that:\n", - "- Applies to ALL users equally\n", - "- Rarely changes (typically only with code deployments)\n", - "- Is hardcoded in your application\n", - "- Must always be present\n", - "\n", - "### What Goes in System Context?\n", - "\n", - "1. **Role Definition** - What is the AI's purpose?\n", - "2. **Domain Knowledge** - What information does it have?\n", - "3. **Behavioral Instructions** - How should it respond?\n", - "4. **Business Rules** - What constraints apply?\n", - "\n", - "### When to Use System Context\n", - "\n", - "Use system context for information that:\n", - "- ✅ Defines the agent's core identity\n", - "- ✅ Contains universal business logic\n", - "- ✅ Provides essential domain knowledge\n", - "- ✅ Should be consistent across all interactions\n", - "\n", - "### Building System Context Step-by-Step" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:13.623394Z", - "start_time": "2025-12-03T23:45:13.621366Z" - } - }, - "outputs": [], - "source": [ - "# Step 1: Define the AI's role\n", - "system_context = \"\"\"You are a Redis University course advisor.\"\"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is the foundation - but it's not enough. The AI needs domain knowledge to be useful." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:14.904988Z", - "start_time": "2025-12-03T23:45:14.903262Z" - } - }, - "outputs": [], - "source": [ - "# Step 2: Add domain knowledge (available courses)\n", - "system_context = \"\"\"You are a Redis University course advisor.\n", - "\n", - "Available Courses:\n", - "- RU101: Introduction to Redis Data Structures (Beginner, 4-6 hours)\n", - " Learn Redis fundamentals: strings, hashes, lists, sets, sorted sets\n", - "\n", - "- RU201: Redis for Python Developers (Intermediate, 6-8 hours)\n", - " Prerequisites: RU101, Python experience\n", - " Build Redis applications with Python and redis-py\n", - "\n", - "- RU202: Redis for Java Developers (Intermediate, 6-8 hours)\n", - " Prerequisites: RU101, Java experience\n", - " Build Redis applications with Java and Jedis\n", - "\n", - "- RU301: Vector Similarity Search with Redis (Advanced, 8-10 hours)\n", - " Prerequisites: RU201 or RU202, ML/AI interest\n", - " Implement semantic search and RAG systems\n", - "\"\"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we have both role and knowledge. Finally, let's add behavioral guidance." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:15.868204Z", - "start_time": "2025-12-03T23:45:15.866316Z" - } - }, - "outputs": [], - "source": [ - "# Step 3: Add behavioral instructions and business rules\n", - "system_context = \"\"\"You are a Redis University course advisor.\n", - "\n", - "Available Courses:\n", - "- RU101: Introduction to Redis Data Structures (Beginner, 4-6 hours)\n", - " Learn Redis fundamentals: strings, hashes, lists, sets, sorted sets\n", - "\n", - "- RU201: Redis for Python Developers (Intermediate, 6-8 hours)\n", - " Prerequisites: RU101, Python experience\n", - " Build Redis applications with Python and redis-py\n", - "\n", - "- RU202: Redis for Java Developers (Intermediate, 6-8 hours)\n", - " Prerequisites: RU101, Java experience\n", - " Build Redis applications with Java and Jedis\n", - "\n", - "- RU301: Vector Similarity Search with Redis (Advanced, 8-10 hours)\n", - " Prerequisites: RU201 or RU202, ML/AI interest\n", - " Implement semantic search and RAG systems\n", - "\n", - "Guidelines:\n", - "1. Always provide specific course recommendations with clear reasoning\n", - "2. Consider the student's background, completed courses, and interests\n", - "3. Ensure prerequisites are met before recommending advanced courses\n", - "4. Be encouraging and supportive in your guidance\n", - "\"\"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Key Insight: System Context is Universal\n", - "\n", - "Notice that system context doesn't mention any specific user. It's the same for everyone. Whether the student is Sarah, Alex, or anyone else, this context remains constant.\n", - "\n", - "This is what makes it \"static\" - you write it once in your code and it's always present with a fixed token cost.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. User Context: Personal Information\n", - "\n", - "### What Is User Context?\n", - "\n", - "User context contains **information about the specific user** that enables personalization. Unlike system context, this is dynamic and different for each user.\n", - "\n", - "### What Goes in User Context?\n", - "\n", - "1. **Profile Information** - Name, background, experience level\n", - "2. **Learning History** - Completed courses, achievements\n", - "3. **Preferences** - Learning style, time availability, interests\n", - "4. **Goals** - What the user wants to achieve\n", - "\n", - "### When to Use User Context\n", - "\n", - "Use user context when:\n", - "- ✅ Information is specific to an individual user\n", - "- ✅ Personalization will significantly improve responses\n", - "- ✅ The information persists across multiple sessions\n", - "- ✅ You have a reliable way to store and retrieve user data\n", - "\n", - "### Building User Context Step-by-Step" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:17.206767Z", - "start_time": "2025-12-03T23:45:17.204666Z" - } - }, - "outputs": [], - "source": [ - "# Step 1: Create a user profile as a dictionary\n", - "# In production, this would come from a database\n", - "sarah_profile = {\n", - " \"name\": \"Sarah Chen\",\n", - " \"background\": \"Python developer, 2 years experience\",\n", - " \"completed_courses\": [\"RU101\"],\n", - " \"interests\": [\"machine learning\", \"data science\", \"vector search\"],\n", - " \"time_availability\": \"evenings and weekends\",\n", - " \"goal\": \"Build a RAG system for my company's documentation\",\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The dictionary format is great for storage, but we need to format it for the LLM." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:18.233651Z", - "start_time": "2025-12-03T23:45:18.231228Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Student Profile:\n", - "- Name: Sarah Chen\n", - "- Background: Python developer, 2 years experience\n", - "- Completed Courses: RU101\n", - "- Interests: machine learning, data science, vector search\n", - "- Availability: evenings and weekends\n", - "- Goal: Build a RAG system for my company's documentation\n", - "\n" - ] - } - ], - "source": [ - "# Step 2: Format as context for the LLM\n", - "\n", - "\n", - "def format_user_context(profile):\n", - " \"\"\"Convert user profile dictionary to formatted context string\"\"\"\n", - " return f\"\"\"Student Profile:\n", - "- Name: {profile['name']}\n", - "- Background: {profile['background']}\n", - "- Completed Courses: {', '.join(profile['completed_courses'])}\n", - "- Interests: {', '.join(profile['interests'])}\n", - "- Availability: {profile['time_availability']}\n", - "- Goal: {profile['goal']}\n", - "\"\"\"\n", - "\n", - "\n", - "user_context = format_user_context(sarah_profile)\n", - "print(user_context)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Understanding User Context Differences\n", - "\n", - "Let's create another user to see how context changes:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:19.081535Z", - "start_time": "2025-12-03T23:45:19.079313Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Student Profile:\n", - "- Name: Alex Kumar\n", - "- Background: Java backend engineer, 5 years experience\n", - "- Completed Courses: RU101, RU202\n", - "- Interests: distributed systems, caching, performance optimization\n", - "- Availability: flexible schedule\n", - "- Goal: Optimize database query performance with Redis caching\n", - "\n" - ] - } - ], - "source": [ - "# Create a different user with different needs\n", - "alex_profile = {\n", - " \"name\": \"Alex Kumar\",\n", - " \"background\": \"Java backend engineer, 5 years experience\",\n", - " \"completed_courses\": [\"RU101\", \"RU202\"],\n", - " \"interests\": [\"distributed systems\", \"caching\", \"performance optimization\"],\n", - " \"time_availability\": \"flexible schedule\",\n", - " \"goal\": \"Optimize database query performance with Redis caching\",\n", - "}\n", - "\n", - "alex_context = format_user_context(alex_profile)\n", - "print(alex_context)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Key Insight: Different Users = Different Context\n", - "\n", - "Notice how Sarah and Alex have:\n", - "- Different programming backgrounds (Python vs Java)\n", - "- Different completed courses\n", - "- Different interests and goals\n", - "\n", - "This personalized context allows the AI to give tailored recommendations. Sarah might be guided toward RU201 and RU301, while Alex might focus on advanced caching strategies.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. Conversation Context: Maintaining Dialogue Flow\n", - "\n", - "### What Is Conversation Context?\n", - "\n", - "Conversation context is the **history of the current dialogue**. It allows the AI to:\n", - "- Remember what was just discussed\n", - "- Understand references like \"it\" or \"that course\"\n", - "- Build on previous responses\n", - "- Maintain coherent multi-turn conversations\n", - "\n", - "### What Goes in Conversation Context?\n", - "\n", - "1. **Previous User Messages** - What the user has asked\n", - "2. **Previous AI Responses** - What the AI has said\n", - "3. **Context from Earlier in the Session** - Background established during this interaction\n", - "\n", - "### When to Use Conversation Context\n", - "\n", - "Always include conversation context for:\n", - "- ✅ Multi-turn conversations (more than a single Q&A)\n", - "- ✅ When users reference \"it\", \"that\", or previous topics\n", - "- ✅ When building on previous responses\n", - "- ✅ When maintaining coherent dialogue\n", - "\n", - "### Building Conversation Context Step-by-Step" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:20.899899Z", - "start_time": "2025-12-03T23:45:20.898042Z" - } - }, - "outputs": [], - "source": [ - "# Step 1: Start with an empty conversation history\n", - "conversation_history = []" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As the conversation progresses, we add each exchange to the history." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:21.906847Z", - "start_time": "2025-12-03T23:45:21.905161Z" - } - }, - "outputs": [], - "source": [ - "# Step 2: Add the first user message\n", - "conversation_history.append(\n", - " {\"role\": \"user\", \"content\": \"What Redis course should I take next?\"}\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:22.330890Z", - "start_time": "2025-12-03T23:45:22.328974Z" - } - }, - "outputs": [], - "source": [ - "# Step 3: Add the AI's response (simulated)\n", - "conversation_history.append(\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"\"\"Based on your Python background and completion of RU101, \n", - "I recommend RU201: Redis for Python Developers. This course will teach you \n", - "how to build Redis applications using redis-py, which aligns perfectly with \n", - "your goal of building a RAG system.\"\"\",\n", - " }\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:22.775681Z", - "start_time": "2025-12-03T23:45:22.773714Z" - } - }, - "outputs": [], - "source": [ - "# Step 4: Add a follow-up question that references previous context\n", - "conversation_history.append(\n", - " {\"role\": \"user\", \"content\": \"How long will that take me to complete?\"}\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice the user said \"that\" instead of \"RU201\". The AI needs the conversation history to understand what \"that\" refers to." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:23.938541Z", - "start_time": "2025-12-03T23:45:23.936388Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Turn 1 (user):\n", - "What Redis course should I take next?\n", - "\n", - "Turn 2 (assistant):\n", - "Based on your Python background and completion of RU101, \n", - "I recommend RU201: Redis for Python Developers. This course will teach you \n", - "how to build Redis applications using redis-py, which aligns perfectly with \n", - "your goal of building a RAG system.\n", - "\n", - "Turn 3 (user):\n", - "How long will that take me to complete?\n", - "\n" - ] - } - ], - "source": [ - "# Let's view the complete conversation history\n", - "for i, msg in enumerate(conversation_history, 1):\n", - " print(f\"Turn {i} ({msg['role']}):\")\n", - " print(f\"{msg['content']}\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Key Insight: Conversation History Enables Natural Dialogue\n", - "\n", - "Without conversation history:\n", - "- ❌ \"How long will **that** take?\" → AI doesn't know what \"that\" refers to\n", - "\n", - "With conversation history:\n", - "- ✅ \"How long will **that** take?\" → AI knows \"that\" = RU201\n", - "\n", - "### Managing Context Window with Long Conversations\n", - "\n", - "As conversations grow, they consume more tokens. Common strategies:\n", - "\n", - "1. **Keep recent history** - Only include last N turns\n", - "2. **Summarize older context** - Compress early conversation into a summary\n", - "3. **Extract key facts** - Pull out important decisions/facts, discard the rest\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4. Retrieved Context: Dynamic Information\n", - "\n", - "### What Is Retrieved Context?\n", - "\n", - "Retrieved context is **relevant information fetched on-demand** based on the current query. This is the most dynamic type of context - it changes with every query.\n", - "\n", - "### What Goes in Retrieved Context?\n", - "\n", - "1. **Database Records** - Course details, user records, etc.\n", - "2. **Search Results** - Relevant documents from vector/semantic search\n", - "3. **API Responses** - Real-time data from external services\n", - "4. **Computed Information** - Analysis or calculations performed on-demand\n", - "\n", - "### When to Use Retrieved Context\n", - "\n", - "Use retrieved context when:\n", - "- ✅ Information is too large to include statically\n", - "- ✅ Only a small subset is relevant to each query\n", - "- ✅ Information changes frequently\n", - "- ✅ You can retrieve it efficiently based on the query\n", - "\n", - "### Building Retrieved Context Step-by-Step" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:25.926833Z", - "start_time": "2025-12-03T23:45:25.924293Z" - } - }, - "outputs": [], - "source": [ - "# Step 1: Simulate a course database\n", - "# In production, this would be Redis, etc.\n", - "course_database = {\n", - " \"RU101\": {\n", - " \"title\": \"Introduction to Redis Data Structures\",\n", - " \"level\": \"Beginner\",\n", - " \"description\": \"Master Redis fundamentals: strings, hashes, lists, sets, and sorted sets\",\n", - " \"duration\": \"4-6 hours\",\n", - " \"prerequisites\": [],\n", - " \"topics\": [\"Data structures\", \"Basic commands\", \"Use cases\"],\n", - " },\n", - " \"RU201\": {\n", - " \"title\": \"Redis for Python Developers\",\n", - " \"level\": \"Intermediate\",\n", - " \"description\": \"Build production Redis applications with Python and redis-py\",\n", - " \"duration\": \"6-8 hours\",\n", - " \"prerequisites\": [\"RU101\", \"Python experience\"],\n", - " \"topics\": [\"redis-py library\", \"Connection pooling\", \"Pipelining\", \"Pub/Sub\"],\n", - " },\n", - " \"RU202\": {\n", - " \"title\": \"Redis for Java Developers\",\n", - " \"level\": \"Intermediate\",\n", - " \"description\": \"Build production Redis applications with Java and Jedis\",\n", - " \"duration\": \"6-8 hours\",\n", - " \"prerequisites\": [\"RU101\", \"Java experience\"],\n", - " \"topics\": [\n", - " \"Jedis library\",\n", - " \"Connection pooling\",\n", - " \"Transactions\",\n", - " \"Redis Streams\",\n", - " ],\n", - " },\n", - " \"RU301\": {\n", - " \"title\": \"Vector Similarity Search with Redis\",\n", - " \"level\": \"Advanced\",\n", - " \"description\": \"Implement semantic search and RAG systems with Redis vector capabilities\",\n", - " \"duration\": \"8-10 hours\",\n", - " \"prerequisites\": [\"RU201 or RU202\", \"ML/AI interest\"],\n", - " \"topics\": [\n", - " \"Vector embeddings\",\n", - " \"Semantic search\",\n", - " \"RAG architecture\",\n", - " \"Hybrid search\",\n", - " ],\n", - " },\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's simulate retrieving course information based on a query." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:28.216611Z", - "start_time": "2025-12-03T23:45:28.213653Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Course Details:\n", - "Code: RU201\n", - "Title: Redis for Python Developers\n", - "Level: Intermediate\n", - "Description: Build production Redis applications with Python and redis-py\n", - "Duration: 6-8 hours\n", - "Prerequisites: RU101, Python experience\n", - "Topics Covered: redis-py library, Connection pooling, Pipelining, Pub/Sub\n", - "\n" - ] - } - ], - "source": [ - "# Step 2: Create a retrieval function\n", - "\n", - "\n", - "def retrieve_course_info(course_code):\n", - " \"\"\"Retrieve detailed information about a specific course\"\"\"\n", - " course = course_database.get(course_code)\n", - " if not course:\n", - " return None\n", - "\n", - " return f\"\"\"Course Details:\n", - "Code: {course_code}\n", - "Title: {course['title']}\n", - "Level: {course['level']}\n", - "Description: {course['description']}\n", - "Duration: {course['duration']}\n", - "Prerequisites: {', '.join(course['prerequisites']) if course['prerequisites'] else 'None'}\n", - "Topics Covered: {', '.join(course['topics'])}\n", - "\"\"\"\n", - "\n", - "\n", - "# Retrieve information about RU201\n", - "retrieved_context = retrieve_course_info(\"RU201\")\n", - "print(retrieved_context)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Key Insight: Retrieved Context is Query-Specific\n", - "\n", - "Notice that we only retrieved information about RU201 - the course the user asked about. We didn't include:\n", - "- RU101 details (user already completed it)\n", - "- RU202 details (not relevant to a Python developer)\n", - "- RU301 details (not the current focus)\n", - "\n", - "This selective retrieval is what makes this approach scalable. Imagine having 500 courses - you can't include them all in every request, but you can retrieve the 2-3 most relevant ones.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Bringing It All Together: Complete Context Integration\n", - "\n", - "Now that we understand each context type individually, let's see how they work together to create an intelligent, personalized response.\n", - "\n", - "### The Complete Picture\n", - "\n", - "Here's how all four context types combine in a single LLM call:\n", - "\n", - "```\n", - "┌─────────────────────────────────────────────┐\n", - "│ COMPLETE LLM REQUEST │\n", - "├─────────────────────────────────────────────┤\n", - "│ 1. SYSTEM CONTEXT (Static) │\n", - "│ - Role: \"You are a course advisor\" │\n", - "│ - Domain: Available courses │\n", - "│ - Rules: Guidelines and constraints │\n", - "├─────────────────────────────────────────────┤\n", - "│ 2. USER CONTEXT (Dynamic - User Specific) │\n", - "│ - Profile: Sarah Chen, Python dev │\n", - "│ - History: Completed RU101 │\n", - "│ - Goal: Build RAG system │\n", - "├─────────────────────────────────────────────┤\n", - "│ 3. CONVERSATION CONTEXT (Dynamic - Session) │\n", - "│ - User: \"What course should I take?\" │\n", - "│ - AI: \"I recommend RU201...\" │\n", - "│ - User: \"How long will that take?\" │\n", - "├─────────────────────────────────────────────┤\n", - "│ 4. RETRIEVED CONTEXT (Dynamic - Query) │\n", - "│ - RU201 course details │\n", - "│ - Duration, prerequisites, topics │\n", - "├─────────────────────────────────────────────┤\n", - "│ RESULT: Personalized, context-aware answer │\n", - "└─────────────────────────────────────────────┘\n", - "```\n", - "\n", - "### Let's Build This Step-by-Step" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:31.029112Z", - "start_time": "2025-12-03T23:45:31.027001Z" - } - }, - "outputs": [], - "source": [ - "# Step 1: Start with system context\n", - "messages = [{\"role\": \"system\", \"content\": system_context}]" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:31.521575Z", - "start_time": "2025-12-03T23:45:31.519343Z" - } - }, - "outputs": [], - "source": [ - "# Step 2: Add user context\n", - "messages.append({\"role\": \"system\", \"content\": user_context})" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:32.012699Z", - "start_time": "2025-12-03T23:45:32.010368Z" - } - }, - "outputs": [], - "source": [ - "# Step 3: Add conversation history\n", - "messages.extend(conversation_history)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:32.426405Z", - "start_time": "2025-12-03T23:45:32.424440Z" - } - }, - "outputs": [], - "source": [ - "# Step 4: Add retrieved context\n", - "messages.append({\"role\": \"system\", \"content\": retrieved_context})" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:33.216540Z", - "start_time": "2025-12-03T23:45:33.212475Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'role': 'system',\n", - " 'content': \"You are a Redis University course advisor.\\n\\nAvailable Courses:\\n- RU101: Introduction to Redis Data Structures (Beginner, 4-6 hours)\\n Learn Redis fundamentals: strings, hashes, lists, sets, sorted sets\\n\\n- RU201: Redis for Python Developers (Intermediate, 6-8 hours)\\n Prerequisites: RU101, Python experience\\n Build Redis applications with Python and redis-py\\n\\n- RU202: Redis for Java Developers (Intermediate, 6-8 hours)\\n Prerequisites: RU101, Java experience\\n Build Redis applications with Java and Jedis\\n\\n- RU301: Vector Similarity Search with Redis (Advanced, 8-10 hours)\\n Prerequisites: RU201 or RU202, ML/AI interest\\n Implement semantic search and RAG systems\\n\\nGuidelines:\\n1. Always provide specific course recommendations with clear reasoning\\n2. Consider the student's background, completed courses, and interests\\n3. Ensure prerequisites are met before recommending advanced courses\\n4. Be encouraging and supportive in your guidance\\n\"},\n", - " {'role': 'system',\n", - " 'content': \"Student Profile:\\n- Name: Sarah Chen\\n- Background: Python developer, 2 years experience\\n- Completed Courses: RU101\\n- Interests: machine learning, data science, vector search\\n- Availability: evenings and weekends\\n- Goal: Build a RAG system for my company's documentation\\n\"},\n", - " {'role': 'user', 'content': 'What Redis course should I take next?'},\n", - " {'role': 'assistant',\n", - " 'content': 'Based on your Python background and completion of RU101, \\nI recommend RU201: Redis for Python Developers. This course will teach you \\nhow to build Redis applications using redis-py, which aligns perfectly with \\nyour goal of building a RAG system.'},\n", - " {'role': 'user', 'content': 'How long will that take me to complete?'},\n", - " {'role': 'system',\n", - " 'content': 'Course Details:\\nCode: RU201\\nTitle: Redis for Python Developers\\nLevel: Intermediate\\nDescription: Build production Redis applications with Python and redis-py\\nDuration: 6-8 hours\\nPrerequisites: RU101, Python experience\\nTopics Covered: redis-py library, Connection pooling, Pipelining, Pub/Sub\\n'}]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Making the Complete LLM Call" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:45:36.594665Z", - "start_time": "2025-12-03T23:45:34.606057Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "AI Response:\n", - "The RU201: Redis for Python Developers course will take you approximately 6-8 hours to complete. This timeframe is flexible and can be adjusted based on your availability during evenings and weekends. You'll gain valuable skills that will help you in building your RAG system for your company's documentation. Enjoy your learning journey!\n" - ] - } - ], - "source": [ - "# Make the LLM call with complete context\n", - "response = client.chat.completions.create(\n", - " model=\"gpt-4o-mini\", messages=messages, temperature=0.7\n", - ")\n", - "\n", - "answer = response.choices[0].message.content\n", - "print(\"AI Response:\")\n", - "print(answer)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### What Just Happened?\n", - "\n", - "The LLM received all four context types and used them to generate a personalized response:\n", - "\n", - "1. **System Context** told it to act as a course advisor and provided course information\n", - "2. **User Context** gave it Sarah's background, interests, and goals\n", - "3. **Conversation Context** showed that \"that\" refers to RU201\n", - "4. **Retrieved Context** provided detailed information about RU201's duration and topics\n", - "\n", - "The result is a response that:\n", - "- Understands what course \"that\" refers to\n", - "- Considers Sarah's available time (evenings and weekends)\n", - "- Relates the duration to her specific situation\n", - "- Stays aligned with her goal of building a RAG system\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Context Management Strategies\n", - "\n", - "Different situations require different approaches to context management. Let's explore three common strategies.\n", - "\n", - "### Strategy 1: New User (Minimal Context)\n", - "\n", - "**Scenario:** First-time user, no conversation history\n", - "\n", - "| Context Type | What to Include | Token Budget |\n", - "|--------------|-----------------|-------------|\n", - "| System | Full role definition and course catalog | 2,000 |\n", - "| User | Basic profile only (if available) | 500 |\n", - "| Conversation | Empty (new session) | 0 |\n", - "| Retrieved | General overview information | 1,000 |\n", - "| **Total** | | **3,500** |\n", - "\n", - "**Use when:**\n", - "- First interaction with a user\n", - "- No user history available\n", - "- Providing general guidance\n", - "\n", - "### Strategy 2: Returning User (Rich Context)\n", - "\n", - "**Scenario:** User with history, ongoing conversation\n", - "\n", - "| Context Type | What to Include | Token Budget |\n", - "|--------------|-----------------|-------------|\n", - "| System | Full role definition and course catalog | 2,000 |\n", - "| User | Complete profile + learning history | 1,500 |\n", - "| Conversation | Last 5-10 turns of dialogue | 3,000 |\n", - "| Retrieved | Personalized, highly relevant course details | 2,000 |\n", - "| **Total** | | **8,500** |\n", - "\n", - "**Use when:**\n", - "- User has established history\n", - "- Multi-turn conversation in progress\n", - "- Deep personalization is valuable\n", - "\n", - "### Strategy 3: Long Conversation (Optimized Context)\n", - "\n", - "**Scenario:** Approaching token limits, need to optimize\n", - "\n", - "| Context Type | What to Include | Token Budget |\n", - "|--------------|-----------------|-------------|\n", - "| System | Condensed role + essential rules only | 1,000 |\n", - "| User | Key profile facts only | 500 |\n", - "| Conversation | Summarized key decisions + last 3 turns | 2,000 |\n", - "| Retrieved | Only the most relevant details | 1,000 |\n", - "| **Total** | | **4,500** |\n", - "\n", - "**Use when:**\n", - "- Conversation has many turns\n", - "- Approaching context window limit\n", - "- Need to maintain performance\n", - "\n", - "### Implementing an Adaptive Strategy" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:46:13.539806Z", - "start_time": "2025-12-03T23:46:13.536340Z" - } - }, - "outputs": [], - "source": [ - "def build_context_adaptively(user_profile, conversation_history, query):\n", - " \"\"\"\n", - " Build context adaptively based on conversation length\n", - " \"\"\"\n", - " # Count conversation tokens (rough estimate)\n", - " conv_tokens = sum(len(msg[\"content\"].split()) * 1.3 for msg in conversation_history)\n", - "\n", - " messages = []\n", - "\n", - " # Strategy selection based on conversation length\n", - " if len(conversation_history) == 0:\n", - " # New user - full system context\n", - " messages.append({\"role\": \"system\", \"content\": system_context})\n", - " if user_profile:\n", - " messages.append(\n", - " {\"role\": \"system\", \"content\": format_user_context(user_profile)}\n", - " )\n", - "\n", - " elif conv_tokens < 10000:\n", - " # Normal conversation - rich context\n", - " messages.append({\"role\": \"system\", \"content\": system_context})\n", - " messages.append(\n", - " {\"role\": \"system\", \"content\": format_user_context(user_profile)}\n", - " )\n", - " messages.extend(conversation_history)\n", - "\n", - " else:\n", - " # Long conversation - optimized context\n", - " # Use condensed system context\n", - " condensed_system = \"You are a Redis University course advisor. Help students choose appropriate courses.\"\n", - " messages.append({\"role\": \"system\", \"content\": condensed_system})\n", - "\n", - " # Include only key user facts\n", - " key_facts = f\"Student: {user_profile['name']}, {user_profile['background']}. Completed: {', '.join(user_profile['completed_courses'])}\"\n", - " messages.append({\"role\": \"system\", \"content\": key_facts})\n", - "\n", - " # Include only recent conversation history\n", - " messages.extend(conversation_history[-6:])\n", - "\n", - " # Always add retrieved context if relevant\n", - " # (In production, you'd determine relevance and retrieve accordingly)\n", - "\n", - " return messages" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## Best Practices for Context Engineering\n", - "\n", - "### 1. Start Simple, Add Complexity Gradually\n", - "\n", - "Don't try to build everything at once. Follow this progression:\n", - "\n", - "```python\n", - "# Phase 1: Basic agent with system context only\n", - "agent = BasicAgent(system_context)\n", - "\n", - "# Phase 2: Add user context\n", - "agent.set_user_profile(user_profile)\n", - "\n", - "# Phase 3: Add conversation history\n", - "agent.enable_conversation_memory()\n", - "\n", - "# Phase 4: Add retrieval\n", - "agent.add_retrieval_system(course_database)\n", - "```\n", - "\n", - "### 2. Measure Token Usage Continuously\n", - "\n", - "Always know your token consumption:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:46:15.607387Z", - "start_time": "2025-12-03T23:46:15.604330Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Total tokens: 332\n", - "Percentage of 128K limit: 0.3%\n", - "\n", - "Breakdown:\n", - " system: 261 tokens (78.8%)\n", - " user: 20 tokens (5.9%)\n", - " assistant: 51 tokens (15.3%)\n" - ] - } - ], - "source": [ - "def estimate_tokens(text):\n", - " \"\"\"Rough token estimation (for planning purposes)\"\"\"\n", - " return len(text.split()) * 1.3\n", - "\n", - "\n", - "def analyze_context_usage(messages):\n", - " \"\"\"Analyze token usage across context types\"\"\"\n", - " total_tokens = 0\n", - " breakdown = {}\n", - "\n", - " for msg in messages:\n", - " tokens = estimate_tokens(msg[\"content\"])\n", - " total_tokens += tokens\n", - "\n", - " # Categorize by role\n", - " role = msg[\"role\"]\n", - " breakdown[role] = breakdown.get(role, 0) + tokens\n", - "\n", - " print(f\"Total tokens: {total_tokens:.0f}\")\n", - " print(f\"Percentage of 128K limit: {total_tokens/128000*100:.1f}%\")\n", - " print(\"\\nBreakdown:\")\n", - " for role, tokens in breakdown.items():\n", - " print(f\" {role}: {tokens:.0f} tokens ({tokens/total_tokens*100:.1f}%)\")\n", - "\n", - "\n", - "# Analyze our context\n", - "analyze_context_usage(messages)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. Optimize for Relevance, Not Completeness\n", - "\n", - "**Wrong approach:** Include everything you have\n", - "```python\n", - "# Bad: Including all 50 courses = 30,000 tokens\n", - "context = \"\\n\".join([format_course(c) for c in all_courses])\n", - "```\n", - "\n", - "**Right approach:** Include only what's relevant\n", - "```python\n", - "# Good: Including only relevant courses = 2,000 tokens\n", - "relevant_courses = search_courses(query, user_profile, limit=3)\n", - "context = \"\\n\".join([format_course(c) for c in relevant_courses])\n", - "```\n", - "\n", - "### 4. Use Clear, Structured Formatting\n", - "\n", - "LLMs perform better with well-structured context:\n", - "\n", - "```python\n", - "# Good structure\n", - "context = \"\"\"\n", - "ROLE: Course advisor for Redis University\n", - "\n", - "STUDENT PROFILE:\n", - "- Name: Sarah Chen\n", - "- Background: Python developer\n", - "- Completed: RU101\n", - "\n", - "RELEVANT COURSES:\n", - "- RU201: Redis for Python (6-8 hours)\n", - " Prerequisites: RU101, Python experience\n", - "\n", - "TASK: Recommend the best next course for this student.\n", - "\"\"\"\n", - "```\n", - "\n", - "### 5. Test Different Context Combinations\n", - "\n", - "Context engineering is empirical - always test:" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-03T23:46:46.799071Z", - "start_time": "2025-12-03T23:46:19.257619Z" - }, - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Query: What course should I take next?\n", - "============================================================\n", - "\n", - "minimal strategy:\n", - "To provide a tailored recommendation, please share your background and any courses you've already completed. Do you have prior experience with programming languages like Python or Java? Additionally, let me know about your interests, particularly in machine learning or artificial intelligence!\n", - "\n", - "with_user strategy:\n", - "Hi Sarah! It's great to see your background as a Python developer and your interest in machine learning and vector search. Since you have already completed RU101, the next step for you is RU201: Redis for Python Developers. \n", - "\n", - "This course is designed for individuals like you who have Python experience and want to build Redis applications using the redis-py library. It will help you deepen your understanding of how to leverage Redis in your projects and is essential for your goal of constructing a Retrieval-Augmented Generation (RAG) system for your company's documentation.\n", - "\n", - "Once you've completed RU201, you’ll be well-equipped to take RU301: Vector Similarity Search with Redis, where you can further explore semantic search techniques. \n", - "\n", - "I encourage you to enroll in RU201\n", - "\n", - "with_retrieval strategy:\n", - "Based on your background as a Python developer and the fact that you've completed RU101, I highly recommend enrolling in **RU201: Redis for Python Developers**. \n", - "\n", - "This course will allow you to build Redis applications using Python, which directly aligns with your skill set and interests. Since you have 2 years of Python experience, you should be well-equipped to tackle the content of this course.\n", - "\n", - "Furthermore, completing RU201 will provide you with essential knowledge and skills that are prerequisites for RU301, the advanced course focused on implementing semantic search and building RAG (Retrieval-Augmented Generation) systems—exactly what you're interested in for your company's documentation.\n", - "\n", - "Taking RU201 will not only enhance your Redis skills but also help you progress towards your goal of developing\n", - "\n", - "Query: I want to learn about vector search\n", - "============================================================\n", - "\n", - "minimal strategy:\n", - "That's great to hear! Vector search is a fascinating area, especially with the rise of machine learning and AI applications. To get started with vector search using Redis, I recommend you take the following course:\n", - "\n", - "### RU301: Vector Similarity Search with Redis (Advanced, 8-10 hours)\n", - "- **Prerequisites**: You need to have completed either RU201 (Redis for Python Developers) or RU202 (Redis for Java Developers) first. You should also have an interest in machine learning or AI to fully benefit from this course.\n", - "\n", - "If you haven't yet taken RU201 or RU202, I suggest you start with RU101: Introduction to Redis Data Structures to build a strong foundation.\n", - "\n", - "Here’s a potential pathway:\n", - "1. **RU101:\n", - "\n", - "with_user strategy:\n", - "Hi Sarah!\n", - "\n", - "It's great to hear that you're interested in learning about vector search, especially since you have a specific goal of building a RAG (Retrieval-Augmented Generation) system for your company's documentation. Given your background as a Python developer and your completion of RU101, the next step for you would be to enroll in:\n", - "\n", - "**RU201: Redis for Python Developers (Intermediate, 6-8 hours)**\n", - "This course will help you build Redis applications using Python and the redis-py library. Since you already have Python experience and have completed RU101, you're well-prepared for this course.\n", - "\n", - "Once you complete RU201, you will be eligible for:\n", - "\n", - "**RU301: Vector Similarity Search with Redis (Advanced, 8-10\n", - "\n", - "with_retrieval strategy:\n", - "Given your interest in vector search and machine learning, I recommend you take RU201: Redis for Python Developers first. As a Python developer with two years of experience, you meet the prerequisites, having already completed RU101. \n", - "\n", - "This intermediate course will solidify your understanding of Redis in a Python context, covering essential topics and tools that will be foundational for your future learning. After mastering the content of RU201, you'll be well-equipped to pursue RU301: Vector Similarity Search with Redis, which focuses specifically on implementing semantic search and RAG systems.\n", - "\n", - "It's great to see your enthusiasm to build a RAG system for your company's documentation! Let me know if you have any questions or need assistance with enrolling in RU201!\n", - "\n", - "Query: How long will it take to become Redis-proficient?\n", - "============================================================\n", - "\n", - "minimal strategy:\n", - "Becoming proficient in Redis can vary based on your current knowledge, experience, and the depth of understanding you wish to achieve. Here’s a suggested learning path that spans different levels of expertise, using our course structure:\n", - "\n", - "1. **Beginner Level**: Start with **RU101: Introduction to Redis Data Structures** (4-6 hours). This course will lay your foundational knowledge about Redis, covering essential concepts like strings, hashes, lists, sets, and sorted sets.\n", - "\n", - "2. **Intermediate Level**: If you have programming experience, you can choose between:\n", - " - **RU201: Redis for Python Developers** (if you're familiar with Python), or \n", - " - **RU202: Redis for Java Developers** (if you have Java experience\n", - "\n", - "with_user strategy:\n", - "Becoming Redis-proficient will depend on your dedication and the courses you choose to take based on your current skills and interests. Given your background as a Python developer and your completion of RU101, you are on a great path. \n", - "\n", - "Here's a breakdown of the courses you might consider:\n", - "\n", - "1. **RU101: Introduction to Redis Data Structures** (Completed, 4-6 hours)\n", - "2. **RU201: Redis for Python Developers** (Intermediate, 6-8 hours)\n", - " - Since you have experience with Python and you've completed RU101, this course is the next step for you. You will learn to build Redis applications using Python, which aligns perfectly with your background.\n", - "3. **RU301: Vector Similarity Search with\n", - "\n", - "with_retrieval strategy:\n", - "Becoming proficient in Redis can vary based on several factors, including your prior knowledge, the time you can dedicate to learning, and the complexity of projects you wish to undertake. Given your background as a Python developer and your completed course (RU101), you're already on the right path.\n", - "\n", - "Here’s a suggested timeline for becoming proficient in Redis, particularly with a focus on your interest in machine learning and building a RAG system:\n", - "\n", - "1. **Complete RU201 (Redis for Python Developers)**: This course will take you about 6-8 hours. In this course, you'll learn how to build production Redis applications using Python and the redis-py library, which is essential for your goals.\n", - "\n", - "2. **Practice and Build Projects**: After completing RU\n" - ] - } - ], - "source": [ - "def test_context_strategies(user_profile, test_queries):\n", - " \"\"\"\n", - " Test different context strategies to find the best approach\n", - " \"\"\"\n", - " strategies = [\n", - " (\"minimal\", [{\"role\": \"system\", \"content\": system_context}]),\n", - " (\n", - " \"with_user\",\n", - " [\n", - " {\"role\": \"system\", \"content\": system_context},\n", - " {\"role\": \"system\", \"content\": format_user_context(user_profile)},\n", - " ],\n", - " ),\n", - " (\n", - " \"with_retrieval\",\n", - " [\n", - " {\"role\": \"system\", \"content\": system_context},\n", - " {\"role\": \"system\", \"content\": format_user_context(user_profile)},\n", - " {\"role\": \"system\", \"content\": retrieved_context},\n", - " ],\n", - " ),\n", - " ]\n", - "\n", - " for query in test_queries:\n", - " print(f\"\\nQuery: {query}\")\n", - " print(\"=\" * 60)\n", - "\n", - " for strategy_name, context_messages in strategies:\n", - " messages = context_messages + [{\"role\": \"user\", \"content\": query}]\n", - "\n", - " response = client.chat.completions.create(\n", - " model=\"gpt-4o-mini\", messages=messages, max_tokens=150\n", - " )\n", - "\n", - " print(f\"\\n{strategy_name} strategy:\")\n", - " print(response.choices[0].message.content)\n", - "\n", - "\n", - "# Example usage (uncomment to run)\n", - "test_queries = [\n", - " \"What course should I take next?\",\n", - " \"I want to learn about vector search\",\n", - " \"How long will it take to become Redis-proficient?\",\n", - "]\n", - "test_context_strategies(sarah_profile, test_queries)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Example expected output:**\n", - "```\n", - "Query: What course should I take next?\n", - "============================================================\n", - "\n", - "minimal strategy:\n", - "To provide you with the best recommendation, I would need to know a bit more about your current background. Specifically:\n", - "\n", - "1. Have you completed any of the available courses?\n", - "2. What level of programming experience do you have (Python, Java, etc.)?\n", - "3. Are you interested in machine learning or artificial intelligence?\n", - "4. What are your goals or what do you hope to achieve by taking the next course?\n", - "\n", - "Once I have this information, I can suggest the most suitable course for you!\n", - "\n", - "with_user strategy:\n", - "Hi Sarah!\n", - "\n", - "Given your background as a Python developer and the fact that you've already completed RU101, you're well-prepared to dive into the next level of Redis courses. Since you have an interest in machine learning and data science, as well as a goal to build a RAG (Retrieval-Augmented Generation) system for your company's documentation, I highly recommend you take **RU201: Redis for Python Developers**.\n", - "\n", - "This course will build on your existing knowledge from RU101 and will teach you how to effectively use Redis to create applications specifically with Python. This is perfect for your goals, as it will give you the necessary skills to leverage Redis in developing your RAG system.\n", - "\n", - "Once you complete RU201, you can then progress to **RU301\n", - "\n", - "with_retrieval strategy:\n", - "Based on your background as a Python developer with two years of experience, along with your completion of RU101, I highly recommend that you take **RU201: Redis for Python Developers**. \n", - "\n", - "This course is tailored for individuals with a grounding in Python who want to leverage Redis to build applications. Since you're interested in machine learning and data science, mastering Redis with Python will significantly enhance your ability to develop applications like a RAG system for your company's documentation.\n", - "\n", - "Taking RU201 will equip you with key concepts and the redis-py library, which are essential for efficiently working with Redis in your projects. With your evening and weekend availability, you should be able to complete the course within the estimated 6-8 hours.\n", - "\n", - "Once you've completed RU201, you'll\n", - "\n", - "Query: I want to learn about vector search\n", - "============================================================\n", - "\n", - "minimal strategy:\n", - "That's great! Vector search is an exciting and increasingly important topic, especially in the fields of machine learning and artificial intelligence. To get started with vector similarity search using Redis, you'll want to take RU301: Vector Similarity Search with Redis.\n", - "\n", - "Here are the prerequisites and reasoning for this recommendation:\n", - "\n", - "1. **Prerequisites**: You need to have completed either RU201 (Redis for Python Developers) or RU202 (Redis for Java Developers) before taking RU301. Both of these intermediate courses cover building Redis applications and will give you a strong foundation.\n", - "\n", - "2. **Interest in ML/AI**: Since you're interested in vector search, it's essential to have a background or understanding of machine learning or AI concepts, which RU301 will help you with by\n", - "\n", - "with_user strategy:\n", - "Hi Sarah! It's great to see your interest in vector search, especially since you're looking to build a RAG (Retrieve and Generate) system for your company's documentation.\n", - "\n", - "Given your background as a Python developer and that you've completed RU101, I recommend you take **RU201: Redis for Python Developers** next. This course will help you build Redis applications specifically with Python and teach you how to leverage Redis for your data storage needs. It's an important stepping stone before diving into advanced topics.\n", - "\n", - "Once you've completed RU201, you can then move on to **RU301: Vector Similarity Search with Redis**. This advanced course will delve into implementing semantic search and other techniques that are essential for your RAG system project.\n", - "\n", - "These courses align perfectly with your interests\n", - "\n", - "with_retrieval strategy:\n", - "Hi Sarah! It's fantastic to see your interest in learning about vector search, especially since you're aiming to build a RAG (Retrieval-Augmented Generation) system for your company's documentation. Given your background as a Python developer and your completion of RU101, the next step for you would be to enroll in **RU201: Redis for Python Developers**.\n", - "\n", - "### Here’s why RU201 is an excellent fit for you:\n", - "\n", - "1. **Prerequisites Met**: You’ve already completed RU101, and as a Python developer, you have the requisite experience to succeed in this course.\n", - "2. **Focused on Python**: This course specifically teaches you how to build Redis applications with Python, which aligns perfectly with your background.\n", - "3. **Prepare for Advanced\n", - "\n", - "Query: How long will it take to become Redis-proficient?\n", - "============================================================\n", - "\n", - "minimal strategy:\n", - "Becoming proficient in Redis can vary greatly depending on your current background, experience, and how much time you can dedicate to learning. Here's a general guideline based on the courses available:\n", - "\n", - "1. **RU101: Introduction to Redis Data Structures (Beginner, 4-6 hours)** - This foundational course will introduce you to basic Redis concepts and data structures. Completing this course is essential for starting your Redis journey.\n", - "\n", - "2. **RU201: Redis for Python Developers (Intermediate, 6-8 hours)** - If you have experience with Python, this course will build on your knowledge from RU101 and teach you how to integrate Redis into Python applications. This is a great next step if you’re looking to apply Redis practically.\n", - "\n", - "3. **RU\n", - "\n", - "with_user strategy:\n", - "The time it takes to become proficient in Redis can vary depending on your prior knowledge, the complexity of the projects you want to undertake, and the time you can dedicate to learning. Given your background as a Python developer with two years of experience, you've already completed RU101, which gives you a solid foundation in Redis fundamentals.\n", - "\n", - "Here’s a suggested pathway to proficiency based on your profile:\n", - "\n", - "1. **RU101: Introduction to Redis Data Structures** - You’ve completed this course, which typically takes 4-6 hours.\n", - "\n", - "2. **RU201: Redis for Python Developers** - Since you have Python experience and have completed RU101, this intermediate course will further your skills in building applications with Redis. This course typically takes 6-8 hours\n", - "\n", - "with_retrieval strategy:\n", - "Becoming proficient in Redis can vary depending on your learning pace and dedication, but with your background and interests, here's a potential pathway based on the courses available:\n", - "\n", - "1. **RU101: Introduction to Redis Data Structures (Completed)** - You've already completed this foundational course, which covers the basic data structures in Redis.\n", - "\n", - "2. **RU201: Redis for Python Developers** - This intermediate course will take about 6-8 hours. Since you have 2 years of Python experience and have completed RU101, you're well-prepared to dive into this course. This will enhance your skills in building Redis applications specifically using Python.\n", - "\n", - "3. **RU301: Vector Similarity Search with Redis** - This advanced course (8-10 hours) requires completion\n", - "```\n", - "\n", - "### Analyzing Context Strategy Results\n", - "\n", - "Let's analyze what happened when we tested the same queries with different amounts of context.\n", - "\n", - "#### What We Observed\n", - "\n", - "**Query 1: \"What course should I take next?\"**\n", - "\n", - "- **Minimal (system only):** Asked clarifying questions - \"What's your background? What are your goals?\"\n", - "- **With user context:** Immediately recommended RU201 based on Sarah's Python background and completed RU101\n", - "- **With retrieval:** Same recommendation PLUS specific course details (duration, topics) for better decision-making\n", - "\n", - "**Query 2: \"I want to learn about vector search\"**\n", - "\n", - "- **Minimal:** Suggested RU301 but couldn't verify if prerequisites were met\n", - "- **With user context:** Built a learning path (RU201 → RU301) based on what Sarah already completed\n", - "- **With retrieval:** Same path with detailed justification for each step\n", - "\n", - "**Query 3: \"How long will it take to become Redis-proficient?\"**\n", - "\n", - "- **Minimal:** Listed all courses but repeated RU101 (which Sarah already finished)\n", - "- **With user context:** Calculated time starting from RU201, acknowledging completed work\n", - "- **With retrieval:** Most accurate timeline with specific hours per course\n", - "\n", - "---\n", - "\n", - "### Key Insights\n", - "\n", - "**1. System Context Alone = Generic Bot**\n", - "- Must ask follow-up questions\n", - "- Can't personalize\n", - "- Wastes user time with back-and-forth\n", - "\n", - "**2. Adding User Context = Personal Assistant**\n", - "- Knows who you are\n", - "- Skips unnecessary questions\n", - "- Tailors recommendations instantly\n", - "\n", - "**3. Adding Retrieved Context = Expert Advisor**\n", - "- Provides specific details (hours, topics, prerequisites)\n", - "- Makes responses actionable\n", - "- Gives users everything needed to decide\n", - "\n", - "---\n", - "\n", - "### The Pattern\n", - "```\n", - "More Context = Less Back-and-Forth = Better Experience\n", - "\n", - "Minimal: User asks → AI asks clarifying questions → User answers → AI responds\n", - " (3-4 interactions to get an answer)\n", - "\n", - "Rich: User asks → AI responds with personalized, detailed answer\n", - " (1 interaction - done)\n", - "```\n", - "\n", - "---\n", - "\n", - "### When to Use Each Strategy\n", - "\n", - "| Strategy | Best For | Example |\n", - "|----------|----------|---------|\n", - "| **Minimal** | New users, no history available | First-time visitor to your site |\n", - "| **With User** | Returning users, simple queries | \"What should I do next?\" |\n", - "| **With Retrieval** | Complex decisions, detailed planning | \"Plan my learning path for the year\" |\n", - "\n", - "---\n", - "\n", - "### What This Means for Production\n", - "\n", - "**The Right Context Strategy Depends On:**\n", - "\n", - "1. **Do you have user history?**\n", - " - Yes → Include user context\n", - " - No → Use minimal, ask questions\n", - "\n", - "2. **Is the query complex?**\n", - " - Yes → Retrieve specific details\n", - " - No → User context might be enough\n", - "\n", - "3. **Are you near token limits?**\n", - " - Yes → Switch to minimal or summarize\n", - " - No → Use rich context\n", - "\n", - "**Simple Rule:** Start with rich context (all four types). Only reduce when you hit token limits or lack data.\n", - "\n", - "---\n", - "\n", - "### Action Items\n", - "\n", - "Based on this test, you should:\n", - "\n", - "1. **Always include user context** when available (massive quality improvement, low token cost)\n", - "2. **Retrieve context dynamically** based on what the query asks about (don't retrieve RU201 details for every question)\n", - "3. **Monitor token usage** - several responses were cut off at 150 tokens\n", - "4. **Test with your own use case** - Run this experiment with your domain and queries\n", - "\n", - "**Bottom Line:** More relevant context = better responses. The challenge is determining what's \"relevant\" and managing token budgets." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## 📚 Course Summary: What You've Learned\n", - "\n", - "Congratulations! You've completed Chapter 1: Foundations of Context Engineering. Let's recap your journey.\n", - "\n", - "### From Notebook 01: Why Context Engineering Matters\n", - "\n", - "You discovered the fundamental problem that context engineering solves:\n", - "\n", - "**The Core Problem:**\n", - "- AI agents without context are like doctors without medical records - they can't remember, personalize, or maintain coherent interactions\n", - "- This leads to frustrated users, operational inefficiency, and limited AI capabilities\n", - "\n", - "**The Impact:**\n", - "- You saw the dramatic difference between context-less and context-aware AI through the university advisor example\n", - "- Without context: repetitive, generic, frustrating interactions\n", - "- With context: personalized, coherent, valuable assistance\n", - "\n", - "**The Four Context Types:**\n", - "You learned the foundational framework:\n", - "1. **System Context** - \"What am I?\" (Role, rules, domain knowledge)\n", - "2. **User Context** - \"Who are you?\" (Profile, preferences, history)\n", - "3. **Conversation Context** - \"What have we discussed?\" (Dialogue flow)\n", - "4. **Retrieved Context** - \"What information is relevant?\" (On-demand data)\n", - "\n", - "**The Fundamental Constraint:**\n", - "- Every AI model has a context window limit (e.g., 128K tokens)\n", - "- Every token spent on one type of context is unavailable for another\n", - "- Context engineering is optimization within constraints\n", - "\n", - "**Real-World Importance:**\n", - "- Customer support, healthcare, sales, research - all require proper context management\n", - "- Poor context management has measurable business impact: 40-60% abandonment rates, 3-5x more interactions needed, high escalation rates\n", - "\n", - "### From Notebook 02: How to Implement Context Engineering\n", - "\n", - "You mastered the practical implementation:\n", - "\n", - "**Hands-On Skills Acquired:**\n", - "\n", - "1. **Building System Context**\n", - " - How to define AI role and identity\n", - " - Structuring domain knowledge effectively\n", - " - Writing clear behavioral guidelines\n", - " - Understanding static vs. dynamic information\n", - "\n", - "2. **Creating User Context**\n", - " - Storing user profiles as structured data\n", - " - Formatting user information for LLMs\n", - " - Personalizing responses based on user attributes\n", - " - Seeing how different users get different context\n", - "\n", - "3. **Managing Conversation Context**\n", - " - Maintaining dialogue history across turns\n", - " - Enabling natural reference resolution (\"that course\")\n", - " - Building coherent multi-turn conversations\n", - " - Strategies for handling long conversations\n", - "\n", - "4. **Retrieving Dynamic Context**\n", - " - Fetching relevant information on-demand\n", - " - Query-specific data retrieval\n", - " - Optimizing for relevance vs. completeness\n", - " - Simulating database and search operations\n", - "\n", - "**Integration Mastery:**\n", - "- You learned how to combine all four context types into a single LLM call\n", - "- You saw the complete message array structure that makes intelligent responses possible\n", - "- You understood how each context type contributes to the final response quality\n", - "\n", - "**Strategic Thinking:**\n", - "You explored three context management strategies:\n", - "- **Minimal Context** - For new users with no history\n", - "- **Rich Context** - For returning users with established profiles\n", - "- **Optimized Context** - For long conversations near token limits\n", - "\n", - "**Best Practices:**\n", - "1. Start simple, add complexity gradually\n", - "2. Measure token usage continuously\n", - "3. Optimize for relevance, not completeness\n", - "4. Use clear, structured formatting\n", - "5. Test and iterate based on results\n", - "\n", - "### What You Can Do Now\n", - "\n", - "After completing these two notebooks, you have the foundational skills to:\n", - "\n", - " - **Understand** why context engineering is critical for production AI systems \n", - " - **Identify** which context type to use for different information \n", - " - **Build** context-aware AI agents from scratch \n", - " - **Format** context appropriately for LLM consumption \n", - " - **Combine** multiple context sources into coherent requests \n", - " - **Optimize** token usage within context window constraints \n", - " - **Adapt** context strategies based on user type and conversation length \n", - " - **Implement** the Redis University course advisor pattern for your own domain \n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 🤔 What's Next?\n", - "\n", - "In the next section, you'll dive deeper into advanced techniques:\n", - "\n", - "**Section 2: Retrieved Context Engineering**\n", - "- **Notebook 1:** RAG Fundamentals and Implementation\n", - " - Vector embeddings and semantic search with Redis\n", - " - Building production-ready RAG pipelines\n", - " - Why context quality matters\n", - "- **Notebook 2:** Engineering Context for Production\n", - " - Data engineering workflows for context\n", - " - Chunking as a design choice (when to chunk vs. whole-record embedding)\n", - " - Production pipeline architectures\n", - " - Quality optimization techniques\n", - "- Building production RAG systems with LangChain and LangGraph\n", - "- Semantic retrieval strategies\n", - "- Hybrid search approaches\n", - "- Optimizing retrieval performance\n", - "\n", - "**Section 3: Memory Systems for Context Engineering**\n", - "- Long-term memory systems with Redis Agent Memory Server\n", - "- Working memory vs. long-term memory patterns\n", - "- Memory summarization and compression\n", - "- Multi-agent memory coordination\n", - "\n", - "**Section 4: Production Optimization**\n", - "- Context compression techniques\n", - "- Caching strategies\n", - "- Performance monitoring\n", - "- Cost optimization\n", - "\n", - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "### **Context Engineering Fundamentals**\n", - "- [Prompt Engineering Guide](https://www.promptingguide.ai/) - Comprehensive guide to prompt engineering\n", - "- [OpenAI Prompt Engineering Guide](https://platform.openai.com/docs/guides/prompt-engineering) - Best practices\n", - "- [Anthropic's Guide to Building Effective Agents](https://www.anthropic.com/research/building-effective-agents) - Agent design patterns\n", - "\n", - "### **LLM Context Management**\n", - "- [LangChain Documentation](https://python.langchain.com/docs/get_started/introduction) - Framework for context-aware applications\n", - "- [Context Window Management](https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them) - Understanding token limits\n", - "- [OpenAI API Reference](https://platform.openai.com/docs/api-reference) - Complete API documentation\n", - "\n", - "### **Academic Papers and Technical Reports**\n", - "- [In-Context Learning Survey](https://arxiv.org/abs/2301.00234) - Research on how LLMs use context\n", - "- [Retrieval-Augmented Generation](https://arxiv.org/abs/2005.11401) - Foundational RAG paper\n", - "- [Lost in the Middle](https://arxiv.org/abs/2307.03172) - How LLMs use long contexts\n", - "- [Context Rot](https://github.com/chroma-core/context-rot?tab=readme-ov-file) - How Increasing Input Tokens Impacts LLM Performance\n", - "\n", - "### **Redis Resources**\n", - "- [Redis Documentation](https://redis.io/docs/) - Official Redis documentation\n", - "- [Redis University](https://university.redis.com/) - Free Redis courses\n", - "- [Redis Python Client](https://redis-py.readthedocs.io/) - redis-py documentation\n", - "\n", - "---" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.7" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/notebooks/section-2-retrieved-context-engineering/01_rag_fundamentals_and_implementation.ipynb b/notebooks/section-2-retrieved-context-engineering/01_rag_fundamentals_and_implementation.ipynb deleted file mode 100644 index eb8757d..0000000 --- a/notebooks/section-2-retrieved-context-engineering/01_rag_fundamentals_and_implementation.ipynb +++ /dev/null @@ -1,2727 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "f38f7a74133d584d", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# Engineering Retrieved Context with RAG\n", - "\n", - "## From Context Engineering to Retrieval-Augmented Generation\n", - "\n", - "In Section 1, you learned about the four core context types:\n", - "1. **System Context** - The AI's role and domain knowledge\n", - "2. **User Context** - Personal profiles and preferences \n", - "3. **Conversation Context** - Dialogue history and flow\n", - "4. **Retrieved Context** - Dynamic information from external sources\n", - "\n", - "This notebook focuses on **Retrieved Context** - the most powerful and complex context type. You'll learn how to build a production-ready RAG (Retrieval-Augmented Generation) system that dynamically fetches relevant information to enhance AI responses.\n", - "\n", - "## What You'll Learn\n", - "\n", - "**RAG Fundamentals:**\n", - "- What RAG is and why it's essential for context engineering\n", - "- How vector embeddings enable semantic search\n", - "- Building a complete RAG pipeline with LangChain and Redis\n", - "\n", - "**Practical Implementation:**\n", - "- Generate and ingest course data using existing utilities\n", - "- Set up Redis vector store for semantic search\n", - "- Implement retrieval and generation workflows\n", - "- Combine retrieved context with user and system context\n", - "\n", - "**Foundation for Advanced Topics:**\n", - "- This RAG system becomes the base for Section 3 (Memory Systems for Context Engineering)\n", - "- You'll add LangGraph state management and tools in later sections\n", - "- Focus here is purely on retrieval → context assembly → generation\n", - "\n", - "**Time to complete:** 45-50 minutes\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "c32f737633a8079d", - "metadata": {}, - "source": [ - "## Why RAG Matters for Context Engineering\n", - "\n", - "### The Challenge: Static vs. Dynamic Knowledge\n", - "\n", - "In Section 1, we used **hardcoded** course information in the system context:\n", - "\n", - "```python\n", - "system_context = \"\"\"You are a Redis University course advisor.\n", - "\n", - "Available Courses:\n", - "- RU101: Introduction to Redis (Beginner, 4-6 hours)\n", - "- RU201: Redis for Python (Intermediate, 6-8 hours)\n", - "...\n", - "\"\"\"\n", - "```\n", - "\n", - "**Problems with this approach:**\n", - "- ❌ **Doesn't scale** - Can't hardcode thousands of courses\n", - "- ❌ **Wastes tokens** - Includes irrelevant courses in every request\n", - "- ❌ **Hard to update** - Requires code changes to add/modify courses\n", - "- ❌ **No personalization** - Same courses shown to everyone\n", - "\n", - "### The Solution: Retrieval-Augmented Generation (RAG)\n", - "\n", - "RAG solves these problems by **dynamically retrieving** only the most relevant information:\n", - "\n", - "```\n", - "User Query: \"I want to learn about vector search\"\n", - " ↓\n", - "Semantic Search: Find courses matching \"vector search\"\n", - " ↓\n", - "Retrieved Context: RU301 - Vector Similarity Search with Redis\n", - " ↓\n", - "LLM Generation: Personalized recommendation using retrieved context\n", - "```\n", - "\n", - "**Benefits:**\n", - "- ✅ **Scales beyond tokens** - Store millions of documents\n", - "- ✅ **Token efficient** - Only retrieve what's relevant\n", - "- ✅ **Easy to update** - Add/modify data without code changes\n", - "- ✅ **Personalized** - Different results for different queries\n", - "\n", - "### RAG as \"Retrieved Context\" from Section 1\n", - "\n", - "Remember the four context types? RAG is how we implement **Retrieved Context** in production:\n", - "\n", - "| Context Type | Storage | Retrieval Method | Example |\n", - "|--------------|---------|------------------|---------|\n", - "| System Context | Hardcoded | Always included | AI role, instructions |\n", - "| User Context | Database | User ID lookup | Student profile |\n", - "| Conversation Context | Session store | Session ID lookup | Chat history |\n", - "| **Retrieved Context** | **Vector DB** | **Search** | **Relevant courses** |\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "6199337174405d39", - "metadata": {}, - "source": [ - "## Setup and Environment\n", - "\n", - "Let's prepare our environment with the necessary dependencies." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "7b8643051fbc09a2", - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-05T17:23:06.945701Z", - "start_time": "2025-12-05T17:23:06.937481Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment variables loaded\n", - " REDIS_URL: redis://localhost:6379\n", - " OPENAI_API_KEY: ✓ Set\n" - ] - } - ], - "source": [ - "import json\n", - "import os\n", - "import sys\n", - "\n", - "import tiktoken\n", - "from dotenv import load_dotenv\n", - "\n", - "# Load environment variables\n", - "load_dotenv()\n", - "\n", - "# Verify required environment variables\n", - "required_vars = [\"OPENAI_API_KEY\"]\n", - "missing_vars = [var for var in required_vars if not os.getenv(var)]\n", - "\n", - "if missing_vars:\n", - " print(\n", - " f\"\"\"\n", - "⚠️ Missing required environment variables: {', '.join(missing_vars)}\n", - "\n", - "Please create a .env file with:\n", - "OPENAI_API_KEY=your_openai_api_key\n", - "REDIS_URL=redis://localhost:6379\n", - "\n", - "For Redis setup:\n", - "- Local: docker run -d -p 6379:6379 redis/redis-stack-server:latest\n", - "- Cloud: https://redis.com/try-free/\n", - "\"\"\"\n", - " )\n", - " sys.exit(1)\n", - "REDIS_URL = \"redis://localhost:6379\"\n", - "print(\"✅ Environment variables loaded\")\n", - "print(f\" REDIS_URL: {REDIS_URL}\")\n", - "print(f\" OPENAI_API_KEY: {'✓ Set' if os.getenv('OPENAI_API_KEY') else '✗ Not set'}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c09c113f31cc9237", - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-05T17:23:06.964428Z", - "start_time": "2025-12-05T17:23:06.962690Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Utility functions loaded\n" - ] - } - ], - "source": [ - "# Utility: Token counter\n", - "def count_tokens(text: str, model: str = \"gpt-4o\") -> int:\n", - " \"\"\"Count tokens in text using tiktoken.\"\"\"\n", - " encoding = tiktoken.encoding_for_model(model)\n", - " return len(encoding.encode(text))\n", - "\n", - "print(\"✅ Utility functions loaded\")" - ] - }, - { - "cell_type": "markdown", - "id": "a604197ba5bed3c", - "metadata": {}, - "source": [ - "### Install Dependencies\n", - "\n", - "We'll use LangChain for RAG orchestration and Redis for vector storage." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "aa253a5a5fea56a", - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-05T17:23:07.891527Z", - "start_time": "2025-12-05T17:23:07.889752Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Dependencies ready\n" - ] - } - ], - "source": [ - "# Install required packages (uncomment if needed)\n", - "# %pip install -q langchain langchain-openai langchain-redis redisvl redis python-dotenv\n", - "\n", - "print(\"✅ Dependencies ready\")" - ] - }, - { - "cell_type": "markdown", - "id": "f78bfe047e37e3fe", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 📊 Step 1: Understanding Vector Embeddings\n", - "\n", - "Before building our RAG system, let's understand the core concept: **vector embeddings**.\n", - "\n", - "### What Are Embeddings?\n", - "\n", - "Embeddings convert text into numerical vectors that capture semantic meaning:\n", - "\n", - "```\n", - "Text: \"Introduction to Redis\"\n", - " ↓ (embedding model)\n", - "Vector: [0.23, -0.45, 0.67, ..., 0.12] # 1536 dimensions for OpenAI\n", - "```\n", - "\n", - "**Key insight:** Similar texts have similar vectors (measured by cosine similarity).\n", - "\n", - "### Why Embeddings Enable Semantic Search\n", - "\n", - "Traditional keyword search:\n", - "- Query: \"machine learning courses\" \n", - "- Matches: Only documents containing exact words \"machine learning\"\n", - "- Misses: \"AI courses\", \"neural network classes\", \"deep learning programs\"\n", - "\n", - "Semantic search with embeddings:\n", - "- Query: \"machine learning courses\"\n", - "- Matches: All semantically similar content (AI, neural networks, deep learning, etc.)\n", - "- Works across synonyms, related concepts, and different phrasings\n", - "\n", - "Let's see this in action:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "8987e7214633221", - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-05T17:23:11.290671Z", - "start_time": "2025-12-05T17:23:08.700358Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Generated embeddings for 3 texts\n", - " Vector dimensions: 1536\n", - " First vector preview: [-0.030, -0.013, 0.001, ...]\n" - ] - } - ], - "source": [ - "from langchain_openai import OpenAIEmbeddings\n", - "\n", - "# Initialize embedding model\n", - "embeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\n", - "\n", - "# Generate embeddings for similar and different texts\n", - "texts = [\n", - " \"Introduction to machine learning and neural networks\",\n", - " \"Learn about AI and deep learning fundamentals\",\n", - " \"Database administration and SQL queries\",\n", - "]\n", - "\n", - "# Get embeddings (this calls OpenAI API)\n", - "vectors = embeddings.embed_documents(texts)\n", - "\n", - "print(f\"✅ Generated embeddings for {len(texts)} texts\")\n", - "print(f\" Vector dimensions: {len(vectors[0])}\")\n", - "print(\n", - " f\" First vector preview: [{vectors[0][0]:.3f}, {vectors[0][1]:.3f}, {vectors[0][2]:.3f}, ...]\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "7963a05e261c914c", - "metadata": {}, - "source": [ - "### Measuring Semantic Similarity\n", - "\n", - "Let's calculate cosine similarity to see which texts are semantically related:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "830004ddb2bd656b", - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-04T20:32:41.365327Z", - "start_time": "2025-12-04T20:32:41.362612Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Semantic Similarity Scores (0=unrelated, 1=identical):\n", - " ML vs AI: 0.623 ← High similarity (related topics)\n", - " ML vs Database: 0.171 ← Low similarity (different topics)\n", - " AI vs Database: 0.177 ← Low similarity (different topics)\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "\n", - "\n", - "def cosine_similarity(vec1, vec2):\n", - " \"\"\"Calculate cosine similarity between two vectors.\"\"\"\n", - " return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))\n", - "\n", - "\n", - "# Compare similarities\n", - "sim_1_2 = cosine_similarity(vectors[0], vectors[1]) # ML vs AI (related)\n", - "sim_1_3 = cosine_similarity(vectors[0], vectors[2]) # ML vs Database (unrelated)\n", - "sim_2_3 = cosine_similarity(vectors[1], vectors[2]) # AI vs Database (unrelated)\n", - "\n", - "print(\"Semantic Similarity Scores (0=unrelated, 1=identical):\")\n", - "print(f\" ML vs AI: {sim_1_2:.3f} ← High similarity (related topics)\")\n", - "print(f\" ML vs Database: {sim_1_3:.3f} ← Low similarity (different topics)\")\n", - "print(f\" AI vs Database: {sim_2_3:.3f} ← Low similarity (different topics)\")" - ] - }, - { - "cell_type": "markdown", - "id": "be16970c9b44fcec", - "metadata": {}, - "source": [ - "**💡 Key Takeaway:** Embeddings capture semantic meaning, allowing us to find relevant information even when exact keywords don't match.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "d63e217969956023", - "metadata": {}, - "source": [ - "## 📚 Step 2: Generate Course Data\n", - "\n", - "Now let's create realistic course data for our RAG system. We'll use the existing utilities from the reference agent.\n", - "\n", - "### Understanding the Course Generation Script\n", - "\n", - "The `generate_courses.py` script creates realistic course data with:\n", - "- Multiple majors (CS, Data Science, Math, Business, Psychology)\n", - "- Course templates with descriptions, prerequisites, schedules\n", - "- Realistic metadata (instructors, enrollment, difficulty levels)\n", - "\n", - "Let's generate our course catalog:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "e95cd4b02364b072", - "metadata": { - "ExecuteTime": { - "end_time": "2025-12-04T20:34:38.805942Z", - "start_time": "2025-12-04T20:34:38.563262Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📚 Generating course catalog...\n", - "\n", - "✅ Generated 5 majors:\n", - " - Computer Science (CS)\n", - " - Data Science (DS)\n", - " - Mathematics (MATH)\n", - " - Business Administration (BUS)\n", - " - Psychology (PSY)\n", - "\n", - "✅ Generated 50 courses\n", - "\n", - "Sample Course:\n", - " Code: CS001\n", - " Title: Introduction to Programming\n", - " Department: Computer Science\n", - " Difficulty: beginner\n", - " Credits: 3\n", - " Description: Fundamental programming concepts using Python. Variables, control structures, functions, and basic d...\n", - "\n" - ] - } - ], - "source": [ - "# IGNORE: Add reference-agent to Python path because I installed reference-agent with pip\n", - "# IGNORE: sys.path.insert(0, os.path.join(os.getcwd(), 'python-recipes/context-engineering/reference-agent'))\n", - "\n", - "# Initialize generator with a seed for reproducibility\n", - "import random\n", - "\n", - "from redis_context_course.scripts.generate_courses import CourseGenerator\n", - "\n", - "random.seed(42)\n", - "\n", - "# Create generator\n", - "generator = CourseGenerator()\n", - "\n", - "print(\"📚 Generating course catalog...\")\n", - "print()\n", - "\n", - "# Generate majors\n", - "majors = generator.generate_majors()\n", - "print(f\"✅ Generated {len(majors)} majors:\")\n", - "for major in majors:\n", - " print(f\" - {major.name} ({major.code})\")\n", - "\n", - "print()\n", - "\n", - "# Generate courses (10 per major)\n", - "courses = generator.generate_courses(courses_per_major=10)\n", - "print(f\"✅ Generated {len(courses)} courses\")\n", - "\n", - "# Show a sample course\n", - "sample_course = courses[0]\n", - "print(\n", - " f\"\"\"\n", - "Sample Course:\n", - " Code: {sample_course.course_code}\n", - " Title: {sample_course.title}\n", - " Department: {sample_course.department}\n", - " Difficulty: {sample_course.difficulty_level.value}\n", - " Credits: {sample_course.credits}\n", - " Description: {sample_course.description[:100]}...\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "35eb083f18863411", - "metadata": {}, - "source": [ - "### Save Course Catalog to JSON\n", - "\n", - "Let's save this data so we can ingest it into Redis:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "c15d309043a79486", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Generated 5 majors and 50 courses\n", - "Data saved to course_catalog_section2.json\n", - "✅ Course catalog saved to course_catalog_section2.json\n", - " Ready for ingestion into Redis vector store\n" - ] - } - ], - "source": [ - "catalog_file = \"course_catalog_section2.json\"\n", - "generator.save_to_json(catalog_file)\n", - "\n", - "print(f\"✅ Course catalog saved to {catalog_file}\")\n", - "print(f\" Ready for ingestion into Redis vector store\")" - ] - }, - { - "cell_type": "markdown", - "id": "429acdaadabaa392", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🔧 Step 3: Set Up Redis Vector Store\n", - "\n", - "Now we'll configure Redis to store our course embeddings and enable semantic search.\n", - "\n", - "### Understanding Redis Vector Search\n", - "\n", - "Redis Stack provides vector similarity search capabilities:\n", - "- **Storage:** Courses stored as Redis hashes with vector fields\n", - "- **Indexing:** Vector index for fast similarity search (HNSW algorithm)\n", - "- **Search:** Find top-k most similar courses to a query vector using cosine similarity\n", - "\n", - "### Using the Reference Agent Utilities\n", - "\n", - "Instead of configuring Redis from scratch, we'll use the **production-ready utilities** from the reference agent. These utilities are already configured and tested, allowing you to focus on context engineering concepts rather than Redis configuration details." - ] - }, - { - "cell_type": "markdown", - "id": "64b05a2a034da925", - "metadata": {}, - "source": [ - "### Import Redis Configuration\n", - "\n", - "Let's import the pre-configured Redis setup:\n", - "\n", - "What we're importing:\n", - " - redis_config: A global singleton that manages all Redis connections\n", - "\n", - "What it provides (lazy-initialized properties):\n", - " - redis_config.redis_client: Redis connection for data storage\n", - " - redis_config.embeddings: OpenAI embeddings (text-embedding-3-small)\n", - " - redis_config.vector_index: RedisVL SearchIndex with pre-configured schema\n", - " - redis_config.checkpointer: RedisSaver for LangGraph (used in Section 3)\n", - "\n", - "Why use this:\n", - " - Production-ready configuration (same as reference agent)\n", - " - Proper schema with all course metadata fields\n", - " - Vector field: 1536 dims, cosine distance, HNSW algorithm\n", - " - No boilerplate - just import and use" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "93784287e000173d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Redis configuration imported\n", - " Redis URL: redis://localhost:6379\n", - " Vector index name: course_catalog\n" - ] - } - ], - "source": [ - "from redis_context_course.redis_config import redis_config\n", - "\n", - "print(\"✅ Redis configuration imported\")\n", - "print(f\" Redis URL: {redis_config.redis_url}\")\n", - "print(f\" Vector index name: {redis_config.vector_index_name}\")" - ] - }, - { - "cell_type": "markdown", - "id": "7c2f11887561871f", - "metadata": {}, - "source": [ - "### Test Redis Connection\n", - "\n", - "Let's verify Redis is running and accessible:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "154a875022180c9f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Connected to Redis\n", - " Redis is healthy and ready\n" - ] - } - ], - "source": [ - "# Test connection using built-in health check\n", - "if redis_config.health_check():\n", - " print(\"✅ Connected to Redis\")\n", - " print(f\" Redis is healthy and ready\")\n", - "else:\n", - " print(\"❌ Redis connection failed\")\n", - " print(\" Make sure Redis is running:\")\n", - " print(\" - Local: docker run -d -p 6379:6379 redis/redis-stack-server:latest\")\n", - " print(\" - Cloud: https://redis.com/try-free/\")\n", - " sys.exit(1)" - ] - }, - { - "cell_type": "markdown", - "id": "f89de1e20794eda1", - "metadata": {}, - "source": [ - "### Initialize Course Manager\n", - "\n", - "Now let's import the `CourseManager` - this handles all course operations, such as storage, retrieval, and search:\n", - "\n", - "What it provides:\n", - " - store_course(): Store a course with vector embedding\n", - " - search_courses(): Semantic search with filters\n", - " - get_course(): Retrieve course by ID\n", - " - get_course_by_code(): Retrieve course by course code\n", - " - recommend_courses(): Generate personalized recommendations\n", - "\n", - "How it works:\n", - " - Uses redis_config for connections (redis_client, vector_index, embeddings)\n", - " - Automatically generates embeddings from course content\n", - " - Uses RedisVL's VectorQuery for semantic search\n", - " - Supports metadata filters (department, difficulty, format, etc.)\n", - "\n", - "Why use this:\n", - " - Encapsulates all Redis/RedisVL complexity\n", - " - Same code used in reference agent (Sections 3 & 4)\n", - " - Focus on RAG concepts, not Redis implementation details" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "fa59e20137321967", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:36:01 redisvl.index.index INFO Index already exists, not overwriting.\n", - "✅ Course manager initialized\n", - " Ready for course storage and search\n", - " Using RedisVL for vector operations\n" - ] - } - ], - "source": [ - "from redis_context_course.course_manager import CourseManager\n", - "\n", - "# Initialize course manager\n", - "course_manager = CourseManager()\n", - "\n", - "print(\"✅ Course manager initialized\")\n", - "print(f\" Ready for course storage and search\")\n", - "print(f\" Using RedisVL for vector operations\")" - ] - }, - { - "cell_type": "markdown", - "id": "85ccf2cb80ad5e05", - "metadata": { - "scrolled": true - }, - "source": [ - "---\n", - "\n", - "## 📥 Step 4: Ingest Courses into Redis\n", - "\n", - "Now we'll load our course catalog into Redis with vector embeddings for semantic search.\n", - "\n", - "### Understanding the Ingestion Process\n", - "\n", - "The ingestion pipeline:\n", - "1. **Load** course data from JSON\n", - "2. **Generate embeddings** for each course (title + description + tags)\n", - "3. **Store** in Redis with metadata for filtering\n", - "4. **Index** vectors for fast similarity search\n", - "\n", - "Let's use the existing ingestion utilities:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "da9f4e00dcc39387", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🚀 Starting course ingestion...\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "
🚀 Starting Course Catalog Ingestion\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1;34m🚀 Starting Course Catalog Ingestion\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
✅ Redis connection successful\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m✅ Redis connection successful\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
🧹 Clearing existing data...\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[33m🧹 Clearing existing data\u001b[0m\u001b[33m...\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
   Cleared 50 course records\n",
-       "
\n" - ], - "text/plain": [ - " Cleared \u001b[1;36m50\u001b[0m course records\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
✅ Data cleared successfully\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m✅ Data cleared successfully\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
✅ Loaded catalog from course_catalog_section2.json\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m✅ Loaded catalog from course_catalog_section2.json\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
   Majors: 5\n",
-       "
\n" - ], - "text/plain": [ - " Majors: \u001b[1;36m5\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
   Courses: 50\n",
-       "
\n" - ], - "text/plain": [ - " Courses: \u001b[1;36m50\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "726dd580013540b0ba9fe613ba17c2f1", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "
✅ Ingested 5 majors\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m✅ Ingested \u001b[0m\u001b[1;32m5\u001b[0m\u001b[32m majors\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4663482cb45e4ad28f232670304028e9", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:36:05 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:05 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:05 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:06 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:06 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:06 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:06 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:06 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:07 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:07 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:07 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:07 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:08 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:08 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:08 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:08 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:09 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:09 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:09 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:09 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:10 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:10 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:10 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:10 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:10 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:11 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:11 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:11 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:11 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:11 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:12 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:12 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:12 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:12 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:13 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:13 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:13 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:13 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:14 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:14 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:15 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:15 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:15 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:15 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:15 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:16 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:16 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:17 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:17 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:36:18 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "data": { - "text/html": [ - "
\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "
✅ Ingested 50 courses\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m✅ Ingested \u001b[0m\u001b[1;32m50\u001b[0m\u001b[32m courses\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
📊 Verification - Courses: 50, Majors: 5\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[34m📊 Verification - Courses: \u001b[0m\u001b[1;34m50\u001b[0m\u001b[34m, Majors: \u001b[0m\u001b[1;34m5\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
🎉 Ingestion completed successfully!\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1;32m🎉 Ingestion completed successfully!\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "✅ Course ingestion complete!\n", - " Courses in Redis: 50\n", - " Majors in Redis: 5\n" - ] - } - ], - "source": [ - "import asyncio\n", - "\n", - "from redis_context_course.scripts.ingest_courses import CourseIngestionPipeline\n", - "\n", - "# What we're importing:\n", - "# - CourseIngestionPipeline: Handles bulk ingestion of course data\n", - "#\n", - "# What it does:\n", - "# - Loads course catalog from JSON file\n", - "# - For each course: generates embedding + stores in Redis\n", - "# - Uses CourseManager internally for storage\n", - "# - Provides progress tracking and verification\n", - "#\n", - "# Why use this:\n", - "# - Handles batch ingestion efficiently\n", - "# - Same utility used to populate reference agent\n", - "# - Includes error handling and progress reporting\n", - "\n", - "# Initialize ingestion pipeline\n", - "pipeline = CourseIngestionPipeline()\n", - "\n", - "print(\"🚀 Starting course ingestion...\")\n", - "print()\n", - "\n", - "# Run ingestion (clear existing data first)\n", - "success = await pipeline.run_ingestion(catalog_file=catalog_file, clear_existing=True)\n", - "\n", - "if success:\n", - " print()\n", - " print(\"✅ Course ingestion complete!\")\n", - "\n", - " # Verify what was ingested\n", - " verification = pipeline.verify_ingestion()\n", - " print(f\" Courses in Redis: {verification['courses']}\")\n", - " print(f\" Majors in Redis: {verification['majors']}\")\n", - "else:\n", - " print(\"❌ Ingestion failed\")" - ] - }, - { - "cell_type": "markdown", - "id": "2c4d3d17c5c3cdae", - "metadata": {}, - "source": [ - "### What Just Happened?\n", - "\n", - "For each course, the ingestion pipeline:\n", - "\n", - "1. **Created searchable content:**\n", - " ```python\n", - " content = f\"{course.title} {course.description} {course.department} {' '.join(course.tags)}\"\n", - " ```\n", - "\n", - "2. **Generated embedding vector:**\n", - " ```python\n", - " embedding = await embeddings.aembed_query(content) # 1536-dim vector\n", - " ```\n", - "\n", - "3. **Stored in Redis:**\n", - " ```python\n", - " redis_client.hset(f\"course_idx:{course.id}\", mapping={\n", - " \"course_code\": \"CS001\",\n", - " \"title\": \"Introduction to Programming\",\n", - " \"description\": \"...\",\n", - " \"content_vector\": embedding.tobytes() # Binary vector\n", - " })\n", - " ```\n", - "\n", - "4. **Indexed for search:**\n", - " - Redis automatically indexes the vector field\n", - " - Enables fast k-NN (k-nearest neighbors) search\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "d19cebdedbaec6a0", - "metadata": {}, - "source": [ - "## 🔍 Step 5: Semantic Search - Finding Relevant Courses\n", - "\n", - "Now comes the magic: semantic search. Let's query our vector store to find relevant courses.\n", - "\n", - "### Basic Semantic Search\n", - "\n", - "Let's search for courses related to \"machine learning\".\n", - "\n", - "When this is called:\n", - "```python\n", - "await course_manager.search_courses(\n", - " query=query,\n", - " limit=3 # top_k parameter\n", - ")\n", - "```\n", - "It is performing semantic search under the hood:\n", - "1. Generates embedding for the query using OpenAI\n", - "2. Performs vector similarity search in Redis (cosine distance)\n", - "3. Returns top-k most similar courses\n", - "4. Uses RedisVL's VectorQuery under the hood" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "8bd46b1b7a140f91", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🔍 Searching for: 'machine learning and artificial intelligence'\n", - "\n", - "12:36:53 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "✅ Found 3 relevant courses:\n", - "\n", - "1. CS007: Machine Learning\n", - " Department: Computer Science\n", - " Difficulty: advanced\n", - " Description: Introduction to machine learning algorithms and applications. Supervised and unsupervised learning, ...\n", - "\n", - "2. DS018: Statistics for Data Science\n", - " Department: Data Science\n", - " Difficulty: intermediate\n", - " Description: Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and st...\n", - "\n", - "3. DS014: Statistics for Data Science\n", - " Department: Data Science\n", - " Difficulty: intermediate\n", - " Description: Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and st...\n", - "\n" - ] - } - ], - "source": [ - "# We already initialized course_manager in Step 3\n", - "# It's ready to use for semantic search\n", - "\n", - "# Search for machine learning courses\n", - "query = \"machine learning and artificial intelligence\"\n", - "print(f\"🔍 Searching for: '{query}'\\n\")\n", - "\n", - "# Perform semantic search (returns top 3 most similar courses)\n", - "results = await course_manager.search_courses(query=query, limit=3) # top_k parameter\n", - "\n", - "print(f\"✅ Found {len(results)} relevant courses:\\n\")\n", - "\n", - "for i, course in enumerate(results, 1):\n", - " print(f\"{i}. {course.course_code}: {course.title}\")\n", - " print(f\" Department: {course.department}\")\n", - " print(f\" Difficulty: {course.difficulty_level.value}\")\n", - " print(f\" Description: {course.description[:100]}...\")\n", - " print()" - ] - }, - { - "cell_type": "markdown", - "id": "19e81b08ef0b24e1", - "metadata": {}, - "source": [ - "### Search with Filters\n", - "\n", - "We can combine semantic search with metadata filters for more precise results:\n", - "\n", - "How filters work:\n", - "\n", - "```python\n", - "results = await course_manager.search_courses(\n", - " query=query,\n", - " limit=3,\n", - " filters=filters\n", - ")\n", - "```\n", - " - CourseManager._build_filters() converts dict to RedisVL filter expressions\n", - " - Uses Tag filters for categorical fields (difficulty_level, format, department)\n", - " - Uses Num filters for numeric fields (credits, year)\n", - " - Combines filters with AND logic\n", - " - Applied to vector search results\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "9c9406198195f5c4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🔍 Searching for: 'machine learning'\n", - " Filters: {'difficulty_level': 'beginner', 'format': 'online'}\n", - "\n", - "12:37:20 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "✅ Found 3 matching courses:\n", - "1. DS020: Data Visualization\n", - " Format: online, Difficulty: beginner\n", - "\n", - "2. PSY043: Introduction to Psychology\n", - " Format: online, Difficulty: beginner\n", - "\n", - "3. PSY049: Introduction to Psychology\n", - " Format: online, Difficulty: beginner\n", - "\n" - ] - } - ], - "source": [ - "# Search for beginner-level machine learning courses\n", - "query = \"machine learning\"\n", - "filters = {\"difficulty_level\": \"beginner\", \"format\": \"online\"}\n", - "\n", - "print(f\"🔍 Searching for: '{query}'\\n Filters: {filters}\\n\")\n", - "# How filters work:\n", - "# - CourseManager._build_filters() converts dict to RedisVL filter expressions\n", - "# - Uses Tag filters for categorical fields (difficulty_level, format, department)\n", - "# - Uses Num filters for numeric fields (credits, year)\n", - "# - Combines filters with AND logic\n", - "# - Applied to vector search results\n", - "results = await course_manager.search_courses(query=query, limit=3, filters=filters)\n", - "\n", - "print(f\"✅ Found {len(results)} matching courses:\")\n", - "for i, course in enumerate(results, 1):\n", - " print(f\"{i}. {course.course_code}: {course.title}\")\n", - " print(\n", - " f\" Format: {course.format.value}, Difficulty: {course.difficulty_level.value}\"\n", - " )\n", - " print()" - ] - }, - { - "cell_type": "markdown", - "id": "35d2fedcf3efb590", - "metadata": {}, - "source": [ - "**💡 Key Insight:** We can combine:\n", - "- **Semantic search** (find courses about \"machine learning\")\n", - "- **Metadata filters** (only beginner, online courses)\n", - "\n", - "This gives us precise, relevant results for any query. This will be a useful tool to build context for our RAG pipeline.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "b38da21b55f381ab", - "metadata": {}, - "source": [ - "## 🔗 Step 6: Building the RAG Pipeline\n", - "\n", - "Now let's combine everything into a complete RAG pipeline: Retrieval → Context Assembly → Generation.\n", - "\n", - "### The RAG Flow\n", - "\n", - "```\n", - "User Query\n", - " ↓\n", - "1. Semantic Search (retrieve relevant courses)\n", - " ↓\n", - "2. Context Assembly (combine system + user + retrieved context)\n", - " ↓\n", - "3. LLM Generation (create personalized response)\n", - "```\n", - "\n", - "Let's implement each step:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "3a3289098af7058a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ LLM initialized (gpt-4o-mini)\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage, SystemMessage\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "# Initialize LLM\n", - "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0.7)\n", - "\n", - "print(\"✅ LLM initialized (gpt-4o-mini)\")" - ] - }, - { - "cell_type": "markdown", - "id": "e1206c431ffb4292", - "metadata": {}, - "source": [ - "### Step 6.1: Retrieval Function\n", - "\n", - "First, let's create a function to retrieve relevant courses:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "ef03683be57faf95", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:37:29 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "🔍 Retrieved 3 courses for: 'I want to learn about data structures'\n", - " - CS009: Data Structures and Algorithms\n", - " - CS001: Introduction to Programming\n", - " - CS005: Introduction to Programming\n" - ] - } - ], - "source": [ - "async def retrieve_courses(query: str, limit: int = 3, filters: dict = None):\n", - " \"\"\"\n", - " Retrieve relevant courses using semantic search.\n", - "\n", - " Args:\n", - " query: User's search query\n", - " limit: Number of courses to retrieve\n", - " filters: Optional metadata filters\n", - "\n", - " Returns:\n", - " List of relevant courses\n", - " \"\"\"\n", - " results = await course_manager.search_courses(\n", - " query=query, limit=limit, filters=filters\n", - " )\n", - " return results\n", - "\n", - "\n", - "# Test retrieval\n", - "test_query = \"I want to learn about data structures\"\n", - "retrieved_courses = await retrieve_courses(test_query, limit=3)\n", - "\n", - "print(f\"🔍 Retrieved {len(retrieved_courses)} courses for: '{test_query}'\")\n", - "for course in retrieved_courses:\n", - " print(f\" - {course.course_code}: {course.title}\")" - ] - }, - { - "cell_type": "markdown", - "id": "6a068ffa458f850f", - "metadata": {}, - "source": [ - "### Step 6.2: Context Assembly Function\n", - "\n", - "Now let's assemble context from multiple sources (system + user + retrieved):" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "16d6089b-7fe2-451d-b57d-436c49259216", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Context assembled\n", - " Total length: 1537 characters\n", - " Includes: System + User + Retrieved context\n" - ] - } - ], - "source": [ - "def assemble_context(\n", - " user_query: str, retrieved_courses: list, user_profile: dict = None\n", - "):\n", - " \"\"\"\n", - " Assemble context from multiple sources for the LLM.\n", - "\n", - " This implements the context engineering principles from Section 1:\n", - " - System Context: AI role and instructions\n", - " - User Context: Student profile and preferences\n", - " - Retrieved Context: Relevant courses from vector search\n", - " \"\"\"\n", - "\n", - " # System Context: Define the AI's role\n", - " system_context = \"\"\"You are a Redis University course advisor.\n", - "\n", - "Your role:\n", - "- Help students find courses that match their interests and goals\n", - "- Provide personalized recommendations based on student profiles\n", - "- Explain course prerequisites and learning paths\n", - "- Be encouraging and supportive\n", - "\n", - "Guidelines:\n", - "- Only recommend courses from the provided course list\n", - "- Consider student's difficulty level preferences\n", - "- Explain your reasoning for recommendations\n", - "- Be concise but informative\n", - "\"\"\"\n", - "\n", - " # User Context: Student profile (if provided)\n", - " user_context = \"\"\n", - " if user_profile:\n", - " user_context = f\"\"\"\n", - "Student Profile:\n", - "- Name: {user_profile.get('name', 'Student')}\n", - "- Major: {user_profile.get('major', 'Undeclared')}\n", - "- Year: {user_profile.get('year', 'N/A')}\n", - "- Interests: {', '.join(user_profile.get('interests', []))}\n", - "- Preferred Difficulty: {user_profile.get('preferred_difficulty', 'any')}\n", - "- Preferred Format: {user_profile.get('preferred_format', 'any')}\n", - "\"\"\"\n", - "\n", - " # Retrieved Context: Relevant courses from semantic search\n", - " retrieved_context = \"\\nRelevant Courses:\\n\"\n", - " for i, course in enumerate(retrieved_courses, 1):\n", - " retrieved_context += f\"\"\"\n", - "{i}. {course.course_code}: {course.title}\n", - " Department: {course.department}\n", - " Difficulty: {course.difficulty_level.value}\n", - " Format: {course.format.value}\n", - " Credits: {course.credits}\n", - " Description: {course.description}\n", - " Prerequisites: {len(course.prerequisites)} required\n", - "\"\"\"\n", - "\n", - " # Combine all context\n", - " full_context = system_context\n", - " if user_context:\n", - " full_context += user_context\n", - " full_context += retrieved_context\n", - "\n", - " return full_context\n", - "\n", - "\n", - "# Test context assembly\n", - "test_profile = {\n", - " \"name\": \"Sarah Chen\",\n", - " \"major\": \"Computer Science\",\n", - " \"year\": \"Junior\",\n", - " \"interests\": [\"machine learning\", \"data science\"],\n", - " \"preferred_difficulty\": \"intermediate\",\n", - " \"preferred_format\": \"online\",\n", - "}\n", - "\n", - "assembled_context = assemble_context(\n", - " user_query=test_query,\n", - " retrieved_courses=retrieved_courses,\n", - " user_profile=test_profile,\n", - ")\n", - "\n", - "print(\"✅ Context assembled\")\n", - "print(f\" Total length: {len(assembled_context)} characters\")\n", - "print(f\" Includes: System + User + Retrieved context\")" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "9800d8dd-38ea-482f-9486-fc32ba9f1799", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Observe the assembled context: \n", - "\n", - "You are a Redis University course advisor.\n", - "\n", - "Your role:\n", - "- Help students find courses that match their interests and goals\n", - "- Provide personalized recommendations based on student profiles\n", - "- Explain course prerequisites and learning paths\n", - "- Be encouraging and supportive\n", - "\n", - "Guidelines:\n", - "- Only recommend courses from the provided course list\n", - "- Consider student's difficulty level preferences\n", - "- Explain your reasoning for recommendations\n", - "- Be concise but informative\n", - "\n", - "Student Profile:\n", - "- Name: Sarah Chen\n", - "- Major: Computer Science\n", - "- Year: Junior\n", - "- Interests: machine learning, data science\n", - "- Preferred Difficulty: intermediate\n", - "- Preferred Format: online\n", - "\n", - "Relevant Courses:\n", - "\n", - "1. CS009: Data Structures and Algorithms\n", - " Department: Computer Science\n", - " Difficulty: intermediate\n", - " Format: in_person\n", - " Credits: 4\n", - " Description: Study of fundamental data structures and algorithms. Arrays, linked lists, trees, graphs, sorting, and searching.\n", - " Prerequisites: 2 required\n", - "\n", - "2. CS001: Introduction to Programming\n", - " Department: Computer Science\n", - " Difficulty: beginner\n", - " Format: hybrid\n", - " Credits: 3\n", - " Description: Fundamental programming concepts using Python. Variables, control structures, functions, and basic data structures.\n", - " Prerequisites: 0 required\n", - "\n", - "3. CS005: Introduction to Programming\n", - " Department: Computer Science\n", - " Difficulty: beginner\n", - " Format: hybrid\n", - " Credits: 3\n", - " Description: Fundamental programming concepts using Python. Variables, control structures, functions, and basic data structures.\n", - " Prerequisites: 0 required\n", - "\n" - ] - } - ], - "source": [ - "print(f\"Observe the assembled context: \\n\\n{assembled_context}\")" - ] - }, - { - "cell_type": "markdown", - "id": "9f28151926c3be5", - "metadata": {}, - "source": [ - "**🎁 Bonus:** Can you identify the different parts of the context from what we learned in section 1 from above?" - ] - }, - { - "cell_type": "markdown", - "id": "19c1be78f7cd3e20", - "metadata": {}, - "source": [ - "**✅ Answer:** Yes! Looking at the assembled context above, we can identify all three context types from Section 1:\n", - "\n", - "1. **System Context** (Static)\n", - " - The first section: \"You are a Redis University course advisor...\"\n", - " - Defines the AI's role, responsibilities, and guidelines\n", - " - Remains the same for all queries\n", - " - Sets behavioral instructions and constraints\n", - "\n", - "2. **User Context** (Dynamic, User-Specific)\n", - " - The \"Student Profile\" section\n", - " - Contains Sarah Chen's personal information: major, year, interests, preferences\n", - " - Changes based on who is asking the question\n", - " - Enables personalized recommendations\n", - "\n", - "3. **Retrieved Context** (Dynamic, Query-Specific)\n", - " - The \"Relevant Courses\" section\n", - " - Lists the 3 courses found via semantic search for \"data structures\"\n", - " - Changes based on the specific query\n", - " - Provides the factual information the LLM needs to answer\n", - "\n", - "Notice how all three work together: System Context tells the AI **how to behave**, User Context tells it **who it's helping**, and Retrieved Context provides **what information is relevant**. This is RAG in action!" - ] - }, - { - "cell_type": "markdown", - "id": "9e27332f-83d5-475f-9fcc-405525a25c9f", - "metadata": {}, - "source": [ - "### Step 6.3: Generation Function\n", - "\n", - "Finally, let's generate a response using the assembled context:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "cba9e518ee7581c6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:37:48 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", - "\n", - "🤖 Generated Response:\n", - "\n", - "Hi Sarah! It's great to hear that you're interested in learning about data structures, especially since they are fundamental to computer science and essential for machine learning and data science.\n", - "\n", - "Based on your profile, I would recommend **CS009: Data Structures and Algorithms**. Here’s why:\n", - "\n", - "- **Difficulty Level**: This course is at the intermediate level, which matches your preferred difficulty.\n", - "- **Content**: It covers essential topics like arrays, linked lists, trees, graphs, sorting, and searching, all of which are critical for understanding how data is organized and manipulated.\n", - "- **Prerequisites**: Keep in mind that this course requires two prerequisites, so you should ensure you meet those before enrolling.\n", - "\n", - "Unfortunately, this course is in-person, which may not align with your preferred format of online learning. However, if you're open to exploring other options or considering a hybrid format, we can look into additional resources or courses later on.\n", - "\n", - "If you have any other preferences or need further assistance, feel free to ask! You're on a great path, and I'm here to support you in your learning journey.\n" - ] - } - ], - "source": [ - "async def generate_response(user_query: str, context: str):\n", - " \"\"\"\n", - " Generate LLM response using assembled context.\n", - "\n", - " Args:\n", - " user_query: User's question\n", - " context: Assembled context (system + user + retrieved)\n", - "\n", - " Returns:\n", - " LLM response string\n", - " \"\"\"\n", - " messages = [SystemMessage(content=context), HumanMessage(content=user_query)]\n", - "\n", - " response = await llm.ainvoke(messages)\n", - " return response.content\n", - "\n", - "\n", - "# Test generation\n", - "response = await generate_response(test_query, assembled_context)\n", - "\n", - "print(\"\\n🤖 Generated Response:\\n\")\n", - "print(response)" - ] - }, - { - "cell_type": "markdown", - "id": "29793f2405eba89f", - "metadata": {}, - "source": [ - "### 🎯 Understanding the Generated Response\n", - "\n", - "Notice how the LLM's response demonstrates effective context engineering:\n", - "\n", - "**👤 Personalization from User Context:**\n", - "- Addresses Sarah by name\n", - "- References her intermediate difficulty preference\n", - "- Acknowledges her online format preference (even though the course is in-person)\n", - "- Connects to her interests (machine learning and data science)\n", - "\n", - "**📚 Accuracy from Retrieved Context:**\n", - "- Recommends CS009 (which was in the retrieved courses)\n", - "- Provides correct course details (difficulty, format, credits, description)\n", - "- Mentions prerequisites accurately (2 required)\n", - "\n", - "**🤖 Guidance from System Context:**\n", - "- Acts as a supportive advisor (\"I'm here to help you succeed!\")\n", - "- Explains reasoning for the recommendation\n", - "- Acknowledges the format mismatch honestly\n", - "- Stays within the provided course list\n", - "\n", - "This is the power of RAG: the LLM generates a response that is **personalized** (User Context), **accurate** (Retrieved Context), and **helpful** (System Context). Without RAG, the LLM would either hallucinate course details or provide generic advice." - ] - }, - { - "cell_type": "markdown", - "id": "b7dff6ee-0f65-4875-b0ee-469a2afd26b0", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## ✨ Step 7: Complete RAG Function\n", - "\n", - "Let's combine all three steps into a single, reusable RAG function:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "b4a079374b0fe92c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "============================================================\n", - "COMPLETE RAG PIPELINE TEST\n", - "============================================================\n", - "\n", - "Query: I'm interested in learning about databases and data management\n", - "\n", - "Student: Alex Johnson (Data Science, Sophomore)\n", - "\n", - "12:38:16 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:38:23 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", - "Retrieved Courses:\n", - " 1. CS004: Database Systems\n", - " 2. CS009: Data Structures and Algorithms\n", - " 3. CS007: Machine Learning\n", - "\n", - "AI Response:\n", - "Hi Alex! Based on your interest in databases and data management, I recommend the following course:\n", - "\n", - "**CS004: Database Systems**\n", - "- **Department:** Computer Science\n", - "- **Difficulty:** Intermediate\n", - "- **Format:** Online\n", - "- **Credits:** 3\n", - "- **Description:** This course covers the design and implementation of database systems, focusing on SQL, normalization, transactions, and database administration.\n", - "\n", - "This course aligns perfectly with your interests in databases and data analysis. Since you are looking for an intermediate-level course and it provides a solid foundation in SQL, it would be a great fit for your data science major.\n", - "\n", - "Unfortunately, it is only available in an online format, which doesn't match your preference for hybrid learning. However, it is still a strong option to consider for building your database knowledge.\n", - "\n", - "If you’re looking for more advanced topics later on, you might want to consider **CS007: Machine Learning** in the future, as it does have hybrid availability and can complement your data analysis skills.\n", - "\n", - "Let me know if you need more information or if you're interested in exploring other options!\n" - ] - } - ], - "source": [ - "async def rag_query(\n", - " user_query: str, user_profile: dict = None, limit: int = 3, filters: dict = None\n", - "):\n", - " \"\"\"\n", - " Complete RAG pipeline: Retrieve → Assemble → Generate\n", - "\n", - " Args:\n", - " user_query: User's question\n", - " user_profile: Optional student profile\n", - " limit: Number of courses to retrieve\n", - " filters: Optional metadata filters\n", - "\n", - " Returns:\n", - " LLM response string\n", - " \"\"\"\n", - " # Step 1: Retrieve relevant courses\n", - " retrieved_courses = await retrieve_courses(user_query, limit, filters)\n", - "\n", - " # Step 2: Assemble context\n", - " context = assemble_context(user_query, retrieved_courses, user_profile)\n", - "\n", - " # Step 3: Generate response\n", - " response = await generate_response(user_query, context)\n", - "\n", - " return response, retrieved_courses\n", - "\n", - "\n", - "# Test the complete RAG pipeline\n", - "print(\"=\" * 60)\n", - "print(\"COMPLETE RAG PIPELINE TEST\")\n", - "print(\"=\" * 60)\n", - "print()\n", - "\n", - "query = \"I'm interested in learning about databases and data management\"\n", - "profile = {\n", - " \"name\": \"Alex Johnson\",\n", - " \"major\": \"Data Science\",\n", - " \"year\": \"Sophomore\",\n", - " \"interests\": [\"databases\", \"data analysis\", \"SQL\"],\n", - " \"preferred_difficulty\": \"intermediate\",\n", - " \"preferred_format\": \"hybrid\",\n", - "}\n", - "\n", - "print(f\"Query: {query}\")\n", - "print()\n", - "print(f\"Student: {profile['name']} ({profile['major']}, {profile['year']})\")\n", - "print()\n", - "\n", - "response, courses = await rag_query(query, profile, limit=3)\n", - "\n", - "print(\"Retrieved Courses:\")\n", - "for i, course in enumerate(courses, 1):\n", - " print(f\" {i}. {course.course_code}: {course.title}\")\n", - "print()\n", - "\n", - "print(\"AI Response:\")\n", - "print(response)" - ] - }, - { - "cell_type": "markdown", - "id": "f126f77dd7242ddb", - "metadata": {}, - "source": [ - "### 🎯 Why This Complete RAG Function Matters\n", - "\n", - "The `rag_query()` function encapsulates the entire RAG pipeline in a single, reusable interface. This is important because:\n", - "\n", - "**1. Simplicity:** One function call handles retrieval → assembly → generation\n", - "- No need to manually orchestrate the three steps\n", - "- Clean API for building applications\n", - "\n", - "**2. Consistency:** Every query follows the same pattern\n", - "- Ensures all three context types are always included\n", - "- Reduces errors from missing context\n", - "\n", - "**3. Flexibility:** Easy to customize behavior\n", - "- Adjust `top_k` for more/fewer retrieved courses\n", - "- Add/remove user profile information\n", - "- Modify filters for specific use cases\n", - "\n", - "**4. Production-Ready:** This pattern scales to real applications\n", - "- In Section 3, we'll add memory (conversation history)\n", - "- In Section 4, we'll add tools (course enrollment, prerequisites checking)\n", - "- The core RAG pattern remains the same\n", - "\n", - "This is the foundation you'll build on throughout the rest of the course." - ] - }, - { - "cell_type": "markdown", - "id": "3d63b2d5a412a8d", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🧪 Step 8: Try Different Queries\n", - "\n", - "Let's test our RAG system with various queries to see how it handles different scenarios:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "e6d543a2d75022b9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "============================================================\n", - "TEST 1: Beginner Programming\n", - "============================================================\n", - "\n", - "12:38:32 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:38:37 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", - "\n", - "Query: I'm new to programming and want to start learning\n", - "\n", - "\n", - "AI Response:\n", - "\n", - "Hi Maria! It's great to hear that you're interested in starting your programming journey. Since you're a freshman and looking for beginner-level courses, I recommend considering the following course:\n", - "\n", - "**CS001: Introduction to Programming**\n", - "- **Department:** Computer Science\n", - "- **Difficulty:** Beginner\n", - "- **Format:** Hybrid\n", - "- **Credits:** 3\n", - "- **Description:** This course covers fundamental programming concepts using Python, including variables, control structures, functions, and basic data structures.\n", - "- **Prerequisites:** None required\n", - "\n", - "This course is perfect for you as it’s designed for beginners and will give you a solid foundation in programming. Although it is hybrid, meaning it may include some in-person components, it’s still a great starting point to learn the basics of programming.\n", - "\n", - "If you have any more questions or need further assistance, feel free to ask! I'm here to help you succeed.\n" - ] - } - ], - "source": [ - "# Test 1: Beginner looking for programming courses\n", - "print(\"=\" * 60)\n", - "print(\"TEST 1: Beginner Programming\")\n", - "print(\"=\" * 60)\n", - "print()\n", - "\n", - "query1 = \"I'm new to programming and want to start learning\"\n", - "profile1 = {\n", - " \"name\": \"Maria Garcia\",\n", - " \"major\": \"Undeclared\",\n", - " \"year\": \"Freshman\",\n", - " \"interests\": [\"programming\", \"technology\"],\n", - " \"preferred_difficulty\": \"beginner\",\n", - " \"preferred_format\": \"online\",\n", - "}\n", - "\n", - "response1, courses1 = await rag_query(query1, profile1, limit=2)\n", - "print(f\"\\nQuery: {query1}\\n\")\n", - "print(\"\\nAI Response:\\n\")\n", - "print(response1)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "f6430f264bc17b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "============================================================\n", - "TEST 2: Advanced Machine Learning\n", - "============================================================\n", - "\n", - "12:38:41 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:38:47 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", - "\n", - "Query: I want advanced courses in machine learning and AI\n", - "\n", - "\n", - "AI Response:\n", - "\n", - "Hi David! Based on your interests and preferences, I recommend considering the following course:\n", - "\n", - "1. **CS007: Machine Learning**\n", - " - **Department**: Computer Science\n", - " - **Difficulty**: Advanced\n", - " - **Format**: Hybrid (Note: not in-person, but still could be beneficial)\n", - " - **Credits**: 4\n", - " - **Description**: This course covers a range of machine learning algorithms and applications, including both supervised and unsupervised learning, as well as neural networks.\n", - "\n", - "While this course is hybrid and not strictly in-person, it aligns perfectly with your advanced level preference and focuses on machine learning, which is directly relevant to your interests in AI and research. \n", - "\n", - "Unfortunately, I don't see any purely in-person advanced courses specifically focused on machine learning or AI. If you're open to the hybrid format, I believe CS007 would be a great fit for you. Let me know if you have any other questions or if there's anything else I can assist you with!\n" - ] - } - ], - "source": [ - "# Test 2: Advanced student looking for specialized courses\n", - "print(\"=\" * 60)\n", - "print(\"TEST 2: Advanced Machine Learning\")\n", - "print(\"=\" * 60)\n", - "print()\n", - "\n", - "query2 = \"I want advanced courses in machine learning and AI\"\n", - "profile2 = {\n", - " \"name\": \"David Kim\",\n", - " \"major\": \"Computer Science\",\n", - " \"year\": \"Senior\",\n", - " \"interests\": [\"machine learning\", \"AI\", \"research\"],\n", - " \"preferred_difficulty\": \"advanced\",\n", - " \"preferred_format\": \"in-person\",\n", - "}\n", - "\n", - "response2, courses2 = await rag_query(query2, profile2, limit=2)\n", - "print(f\"\\nQuery: {query2}\\n\")\n", - "print(\"\\nAI Response:\\n\")\n", - "print(response2)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "38103b67a0624eb4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "============================================================\n", - "TEST 3: Business Analytics\n", - "============================================================\n", - "\n", - "12:38:47 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "12:38:51 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", - "\n", - "Query: What courses can help me with business analytics and decision making?\n", - "\n", - "\n", - "\n", - "AI Response:\n", - "\n", - "Hi Jennifer! Based on your interests in analytics, management, and strategy, I recommend the following course:\n", - "\n", - "**BUS035: Marketing Strategy**\n", - "- **Difficulty:** Intermediate\n", - "- **Format:** Hybrid\n", - "- **Credits:** 3\n", - "- **Description:** This course covers strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques. While it focuses on marketing, the skills you'll gain in market analysis are highly relevant to business analytics and decision-making.\n", - "\n", - "This course aligns well with your major in Business Administration and your interest in strategy. The hybrid format will also give you a balance of in-person interaction and online flexibility.\n", - "\n", - "Unfortunately, the other course listed (BUS039) is only available online, which doesn't meet your preferred format. \n", - "\n", - "I believe BUS035 will be a great fit for you, allowing you to enhance your analytical skills while applying them to real-world business strategies. If you have any more questions or need further guidance, feel free to ask!\n" - ] - } - ], - "source": [ - "# Test 3: Business student looking for relevant courses\n", - "print(\"=\" * 60)\n", - "print(\"TEST 3: Business Analytics\")\n", - "print(\"=\" * 60)\n", - "print()\n", - "\n", - "query3 = \"What courses can help me with business analytics and decision making?\"\n", - "profile3 = {\n", - " \"name\": \"Jennifer Lee\",\n", - " \"major\": \"Business Administration\",\n", - " \"year\": \"Junior\",\n", - " \"interests\": [\"analytics\", \"management\", \"strategy\"],\n", - " \"preferred_difficulty\": \"intermediate\",\n", - " \"preferred_format\": \"hybrid\",\n", - "}\n", - "\n", - "response3, courses3 = await rag_query(query3, profile3, limit=2)\n", - "print(f\"\\nQuery: {query3}\\n\")\n", - "print()\n", - "print(\"\\nAI Response:\\n\")\n", - "print(response3)" - ] - }, - { - "cell_type": "markdown", - "id": "6994c097a695afdb", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🎓 Key Takeaways\n", - "\n", - "### What You've Learned\n", - "\n", - "**1. RAG Fundamentals**\n", - "- RAG dynamically retrieves relevant information instead of hardcoding knowledge\n", - "- Vector embeddings enable semantic search (meaning-based, not keyword-based)\n", - "- RAG solves the scalability and token efficiency problems of static context\n", - "\n", - "**2. The RAG Pipeline**\n", - "```\n", - "User Query → Semantic Search → Context Assembly → LLM Generation\n", - "```\n", - "- **Retrieval:** Find relevant documents using vector similarity\n", - "- **Assembly:** Combine system + user + retrieved context\n", - "- **Generation:** LLM creates personalized response with full context\n", - "\n", - "**3. Context Engineering in Practice**\n", - "- **System Context:** AI role and instructions (static)\n", - "- **User Context:** Student profile and preferences (dynamic, user-specific)\n", - "- **Retrieved Context:** Relevant courses from vector search (dynamic, query-specific)\n", - "- **Integration:** All three context types work together\n", - "\n", - "**4. Technical Implementation with Reference Agent Utilities**\n", - "- **redis_config**: Production-ready Redis configuration (RedisVL + LangChain)\n", - " - Manages connections, embeddings, vector index, checkpointer\n", - " - Same configuration used in reference agent\n", - "- **CourseManager**: Handles all course operations\n", - " - Uses RedisVL's VectorQuery for semantic search\n", - " - Supports metadata filters with Tag and Num classes\n", - " - Automatically generates embeddings and stores courses\n", - "- **CourseIngestionPipeline**: Bulk data ingestion\n", - " - Loads JSON, generates embeddings, stores in Redis\n", - " - Progress tracking and verification\n", - "- **Benefits**: Focus on RAG concepts, not Redis implementation details\n", - "\n", - "### Best Practices\n", - "\n", - "**Retrieval:**\n", - "- Retrieve only what's needed (top-k results)\n", - "- Use metadata filters to narrow results\n", - "- Balance between too few (missing info) and too many (wasting tokens) results\n", - "- **💡 Research Insight:** Context Rot research shows that distractors (similar-but-wrong information) have amplified negative impact in long contexts. Precision in retrieval matters more than recall. ([Context Rot paper](https://research.trychroma.com/context-rot))\n", - "\n", - "**Context Assembly:**\n", - "- Structure context clearly (system → user → retrieved)\n", - "- Include only relevant metadata\n", - "- Keep descriptions concise but informative\n", - "\n", - "**Generation:**\n", - "- Use appropriate temperature (0.7 for creative, 0.0 for factual)\n", - "- Provide clear instructions in system context\n", - "- Let the LLM explain its reasoning\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "44f445a3359501a4", - "metadata": {}, - "source": [ - "## Part 4: Context Quality Matters\n", - "\n", - "### Why Quality Engineering is Essential\n", - "\n", - "You've built a working RAG system - congratulations! But there's a critical question: **What makes context \"good\"?**\n", - "\n", - "In the next notebook, you'll learn that context engineering is real engineering - it requires the same rigor, analysis, and deliberate decision-making as any other engineering discipline. Let's preview why this matters with a concrete example.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "9d9b8641f068666b", - "metadata": {}, - "source": [ - "### Example: The Impact of Poor vs. Well-Engineered Context\n", - "\n", - "Let's see what happens when we don't engineer our context properly.\n", - "\n", - "**Scenario:** A student asks about machine learning courses." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "38e31170-962f-4fe9-9209-a48f23a33400", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:38:52 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "❌ POOR CONTEXT (Naive Approach):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Courses: 10 (unfiltered - may not be relevant)\n", - "Tokens: 1,261\n", - "Format: Raw JSON with all fields (including internal IDs)\n", - "\n", - "Sample:\n", - "[\n", - " {\n", - " \"id\": \"course_catalog:01KBQSB5VZ3490FT449SH6Y3KT\",\n", - " \"course_code\": \"MATH027\",\n", - " \"title\": \"Calculus I\",\n", - " \"description\": \"Differential calculus including limits, derivatives, and applications. Foundation for advanced mathematics.\",\n", - " \"department\": \"Mathematics\",\n", - " \"credits\": 4,\n", - " ...\n", - "\n" - ] - } - ], - "source": [ - "# Poor context: Raw JSON dump (what we might do naively)\n", - "# Get first 10 courses using a broad search\n", - "poor_context_courses = await course_manager.search_courses(\"course\", limit=10)\n", - "\n", - "poor_context = json.dumps(\n", - " [\n", - " {\n", - " \"id\": c.id,\n", - " \"course_code\": c.course_code,\n", - " \"title\": c.title,\n", - " \"description\": c.description,\n", - " \"department\": c.department,\n", - " \"credits\": c.credits,\n", - " \"difficulty_level\": c.difficulty_level.value,\n", - " \"format\": c.format.value,\n", - " \"instructor\": c.instructor,\n", - " \"prerequisites\": (\n", - " [p.course_code for p in c.prerequisites] if c.prerequisites else []\n", - " ),\n", - " }\n", - " for c in poor_context_courses\n", - " ],\n", - " indent=2,\n", - ")\n", - "\n", - "poor_tokens = count_tokens(poor_context)\n", - "\n", - "print(\n", - " f\"\"\"❌ POOR CONTEXT (Naive Approach):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Courses: {len(poor_context_courses)} (unfiltered - may not be relevant)\n", - "Tokens: {poor_tokens:,}\n", - "Format: Raw JSON with all fields (including internal IDs)\n", - "\n", - "Sample:\n", - "{poor_context[:300]}...\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "53e77ef9355ce3d7", - "metadata": {}, - "source": [ - "Now let's compare with well-engineered context using our RAG system:" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "742185aabf47db4e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:38:52 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n", - "✅ WELL-ENGINEERED CONTEXT (RAG + Optimization):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Courses: 3 (filtered by semantic relevance)\n", - "Tokens: 146\n", - "Format: LLM-optimized text (no internal fields, clean formatting)\n", - "\n", - "Context:\n", - "CS007: Machine Learning (advanced)\n", - "Description: Introduction to machine learning algorithms and applications. Supervised and unsupervised learning, neural networks.\n", - "Department: Computer Science | Credits: 4 | Format: hybrid\n", - "Prerequisites: None\n", - "\n", - "MATH022: Linear Algebra (intermediate)\n", - "Description: Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.\n", - "Department: Mathematics | Credits: 3 | Format: in_person\n", - "Prerequisites: None\n", - "\n", - "MATH023: Linear Algebra (intermediate)\n", - "Description: Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.\n", - "Department: Mathematics | Credits: 3 | Format: hybrid\n", - "Prerequisites: None\n", - "\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Token Reduction: 1,115 tokens (88.4% reduction)\n", - "Cost Savings: $0.0028 per request\n", - "\n" - ] - } - ], - "source": [ - "# Well-engineered context: Filtered + Optimized\n", - "query = \"What machine learning courses are available?\"\n", - "\n", - "# Use our RAG system to get relevant courses\n", - "relevant_courses = await course_manager.search_courses(query, limit=3)\n", - "\n", - "# Transform to LLM-friendly format (not raw JSON)\n", - "well_engineered_context = \"\\n\\n\".join(\n", - " [\n", - " f\"\"\"{course.course_code}: {course.title} ({course.difficulty_level.value})\n", - "Description: {course.description}\n", - "Department: {course.department} | Credits: {course.credits} | Format: {course.format.value}\n", - "Prerequisites: {', '.join([p.course_code for p in course.prerequisites]) if course.prerequisites else 'None'}\"\"\"\n", - " for course in relevant_courses\n", - " ]\n", - ")\n", - "\n", - "good_tokens = count_tokens(well_engineered_context)\n", - "\n", - "print(\n", - " f\"\"\"✅ WELL-ENGINEERED CONTEXT (RAG + Optimization):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Courses: {len(relevant_courses)} (filtered by semantic relevance)\n", - "Tokens: {good_tokens:,}\n", - "Format: LLM-optimized text (no internal fields, clean formatting)\n", - "\n", - "Context:\n", - "{well_engineered_context}\n", - "\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Token Reduction: {poor_tokens - good_tokens:,} tokens ({((poor_tokens - good_tokens) / poor_tokens * 100):.1f}% reduction)\n", - "Cost Savings: ${((poor_tokens - good_tokens) / 1_000_000) * 2.50:.4f} per request\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "1df48bc4771c49ee", - "metadata": {}, - "source": [ - "### The Difference in LLM Responses\n", - "\n", - "Let's see how context quality affects the actual responses:" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "49a4d41f673b11a8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:38:55 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", - "❌ RESPONSE WITH POOR CONTEXT:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "It appears that there are no specific machine learning courses listed in the current course offerings. The available courses primarily focus on mathematics and statistics, particularly in calculus and data science. If you are interested in machine learning, you might want to consider foundational courses in statistics and data structures, as these are often prerequisites for more advanced machine learning courses. \n", - "\n", - "Would you like more information on any of the available courses?\n", - "\n" - ] - } - ], - "source": [ - "# Test with poor context\n", - "messages_poor = [\n", - " SystemMessage(\n", - " content=f\"\"\"You are a Redis University course advisor.\n", - "\n", - "Available Courses:\n", - "{poor_context}\n", - "\n", - "Help students find relevant courses.\"\"\"\n", - " ),\n", - " HumanMessage(content=query),\n", - "]\n", - "\n", - "response_poor = llm.invoke(messages_poor)\n", - "\n", - "print(\n", - " f\"\"\"❌ RESPONSE WITH POOR CONTEXT:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "{response_poor.content}\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "b1d43f264c681b61", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12:39:03 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", - "✅ RESPONSE WITH WELL-ENGINEERED CONTEXT:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "The available machine learning course is:\n", - "\n", - "**CS007: Machine Learning (advanced)**\n", - "- **Description:** Introduction to machine learning algorithms and applications. Supervised and unsupervised learning, neural networks.\n", - "- **Department:** Computer Science\n", - "- **Credits:** 4\n", - "- **Format:** Hybrid\n", - "- **Prerequisites:** None\n", - "\n", - "If you're looking for a course that covers machine learning fundamentals, this would be a great option!\n", - "\n" - ] - } - ], - "source": [ - "# Test with well-engineered context\n", - "messages_good = [\n", - " SystemMessage(\n", - " content=f\"\"\"You are a Redis University course advisor.\n", - "\n", - "Relevant Courses:\n", - "{well_engineered_context}\n", - "\n", - "Help students find the best course for their needs.\"\"\"\n", - " ),\n", - " HumanMessage(content=query),\n", - "]\n", - "\n", - "response_good = llm.invoke(messages_good)\n", - "\n", - "print(\n", - " f\"\"\"✅ RESPONSE WITH WELL-ENGINEERED CONTEXT:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "{response_good.content}\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "a7b99887a7d40e67", - "metadata": {}, - "source": [ - "### Key Takeaways: Why Context Engineering Matters\n", - "\n", - "From this example, you can see that well-engineered context:\n", - "\n", - "1. **Reduces Token Usage** - 50-70% fewer tokens through filtering and optimization\n", - "2. **Improves Relevance** - Semantic search finds the right courses\n", - "3. **Enhances Response Quality** - LLM can focus on relevant information\n", - "4. **Saves Money** - Fewer tokens = lower API costs\n", - "5. **Scales Better** - Works with thousands of courses, not just 10\n", - "\n", - "**The Engineering Mindset:**\n", - "- Context is data that requires engineering discipline\n", - "- Raw data ≠ Good context\n", - "- Systematic transformation: Extract → Clean → Transform → Optimize → Store\n", - "- Quality metrics: Relevance, Completeness, Efficiency, Accuracy\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "e48a057aaae7e8ab", - "metadata": {}, - "source": [ - "### What You'll Learn in the Next Notebook\n", - "\n", - "In **Notebook 2: Crafting and Optimizing Context**, you'll dive deep into:\n", - "\n", - "**Data Engineering for Context:**\n", - "- Systematic transformation pipeline (Extract → Clean → Transform → Optimize → Store)\n", - "- Three engineering approaches: RAG, Structured Views, Hybrid\n", - "- When to use each approach based on your requirements\n", - "\n", - "**Chunking as a Design Choice:**\n", - "- When to chunk vs. when whole-record embedding works better\n", - "- For structured data (courses, products): \"don't chunk\" is often best\n", - "- Four chunking strategies when needed, plus emerging approaches (Late Chunking, Contextual Retrieval)\n", - "\n", - "**Production Pipelines:**\n", - "- Three pipeline architectures (Request-Time, Batch, Event-Driven)\n", - "- Building production-ready context preparation workflows\n", - "- Quality optimization and testing\n", - "\n", - "**You'll learn to engineer context with the same rigor as any other data engineering problem.**\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "6d5da886e31e5b50", - "metadata": {}, - "source": [ - "## 🚀 What's Next?\n", - "\n", - "### 📊 Section 2, Notebook 2: Crafting and Optimizing Context\n", - "\n", - "Now that you understand RAG fundamentals and why context quality matters, the next notebook teaches you to engineer context with production-level rigor:\n", - "- Master data engineering workflows for context preparation\n", - "- Understand chunking as a design choice (not a default)\n", - "- Build production-ready context pipelines\n", - "- Optimize context quality with systematic approaches\n", - "\n", - "### 🧠 Section 3: Memory Systems for Context Engineering\n", - "\n", - "In this section, you built a RAG system that retrieves relevant information for each query. But there's a problem: **it doesn't remember previous conversations**.\n", - "\n", - "In Section 3, you'll add memory to your RAG system:\n", - "- **Working Memory:** Track conversation history within a session\n", - "- **Long-term Memory:** Remember user preferences across sessions\n", - "- **LangGraph Integration:** Manage stateful workflows with checkpointing\n", - "- **Redis Agent Memory Server:** Automatic memory extraction and retrieval\n", - "\n", - "### 🤖 Section 4: Tool Use and Agents\n", - "\n", - "After adding memory, you'll transform your RAG system into a full agent:\n", - "- **Tool Calling:** Let the AI use functions (search, enroll, check prerequisites)\n", - "- **LangGraph State Management:** Orchestrate complex multi-step workflows\n", - "- **Agent Reasoning:** Plan and execute multi-step tasks\n", - "- **Production Patterns:** Error handling, retries, and monitoring\n", - "\n", - "### The Journey\n", - "\n", - "```\n", - "Section 1: Context Engineering Fundamentals\n", - " ↓\n", - "Section 2, NB1: RAG Fundamentals ← You are here\n", - " ↓\n", - "Section 2, NB2: Crafting and Optimizing Context ← Next\n", - " ↓\n", - "Section 3: Memory Systems for Context Engineering\n", - " ↓\n", - "Section 4: Tool Use and Agents (Complete System)\n", - "```\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "bb63ec59713eebcf", - "metadata": {}, - "source": [ - "## 💪 Practice Exercises\n", - "\n", - "Try these exercises to deepen your understanding:\n", - "\n", - "**Exercise 1: Custom Filters**\n", - "- Modify the RAG query to filter by specific departments\n", - "- Try combining multiple filters (difficulty + format + department)\n", - "\n", - "**Exercise 2: Adjust Retrieval**\n", - "- Experiment with different `top_k` values (1, 3, 5, 10)\n", - "- Observe how response quality changes with more/fewer retrieved courses\n", - "\n", - "**Exercise 3: Context Optimization**\n", - "- Modify the `assemble_context` function to include more/less detail\n", - "- Measure token usage and response quality trade-offs\n", - "\n", - "**Exercise 4: Different Domains**\n", - "- Generate courses for a different domain (e.g., healthcare, finance)\n", - "- Ingest and test RAG with your custom data\n", - "\n", - "**Exercise 5: Evaluation**\n", - "- Create test queries with expected results\n", - "- Measure retrieval accuracy (are the right courses retrieved?)\n", - "- Measure generation quality (are responses helpful and accurate?)\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "89b2ee5474515589", - "metadata": {}, - "source": [ - "## 📝 Summary\n", - "\n", - "You've built a complete RAG system that:\n", - "- ✅ Generates and ingests course data with vector embeddings\n", - "- ✅ Performs semantic search to find relevant courses\n", - "- ✅ Assembles context from multiple sources (system + user + retrieved)\n", - "- ✅ Generates personalized responses using LLMs\n", - "- ✅ Handles different query types and user profiles\n", - "\n", - "This RAG system is the foundation for the advanced topics in Sections 3 and 4. You'll build on this exact code to add memory, tools, and full agent capabilities.\n", - "\n", - "**Great work!** You've mastered Retrieved Context and built a production-ready RAG pipeline. 🎉\n", - "\n", - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "### **RAG and Vector Search**\n", - "- [Retrieval-Augmented Generation Paper](https://arxiv.org/abs/2005.11401) - Original RAG paper by Facebook AI\n", - "- [Redis Vector Similarity Search](https://redis.io/docs/stack/search/reference/vectors/) - Official Redis VSS documentation\n", - "- [RedisVL Documentation](https://redisvl.com/) - Redis Vector Library for Python\n", - "- [LangChain RAG Tutorial](https://python.langchain.com/docs/tutorials/rag/) - Building RAG applications\n", - "\n", - "### **Embeddings and Semantic Search**\n", - "- [OpenAI Embeddings Guide](https://platform.openai.com/docs/guides/embeddings) - Understanding text embeddings\n", - "- [Sentence Transformers](https://www.sbert.net/) - Open-source embedding models\n", - "- [HNSW Algorithm](https://arxiv.org/abs/1603.09320) - Hierarchical Navigable Small World graphs\n", - "\n", - "### **LangChain and Redis Integration**\n", - "- [LangChain Documentation](https://python.langchain.com/docs/get_started/introduction) - Framework overview\n", - "- [LangChain Redis Integration](https://python.langchain.com/docs/integrations/vectorstores/redis/) - Using Redis with LangChain\n", - "- [Redis Python Client](https://redis-py.readthedocs.io/) - redis-py documentation\n", - "\n", - "### **Advanced RAG Techniques**\n", - "- [Advanced RAG Patterns](https://blog.langchain.dev/deconstructing-rag/) - LangChain blog on RAG optimization\n", - "- [Advanced Search with RedisVL](https://docs.redisvl.com/en/latest/user_guide/11_advanced_queries.html) - Vector, Hybrid, Text, and Keyword Search\n", - "- [RAG Evaluation](https://arxiv.org/abs/2309.15217) - Measuring RAG system performance\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ff96707ebbaf4026", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.7" - }, - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "state": { - "44f4e550ae25493c87d3f019fa4d508a": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "95f611b8009247979a136344651bdcba": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "b3d340a04fe34b818e963ed2ca23921c": { - "model_module": "@jupyter-widgets/output", - "model_module_version": "1.0.0", - "model_name": "OutputModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/output", - "_model_module_version": "1.0.0", - "_model_name": "OutputModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/output", - "_view_module_version": "1.0.0", - "_view_name": "OutputView", - "layout": "IPY_MODEL_95f611b8009247979a136344651bdcba", - "msg_id": "", - "outputs": [ - { - "data": { - "text/html": "
Ingesting courses... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  98% 0:00:01\n
\n", - "text/plain": "\u001b[32mIngesting courses...\u001b[0m \u001b[38;2;249;38;114m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[38;5;237m╺\u001b[0m \u001b[35m 98%\u001b[0m \u001b[36m0:00:01\u001b[0m\n" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "tabbable": null, - "tooltip": null - } - }, - "fb5d10f8b22e46beacce3a9679df23ad": { - "model_module": "@jupyter-widgets/output", - "model_module_version": "1.0.0", - "model_name": "OutputModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/output", - "_model_module_version": "1.0.0", - "_model_name": "OutputModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/output", - "_view_module_version": "1.0.0", - "_view_name": "OutputView", - "layout": "IPY_MODEL_44f4e550ae25493c87d3f019fa4d508a", - "msg_id": "", - "outputs": [ - { - "data": { - "text/html": "
Ingesting majors... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━   0% -:--:--\n
\n", - "text/plain": "\u001b[34mIngesting majors...\u001b[0m \u001b[38;5;237m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[35m 0%\u001b[0m \u001b[36m-:--:--\u001b[0m\n" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "tabbable": null, - "tooltip": null - } - } - }, - "version_major": 2, - "version_minor": 0 - } - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb b/notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb deleted file mode 100644 index 38c4fc0..0000000 --- a/notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb +++ /dev/null @@ -1,5026 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "f2abf8d931d184b7", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# Crafting and Optimizing Context\n", - "\n", - "## From RAG Basics to Practical Context Engineering\n", - "\n", - "In the previous notebook, you built a working RAG system and saw why context quality matters. Now you'll learn to engineer context with professional-level rigor.\n", - "\n", - "**What makes context \"good\"?**\n", - "\n", - "This notebook teaches you that **context engineering is real engineering** - it requires the same rigor, analysis, and deliberate decision-making as any other engineering discipline. Context isn't just \"data you feed to an LLM\" - it requires thoughtful preparation, quality assessment, and optimization.\n", - "\n", - "## What You'll Learn\n", - "\n", - "**The Engineering Mindset:**\n", - "- Why context quality matters (concrete impact on accuracy, relevance, cost)\n", - "- The transformation workflow: Raw Data → Engineered Context → Quality Responses\n", - "- Contrasts between naive and engineered approaches\n", - "\n", - "**Data Engineering for Context:**\n", - "- Systematic transformation: Extract → Clean → Transform → Optimize → Store\n", - "- Engineering decisions based on YOUR domain requirements\n", - "- When to use different approaches (RAG, Structured Views, Hybrid)\n", - "\n", - "**Introduction to Chunking:**\n", - "- When does your data need chunking? (Critical first question)\n", - "- Different chunking strategies and their trade-offs\n", - "- How to choose based on YOUR data characteristics\n", - "\n", - "**Context Preparation Pipelines:**\n", - "- Three pipeline architectures (Request-Time, Batch, Event-Driven)\n", - "- How to choose based on YOUR constraints\n", - "- Building reusable context preparation workflows\n", - "\n", - "**Time to complete:** 90-105 minutes\n", - "\n", - "---\n", - "\n", - "## Prerequisites\n", - "\n", - "- Completed Section 2, Notebook 1 (RAG Fundamentals and Implementation)\n", - "- Redis 8 running locally\n", - "- OpenAI API key set\n", - "- Understanding of RAG basics and vector embeddings\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "82d806e0faab3793", - "metadata": {}, - "source": [ - "## Part 1: Context is Data - and Data Requires Engineering\n", - "\n", - "### The Naive Approach (What NOT to Do)\n", - "\n", - "Let's start by seeing what happens when you treat context as \"just data\" without engineering discipline.\n", - "\n", - "**Scenario:** A student asks \"What machine learning courses are available?\"\n", - "\n", - "Let's see what happens with a naive approach:" - ] - }, - { - "cell_type": "markdown", - "id": "e8c09fc7b40bee0a", - "metadata": {}, - "source": [ - "### Setup" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "e35c7eed6e9e9574", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:13.405597Z", - "start_time": "2025-11-04T21:16:13.396647Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:18.074137Z", - "iopub.status.busy": "2025-11-05T13:43:18.073930Z", - "iopub.status.idle": "2025-11-05T13:43:18.085939Z", - "shell.execute_reply": "2025-11-05T13:43:18.085211Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment variables loaded\n" - ] - } - ], - "source": [ - "import os\n", - "import sys\n", - "\n", - "from dotenv import load_dotenv\n", - "\n", - "# Load environment variables\n", - "load_dotenv()\n", - "\n", - "# Verify required environment variables\n", - "required_vars = [\"OPENAI_API_KEY\"]\n", - "missing_vars = [var for var in required_vars if not os.getenv(var)]\n", - "\n", - "if missing_vars:\n", - " print(\n", - " f\"\"\"⚠️ Missing required environment variables: {', '.join(missing_vars)}\n", - "\n", - "Please create a .env file with:\n", - "OPENAI_API_KEY=your_openai_api_key\n", - "REDIS_URL=redis://localhost:6379\n", - "\"\"\"\n", - " )\n", - " sys.exit(1)\n", - "\n", - "REDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379\")\n", - "print(\"✅ Environment variables loaded\")" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "26d00b06cb8ec2e8", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:16.311922Z", - "start_time": "2025-11-04T21:16:13.740863Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:18.087959Z", - "iopub.status.busy": "2025-11-05T13:43:18.087809Z", - "iopub.status.idle": "2025-11-05T13:43:19.949380Z", - "shell.execute_reply": "2025-11-05T13:43:19.948960Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:19 redisvl.index.index INFO Index already exists, not overwriting.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Dependencies loaded" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "import asyncio\n", - "\n", - "# Import dependencies\n", - "import json\n", - "from typing import Any, Dict, List\n", - "\n", - "import redis\n", - "import tiktoken\n", - "from langchain_core.messages import HumanMessage, SystemMessage\n", - "from langchain_openai import ChatOpenAI\n", - "from redis_context_course import CourseManager, redis_config\n", - "\n", - "# Initialize\n", - "course_manager = CourseManager()\n", - "redis_client = redis.from_url(REDIS_URL, decode_responses=True)\n", - "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0)\n", - "\n", - "# Token counter\n", - "encoding = tiktoken.encoding_for_model(\"gpt-4o\")\n", - "\n", - "\n", - "def count_tokens(text: str) -> int:\n", - " return len(encoding.encode(text))\n", - "\n", - "\n", - "print(\"✅ Dependencies loaded\")" - ] - }, - { - "cell_type": "markdown", - "id": "a30bf7641e7c2bb4", - "metadata": {}, - "source": [ - "### Naive Approach: Dump Everything\n", - "\n", - "The simplest approach is to include all course data in every request:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "3f6674fd4ec1bbcf", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:17.334336Z", - "start_time": "2025-11-04T21:16:16.832182Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:19.950745Z", - "iopub.status.busy": "2025-11-05T13:43:19.950638Z", - "iopub.status.idle": "2025-11-05T13:43:20.435566Z", - "shell.execute_reply": "2025-11-05T13:43:20.434886Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:20 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Naive Approach Results:\n", - " Courses included: 10\n", - " Token count: 1,689\n", - " Estimated cost per request: $0.0042\n", - "\n", - " For 100 courses, this would be ~16,890 tokens!\n", - "\n", - "\n", - "📄 Sample of raw JSON context:\n", - "[\n", - " {\n", - " \"id\": \"course_catalog:01K9A41NZ4FAYCBY18A6Z1Y86H\",\n", - " \"course_code\": \"CS004\",\n", - " \"title\": \"Database Systems\",\n", - " \"description\": \"Design and implementation of database systems. SQL, normalization, transactions, and database administration.\",\n", - " \"department\": \"Computer Science\",\n", - " \"credits\": 3,\n", - " \"difficulty_level\": \"intermediate\",\n", - " \"format\": \"online\",\n", - " \"instructor\": \"John Zamora\",\n", - " \"prerequisites\": [],\n", - " \"created_at\": \"2025-11-05 08:43:20.429564\",\n", - " \"updated_at\": \"2...\n" - ] - } - ], - "source": [ - "# Naive Approach: Get all courses and dump as JSON\n", - "all_courses = await course_manager.get_all_courses()\n", - "\n", - "# Convert to raw JSON (what many developers do first)\n", - "raw_context = json.dumps(\n", - " [\n", - " {\n", - " \"id\": c.id,\n", - " \"course_code\": c.course_code,\n", - " \"title\": c.title,\n", - " \"description\": c.description,\n", - " \"department\": c.department,\n", - " \"credits\": c.credits,\n", - " \"difficulty_level\": c.difficulty_level.value,\n", - " \"format\": c.format.value,\n", - " \"instructor\": c.instructor,\n", - " \"prerequisites\": (\n", - " [p.course_code for p in c.prerequisites] if c.prerequisites else []\n", - " ),\n", - " \"created_at\": str(c.created_at) if hasattr(c, \"created_at\") else None,\n", - " \"updated_at\": str(c.updated_at) if hasattr(c, \"updated_at\") else None,\n", - " }\n", - " for c in all_courses[:10] # Just first 10 for demo\n", - " ],\n", - " indent=2,\n", - ")\n", - "\n", - "token_count = count_tokens(raw_context)\n", - "\n", - "print(\n", - " f\"\"\"📊 Naive Approach Results:\n", - " Courses included: {len(all_courses[:10])}\n", - " Token count: {token_count:,}\n", - " Estimated cost per request: ${(token_count / 1_000_000) * 2.50:.4f}\n", - "\n", - " For 100 courses, this would be ~{token_count * 10:,} tokens!\n", - "\"\"\"\n", - ")\n", - "\n", - "# Show a sample\n", - "print(\"\\n📄 Sample of raw JSON context:\")\n", - "print(raw_context[:500] + \"...\")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "1f12aa3d9a92a5cf", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:17.347983Z", - "start_time": "2025-11-04T21:16:17.344365Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:20.437326Z", - "iopub.status.busy": "2025-11-05T13:43:20.437167Z", - "iopub.status.idle": "2025-11-05T13:43:20.441839Z", - "shell.execute_reply": "2025-11-05T13:43:20.441287Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Database Systems',\n", - " 'Web Development',\n", - " 'Web Development',\n", - " 'Web Development',\n", - " 'Web Development',\n", - " 'Linear Algebra',\n", - " 'Linear Algebra',\n", - " 'Linear Algebra',\n", - " 'Linear Algebra',\n", - " 'Linear Algebra',\n", - " 'Calculus I',\n", - " 'Calculus I',\n", - " 'Calculus I',\n", - " 'Calculus I',\n", - " 'Calculus I',\n", - " 'Marketing Strategy',\n", - " 'Marketing Strategy',\n", - " 'Marketing Strategy',\n", - " 'Marketing Strategy',\n", - " 'Marketing Strategy',\n", - " 'Marketing Strategy',\n", - " 'Marketing Strategy',\n", - " 'Cognitive Psychology',\n", - " 'Cognitive Psychology',\n", - " 'Cognitive Psychology',\n", - " 'Cognitive Psychology',\n", - " 'Cognitive Psychology',\n", - " 'Cognitive Psychology',\n", - " 'Cognitive Psychology',\n", - " 'Data Structures and Algorithms',\n", - " 'Principles of Management',\n", - " 'Principles of Management',\n", - " 'Principles of Management',\n", - " 'Introduction to Psychology',\n", - " 'Introduction to Psychology',\n", - " 'Introduction to Psychology',\n", - " 'Data Visualization',\n", - " 'Data Visualization',\n", - " 'Data Visualization',\n", - " 'Data Visualization',\n", - " 'Machine Learning',\n", - " 'Introduction to Programming',\n", - " 'Introduction to Programming',\n", - " 'Introduction to Programming',\n", - " 'Statistics for Data Science',\n", - " 'Statistics for Data Science',\n", - " 'Statistics for Data Science',\n", - " 'Statistics for Data Science',\n", - " 'Statistics for Data Science',\n", - " 'Statistics for Data Science']" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[course.title for course in all_courses]" - ] - }, - { - "cell_type": "markdown", - "id": "afdb7ba88280036", - "metadata": {}, - "source": [ - "### Test the Naive Approach" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a9cbb2ba9a1070a", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:20.589130Z", - "start_time": "2025-11-04T21:16:19.252966Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:20.443317Z", - "iopub.status.busy": "2025-11-05T13:43:20.443202Z", - "iopub.status.idle": "2025-11-05T13:43:22.866201Z", - "shell.execute_reply": "2025-11-05T13:43:22.865381Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:22 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🤖 Query: \"What machine learning courses are available?\"\n", - "\n", - "Response:\n", - "Currently, there are no machine learning courses listed in the available course catalog. If you are interested in machine learning, you might consider exploring related courses such as \"Database Systems\" or \"Linear Algebra,\" which can provide foundational knowledge useful in the field of machine learning.\n", - "\n" - ] - } - ], - "source": [ - "# Test with a real query\n", - "query = \"What machine learning courses are available?\"\n", - "\n", - "messages = [\n", - " SystemMessage(\n", - " content=f\"\"\"You are a Redis University course advisor.\n", - "\n", - "Available Courses:\n", - "{raw_context}\n", - "\n", - "Help students find relevant courses.\"\"\"\n", - " ),\n", - " HumanMessage(content=query),\n", - "]\n", - "\n", - "response = llm.invoke(messages)\n", - "\n", - "print(\n", - " f\"\"\"🤖 Query: \"{query}\"\n", - "\n", - "Response:\n", - "{response.content}\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "1e999b3edc323c9a", - "metadata": {}, - "source": [ - "### Problems with the Naive Approach\n", - "\n", - "As discussed in previous notebooks, this approach has several problems:\n", - "\n", - "1. **Excessive Token Usage**\n", - " - 10 courses = ~1,703 tokens\n", - " - 100 courses would be ~17,030 tokens\n", - "\n", - "\n", - "2. **Raw JSON is Inefficient**\n", - " - Includes internal fields (IDs, timestamps, created_at, updated_at)\n", - " - Verbose formatting (indentation, field names repeated)\n", - "\n", - "\n", - "3. **No Filtering**\n", - " - Student asked about ML, but got all courses, even irrelevant ones\n", - " - **Dilutes relevant information with noise**\n", - "\n", - "\n", - "4. **Poor Response Quality**\n", - " - Generic responses (\"We have many courses...\")\n", - " - May miss the most relevant courses\n", - " - Can't provide personalized recommendations\n", - "\n", - "\n", - "5. **Not Scalable**\n", - " - What if you have 1,000 courses? 10,000?\n", - " - What if courses change daily?\n", - " - Requires code changes to update\n", - "\n", - "**Therefore, the goal is not only to give the LLM \"all the data\" - it's to *give it the useful data.***" - ] - }, - { - "cell_type": "markdown", - "id": "803dbc94b12fa6f8", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## The Engineering Mindset\n", - "\n", - "Context is data that flows through a pipeline. Like any data engineering problem, it requires:\n", - "\n", - "### 1. Requirements Analysis\n", - "- What is the intended use case?\n", - "- What queries will users ask?\n", - "- What information do they need?\n", - "- What constraints exist (token budget, latency, cost)?\n", - "\n", - "### 2. Data Transformation\n", - "- Raw data → Cleaned data → Structured data → LLM-optimized context\n", - "\n", - "### 3. Quality Metrics\n", - "- How do we measure if context is \"good\"?\n", - "- Relevance, completeness, efficiency, accuracy\n", - "\n", - "### 4. Testing and Iteration\n", - "- Test with real queries\n", - "- Measure quality metrics\n", - "- Iterate based on results\n", - "\n", - "**The Engineering Question:** \"How do we transform raw course data into high-quality context that produces accurate, relevant, efficient responses?\"" - ] - }, - { - "cell_type": "markdown", - "id": "9730c35637eb3303", - "metadata": {}, - "source": [ - "### Three Engineering Approaches\n", - "\n", - "Let's compare three approaches with concrete examples:\n", - "\n", - "| Approach | Description | Token Usage | Response Quality | Maintenance | Verdict |\n", - "|----------|-------------|-------------|------------------|-------------|---------|\n", - "| **Naive** | Include all raw data | 50K tokens | Poor (generic) | Easy | ❌ Not practical |\n", - "| **RAG** | Semantic search for relevant courses | 3K tokens | Good (relevant) | Moderate | ✅ Good for most cases |\n", - "| **Structured Views** | Pre-compute LLM-optimized summaries | 2K tokens | Excellent (overview + details) | Higher | ✅ Best for real-world use |\n", - "| **Hybrid** | Structured view + RAG | 5K tokens | Excellent (best of both) | Higher | ✅ Best for real-world use |\n", - "\n", - "Let's implement each approach and compare them." - ] - }, - { - "cell_type": "markdown", - "id": "e825e363289a6d65", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## Part 2: Data Engineering Workflow - From Raw to Optimized\n", - "\n", - "### The Data Engineering Pipeline\n", - "\n", - "Context preparation follows a systematic workflow:\n", - "\n", - "```\n", - "Raw Data (Database/API)\n", - " ↓\n", - "[Step 1: Extract] - Get the data\n", - " ↓\n", - "[Step 2: Clean] - Remove noise, fix inconsistencies\n", - " ↓\n", - "[Step 3: Transform] - Structure for LLM consumption\n", - " ↓\n", - "[Step 4: Optimize] - Reduce tokens, improve clarity\n", - " ↓\n", - "[Step 5: Store] - Vector DB, cache, or pre-compute\n", - " ↓\n", - "Engineered Context (Ready for LLM)\n", - "```\n", - "\n", - "Let's walk through this pipeline with a real example." - ] - }, - { - "cell_type": "markdown", - "id": "6055906b662e63d", - "metadata": {}, - "source": [ - "### Step 1: Extract (Raw Data)\n", - "\n", - "First, let's look at what raw course data looks like:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "34d43d9871aa5b9e", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:22.016096Z", - "start_time": "2025-11-04T21:16:22.011996Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.868531Z", - "iopub.status.busy": "2025-11-05T13:43:22.868335Z", - "iopub.status.idle": "2025-11-05T13:43:22.873158Z", - "shell.execute_reply": "2025-11-05T13:43:22.872458Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📄 Step 1: Raw Database Record\n", - "================================================================================\n", - "{\n", - " \"id\": \"course_catalog:01K9A41NZ4FAYCBY18A6Z1Y86H\",\n", - " \"course_code\": \"CS004\",\n", - " \"title\": \"Database Systems\",\n", - " \"description\": \"Design and implementation of database systems. SQL, normalization, transactions, and database administration.\",\n", - " \"department\": \"Computer Science\",\n", - " \"credits\": 3,\n", - " \"difficulty_level\": \"intermediate\",\n", - " \"format\": \"online\",\n", - " \"instructor\": \"John Zamora\",\n", - " \"prerequisites\": [],\n", - " \"created_at\": \"2025-11-05 08:43:20.429564\",\n", - " \"updated_at\": \"2025-11-05 08:43:20.429571\"\n", - "}\n", - "================================================================================\n", - "\n", - "📊 Token count: 161\n" - ] - } - ], - "source": [ - "# Get a sample course\n", - "sample_course = all_courses[0]\n", - "\n", - "# Show raw database record\n", - "raw_record = {\n", - " \"id\": sample_course.id,\n", - " \"course_code\": sample_course.course_code,\n", - " \"title\": sample_course.title,\n", - " \"description\": sample_course.description,\n", - " \"department\": sample_course.department,\n", - " \"credits\": sample_course.credits,\n", - " \"difficulty_level\": sample_course.difficulty_level.value,\n", - " \"format\": sample_course.format.value,\n", - " \"instructor\": sample_course.instructor,\n", - " \"prerequisites\": (\n", - " [p.course_code for p in sample_course.prerequisites]\n", - " if sample_course.prerequisites\n", - " else []\n", - " ),\n", - " \"created_at\": (\n", - " str(sample_course.created_at)\n", - " if hasattr(sample_course, \"created_at\")\n", - " else \"2024-01-15T08:30:00Z\"\n", - " ),\n", - " \"updated_at\": (\n", - " str(sample_course.updated_at)\n", - " if hasattr(sample_course, \"updated_at\")\n", - " else \"2024-09-01T14:22:00Z\"\n", - " ),\n", - "}\n", - "\n", - "raw_json = json.dumps(raw_record, indent=2)\n", - "raw_tokens = count_tokens(raw_json)\n", - "\n", - "print(\"📄 Step 1: Raw Database Record\")\n", - "print(\"=\" * 80)\n", - "print(raw_json)\n", - "print(\"=\" * 80)\n", - "print(f\"\\n📊 Token count: {raw_tokens}\")" - ] - }, - { - "cell_type": "markdown", - "id": "c736e4af9c549cec", - "metadata": {}, - "source": [ - "Issues with above:\n", - " - Internal fields (IDs, timestamps) waste tokens\n", - " - Verbose JSON formatting\n", - " - Prerequisites are codes, not human-readable\n", - " - No structure for LLM consumption" - ] - }, - { - "cell_type": "markdown", - "id": "91c9d3b83e4a304a", - "metadata": {}, - "source": [ - "### Step 2: Clean (Remove Noise)\n", - "\n", - "Remove fields that don't help the LLM answer user queries:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "b17d341ad154ff9c", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:23.517460Z", - "start_time": "2025-11-04T21:16:23.513732Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.874974Z", - "iopub.status.busy": "2025-11-05T13:43:22.874828Z", - "iopub.status.idle": "2025-11-05T13:43:22.878494Z", - "shell.execute_reply": "2025-11-05T13:43:22.877880Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📄 Step 2: Cleaned Record\n", - "================================================================================\n", - "{\n", - " \"course_code\": \"CS004\",\n", - " \"title\": \"Database Systems\",\n", - " \"description\": \"Design and implementation of database systems. SQL, normalization, transactions, and database administration.\",\n", - " \"department\": \"Computer Science\",\n", - " \"credits\": 3,\n", - " \"difficulty_level\": \"intermediate\",\n", - " \"format\": \"online\",\n", - " \"instructor\": \"John Zamora\",\n", - " \"prerequisites\": []\n", - "}\n", - "================================================================================\n", - "\n", - "📊 Token count: 89 (saved 72 tokens, 44.7% reduction)\n" - ] - } - ], - "source": [ - "# Step 2: Clean - Remove internal fields\n", - "cleaned_record = {\n", - " \"course_code\": sample_course.course_code,\n", - " \"title\": sample_course.title,\n", - " \"description\": sample_course.description,\n", - " \"department\": sample_course.department,\n", - " \"credits\": sample_course.credits,\n", - " \"difficulty_level\": sample_course.difficulty_level.value,\n", - " \"format\": sample_course.format.value,\n", - " \"instructor\": sample_course.instructor,\n", - " \"prerequisites\": (\n", - " [p.course_code for p in sample_course.prerequisites]\n", - " if sample_course.prerequisites\n", - " else []\n", - " ),\n", - "}\n", - "\n", - "cleaned_json = json.dumps(cleaned_record, indent=2)\n", - "cleaned_tokens = count_tokens(cleaned_json)\n", - "\n", - "print(\"📄 Step 2: Cleaned Record\")\n", - "print(\"=\" * 80)\n", - "print(cleaned_json)\n", - "print(\"=\" * 80)\n", - "print(\n", - " f\"\\n📊 Token count: {cleaned_tokens} (saved {raw_tokens - cleaned_tokens} tokens, {((raw_tokens - cleaned_tokens) / raw_tokens * 100):.1f}% reduction)\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "e0245185126ebc8d", - "metadata": {}, - "source": [ - "\n", - "Improvements:\n", - " - Removed id, created_at, updated_at\n", - " - Still has all information needed to answer queries\n", - "\n", - "Still has minor problems:\n", - " - JSON formatting is verbose (this is a *minor* issue as LLMs can handle it; however)\n", - " - Prerequisites are still codes\n" - ] - }, - { - "cell_type": "markdown", - "id": "916054c3caf3246f", - "metadata": {}, - "source": [ - "### Step 3: Transform (Structure for LLM)\n", - "\n", - "Convert to a format optimized for LLM consumption:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "ce586982d559bf6", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:24.995047Z", - "start_time": "2025-11-04T21:16:24.990842Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.879993Z", - "iopub.status.busy": "2025-11-05T13:43:22.879888Z", - "iopub.status.idle": "2025-11-05T13:43:22.883531Z", - "shell.execute_reply": "2025-11-05T13:43:22.883057Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📄 Step 3: Transformed to LLM-Friendly Format\n", - "================================================================================\n", - "CS004: Database Systems\n", - "Department: Computer Science\n", - "Credits: 3\n", - "Level: intermediate\n", - "Format: online\n", - "Instructor: John Zamora\n", - "Description: Design and implementation of database systems. SQL, normalization, transactions, and database administration.\n", - " \n", - "================================================================================\n", - "\n", - "📊 Token count: 50 (saved 39 tokens, 43.8% reduction)\n" - ] - } - ], - "source": [ - "# Step 3: Transform - Convert to LLM-friendly format\n", - "\n", - "\n", - "def transform_course_to_text(course) -> str:\n", - " \"\"\"Transform course object to LLM-optimized text format.\"\"\"\n", - "\n", - " # Build prerequisites text\n", - " prereq_text = \"\"\n", - " if course.prerequisites:\n", - " prereq_codes = [p.course_code for p in course.prerequisites]\n", - " prereq_text = f\"\\nPrerequisites: {', '.join(prereq_codes)}\"\n", - "\n", - " # Build course text\n", - " course_text = f\"\"\"{course.course_code}: {course.title}\n", - "Department: {course.department}\\nCredits: {course.credits}\\nLevel: {course.difficulty_level.value}\\nFormat: {course.format.value}\n", - "Instructor: {course.instructor}{prereq_text}\n", - "Description: {course.description}\n", - " \"\"\"\n", - "\n", - " return course_text\n", - "\n", - "\n", - "transformed_text = transform_course_to_text(sample_course)\n", - "transformed_tokens = count_tokens(transformed_text)\n", - "\n", - "print(\"📄 Step 3: Transformed to LLM-Friendly Format\")\n", - "print(\"=\" * 80)\n", - "print(transformed_text)\n", - "print(\"=\" * 80)\n", - "print(\n", - " f\"\\n📊 Token count: {transformed_tokens} (saved {cleaned_tokens - transformed_tokens} tokens, {((cleaned_tokens - transformed_tokens) / cleaned_tokens * 100):.1f}% reduction)\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "f21134e639bb161", - "metadata": {}, - "source": [ - "\n", - "✅ Improvements:\n", - " - Natural text format with the correct metadata\n", - " - Clear structure with labels\n", - " - No JSON overhead (brackets, quotes, commas)\n", - "\n", - "**Note:** In case the description is too long, we can apply compression techniques such as summarization to keep the description within a desired token limit. Section 3 will cover compression in more detail.\n" - ] - }, - { - "cell_type": "markdown", - "id": "b29d61a0bd31afaa", - "metadata": {}, - "source": [ - "### Step 4: Optimize (Further Reduce Tokens)\n", - "\n", - "For even more efficiency, we can create a summarized version:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "d542adf08de72190", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:26.480662Z", - "start_time": "2025-11-04T21:16:26.477068Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.885015Z", - "iopub.status.busy": "2025-11-05T13:43:22.884900Z", - "iopub.status.idle": "2025-11-05T13:43:22.888179Z", - "shell.execute_reply": "2025-11-05T13:43:22.887609Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📄 Step 4: Optimized (Ultra-Compact)\n", - "================================================================================\n", - "CS004: Database Systems - Design and implementation of database systems. SQL, normalization, transactions, and database admini...\n", - "================================================================================\n", - "\n", - "📊 Token count: 24 (saved 26 tokens, 52.0% reduction)\n" - ] - } - ], - "source": [ - "# Step 4: Optimize - Create ultra-compact version\n", - "# TODO: Maybe use summarization here? Maybe for that we need a longer description or some other metadata?\n", - "\n", - "def optimize_course_text(course) -> str:\n", - " \"\"\"Create ultra-compact course description.\"\"\"\n", - " prereqs = (\n", - " f\" (Prereq: {', '.join([p.course_code for p in course.prerequisites])})\"\n", - " if course.prerequisites\n", - " else \"\"\n", - " )\n", - " return (\n", - " f\"{course.course_code}: {course.title} - {course.description[:100]}...{prereqs}\"\n", - " )\n", - "\n", - "\n", - "optimized_text = optimize_course_text(sample_course)\n", - "optimized_tokens = count_tokens(optimized_text)\n", - "\n", - "print(\"📄 Step 4: Optimized (Ultra-Compact)\")\n", - "print(\"=\" * 80)\n", - "print(optimized_text)\n", - "print(\"=\" * 80)\n", - "print(\n", - " f\"\\n📊 Token count: {optimized_tokens} (saved {transformed_tokens - optimized_tokens} tokens, {((transformed_tokens - optimized_tokens) / transformed_tokens * 100):.1f}% reduction)\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "f034058ec3845a04", - "metadata": {}, - "source": [ - "Improvements:\n", - " - Truncated description to 100 chars\n", - " - Removed metadata (instructor, format, credits)\n", - "\n", - "Trade-off:\n", - " - Lost some detail (may need for specific queries)\n", - " - Best for overview/catalog views\n", - "\n", - "**Note:** This is just an example of what you can do to be more efficient. This is where you have to be creative and engineer based on the usercase and requirements." - ] - }, - { - "cell_type": "markdown", - "id": "5bcd00f8a8fc98f7", - "metadata": {}, - "source": [ - "### Step 5: Store (Choose Storage Strategy)\n", - "\n", - "Now we need to decide HOW to store this engineered context:\n", - "\n", - "**Option 1: Vector Database (RAG)**\n", - "- Store transformed text with embeddings\n", - "- Retrieve relevant courses at query time\n", - "- Good for: Large datasets, specific queries\n", - "\n", - "**Option 2: Pre-Computed Views**\n", - "- Create structured summaries ahead of time\n", - "- Store in Redis as cached views\n", - "- Good for: Common queries, overview information\n", - "\n", - "**Option 3: Hybrid**\n", - "- Combine both approaches\n", - "- Pre-compute catalog view + RAG for details\n", - "- Good for: Real-world systems\n", - "\n", - "Let's implement all three and compare." - ] - }, - { - "cell_type": "markdown", - "id": "261d1ca669115e9b", - "metadata": {}, - "source": [ - "### Summary: The Transformation Pipeline\n", - "\n", - "Let's see the complete transformation:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "dfae248ca80f0af4", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:39.408618Z", - "start_time": "2025-11-04T21:16:39.405135Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.889561Z", - "iopub.status.busy": "2025-11-05T13:43:22.889472Z", - "iopub.status.idle": "2025-11-05T13:43:22.892238Z", - "shell.execute_reply": "2025-11-05T13:43:22.891735Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "EXAMPLE PIPELINE SUMMARY\n", - "================================================================================\n", - "\n", - "Step 1: Raw Database Record\n", - " Token count: 161\n", - " Format: JSON with all fields\n", - "\n", - "Step 2: Cleaned Record\n", - " Token count: 89 (44.7% reduction)\n", - " Removed: Internal fields (IDs, timestamps)\n", - "\n", - "Step 3: Transformed to LLM Format\n", - " Token count: 50 (43.8% reduction from Step 2)\n", - " Format: Natural text, structured\n", - "\n", - "Step 4: Optimized (Ultra-Compact)\n", - " Token count: 24 (52.0% reduction from Step 3)\n", - " Format: Single line, truncated\n", - "\n", - "TOTAL REDUCTION: 161 → 24 tokens (85.1% reduction)\n", - "\n", - "================================================================================\n", - "\n", - "🎯 Key Insight:\n", - " Through systematic engineering, we reduced token usage by ~70%\n", - " while IMPROVING readability for the LLM!\n", - "================================================================================\n" - ] - } - ], - "source": [ - "print(\"=\" * 80)\n", - "print(\"EXAMPLE PIPELINE SUMMARY\")\n", - "print(\"=\" * 80)\n", - "\n", - "print(\n", - " f\"\"\"\n", - "Step 1: Raw Database Record\n", - " Token count: {raw_tokens}\n", - " Format: JSON with all fields\n", - "\n", - "Step 2: Cleaned Record\n", - " Token count: {cleaned_tokens} ({((raw_tokens - cleaned_tokens) / raw_tokens * 100):.1f}% reduction)\n", - " Removed: Internal fields (IDs, timestamps)\n", - "\n", - "Step 3: Transformed to LLM Format\n", - " Token count: {transformed_tokens} ({((cleaned_tokens - transformed_tokens) / cleaned_tokens * 100):.1f}% reduction from Step 2)\n", - " Format: Natural text, structured\n", - "\n", - "Step 4: Optimized (Ultra-Compact)\n", - " Token count: {optimized_tokens} ({((transformed_tokens - optimized_tokens) / transformed_tokens * 100):.1f}% reduction from Step 3)\n", - " Format: Single line, truncated\n", - "\n", - "TOTAL REDUCTION: {raw_tokens} → {optimized_tokens} tokens ({((raw_tokens - optimized_tokens) / raw_tokens * 100):.1f}% reduction)\n", - "\"\"\"\n", - ")\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"\\n🎯 Key Insight:\")\n", - "print(\" Through systematic engineering, we reduced token usage by ~70%\")\n", - "print(\" while IMPROVING readability for the LLM!\")\n", - "print(\"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "4fc3b3449d3d842a", - "metadata": {}, - "source": [ - "The key insight states that we reduced token usage.\n", - "\n", - "However, it should be noted that reduction is not the goal. The goal is to optimize the content and provide the most relevant information to the LLM." - ] - }, - { - "cell_type": "markdown", - "id": "7974af3948d4ec98", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## Part 3: Engineering Decision - When to Use Each Approach\n", - "\n", - "Now let's implement the three approaches and compare them with real queries.\n", - "\n", - "### Approach 1: RAG (Semantic Search)\n", - "\n", - "Retrieve only relevant courses using vector search:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "1552972433032e7a", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:40.200346Z", - "start_time": "2025-11-04T21:16:40.193910Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.893549Z", - "iopub.status.busy": "2025-11-05T13:43:22.893468Z", - "iopub.status.idle": "2025-11-05T13:43:22.900749Z", - "shell.execute_reply": "2025-11-05T13:43:22.900353Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "⚠️ Index 'course_index' not found. Please run Section 2 notebooks to create it.\n", - " For this demo, we'll simulate RAG results.\n" - ] - } - ], - "source": [ - "from redisvl.index import SearchIndex\n", - "from redisvl.query import VectorQuery\n", - "from redisvl.query.filter import Tag\n", - "\n", - "# Initialize vector search\n", - "index_name = \"course_index\"\n", - "\n", - "# Check if index exists, create if not\n", - "try:\n", - " index = SearchIndex.from_existing(index_name, redis_url=REDIS_URL)\n", - " print(f\"✅ Using existing index: {index_name}\")\n", - "except:\n", - " print(\n", - " f\"⚠️ Index '{index_name}' not found. Please run Section 2 notebooks to create it.\"\n", - " )\n", - " print(\" For this demo, we'll simulate RAG results.\")\n", - " index = None" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "a5ddc04a807cc174", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:40.589240Z", - "start_time": "2025-11-04T21:16:40.585751Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.901995Z", - "iopub.status.busy": "2025-11-05T13:43:22.901919Z", - "iopub.status.idle": "2025-11-05T13:43:22.905035Z", - "shell.execute_reply": "2025-11-05T13:43:22.904538Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 RAG Approach Results:\n", - " Query: \"What machine learning courses are available?\"\n", - " Courses retrieved: 5\n", - " Token count: 270\n", - "\n", - "📄 Context Preview:\n", - "CS003: Web Development\n", - "Department: Computer Science\n", - "Credits: 3\n", - "Level: intermediate\n", - "Format: in_person\n", - "Instructor: Cody Ayala\n", - "Description: Full-stack web development using modern frameworks. HTML, CSS, JavaScript, React, and backend APIs.\n", - " \n", - "\n", - "CS002: Web Development\n", - "Department: Computer Science\n", - "Credits: 3\n", - "Level: intermediate\n", - "Format: in_person\n", - "Instructor: Kimberly Robertson\n", - "Description: Full-stack web development using modern frameworks. HTML, CSS, JavaScript, React, and backend APIs.\n", - " \n", - "\n", - "CS008:...\n", - "\n" - ] - } - ], - "source": [ - "# Simulate RAG retrieval (in production, this would use vector search)\n", - "\n", - "\n", - "async def rag_approach(query: str, limit: int = 5) -> str:\n", - " \"\"\"Retrieve relevant courses using semantic search.\"\"\"\n", - "\n", - " # In production: Use vector search\n", - " # For demo: Filter courses by keyword matching\n", - " query_lower = query.lower()\n", - "\n", - " relevant_courses = []\n", - " for course in all_courses:\n", - " # Simple keyword matching (in production, use embeddings)\n", - " if any(\n", - " keyword in course.title.lower() or keyword in course.description.lower()\n", - " for keyword in [\"machine learning\", \"ml\", \"ai\", \"data science\", \"neural\"]\n", - " ):\n", - " relevant_courses.append(course)\n", - " if len(relevant_courses) >= limit:\n", - " break\n", - "\n", - " # Transform to LLM-friendly format\n", - " context = \"\\n\\n\".join([transform_course_to_text(c) for c in relevant_courses])\n", - " return context\n", - "\n", - "\n", - "# Test RAG approach\n", - "query = \"What machine learning courses are available?\"\n", - "rag_context = await rag_approach(query, limit=5)\n", - "rag_tokens = count_tokens(rag_context)\n", - "\n", - "print(\n", - " f\"\"\"📊 RAG Approach Results:\n", - " Query: \"{query}\"\n", - " Courses retrieved: 5\n", - " Token count: {rag_tokens:,}\n", - "\n", - "📄 Context Preview:\n", - "{rag_context[:500]}...\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "5b43b96177edaa59", - "metadata": {}, - "source": [ - "### Approach 2: Structured Views (Pre-Computed Summaries)\n", - "\n", - "Create a pre-computed catalog view that's optimized for LLM consumption:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "e49944033c6dec60", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:41.448177Z", - "start_time": "2025-11-04T21:16:41.439641Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.906358Z", - "iopub.status.busy": "2025-11-05T13:43:22.906278Z", - "iopub.status.idle": "2025-11-05T13:43:22.913907Z", - "shell.execute_reply": "2025-11-05T13:43:22.913549Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Structured View Approach Results:\n", - " Total courses: 50\n", - " Token count: 585\n", - " Cached in Redis: ✅\n", - "\n", - "📄 Catalog Preview:\n", - "# Redis University Course Catalog\n", - "\n", - "## Business (10 courses)\n", - "- BUS033: Marketing Strategy (intermediate)\n", - "- BUS035: Marketing Strategy (intermediate)\n", - "- BUS032: Marketing Strategy (intermediate)\n", - "- BUS034: Marketing Strategy (intermediate)\n", - "- BUS037: Marketing Strategy (intermediate)\n", - "- BUS039: Marketing Strategy (intermediate)\n", - "- BUS040: Marketing Strategy (intermediate)\n", - "- BUS038: Principles of Management (beginner)\n", - "- BUS036: Principles of Management (beginner)\n", - "- BUS031: Principles of Management (beginner)\n", - "\n", - "## Computer Science (10 courses)\n", - "- CS004: Database Systems (intermediate)\n", - "- CS003: Web Develo...\n", - "\n" - ] - } - ], - "source": [ - "# Approach 2: Structured Views\n", - "# Pre-compute a catalog summary organized by department\n", - "\n", - "\n", - "async def create_catalog_view() -> str:\n", - " \"\"\"Create a pre-computed catalog view organized by department.\"\"\"\n", - "\n", - " # Group courses by department\n", - " by_department = {}\n", - " for course in all_courses:\n", - " dept = course.department\n", - " if dept not in by_department:\n", - " by_department[dept] = []\n", - " by_department[dept].append(course)\n", - "\n", - " # Build catalog view\n", - " catalog_sections = []\n", - "\n", - " for dept_name in sorted(by_department.keys()):\n", - " courses = by_department[dept_name]\n", - "\n", - " # Create department section\n", - " dept_section = f\"\\n## {dept_name} ({len(courses)} courses)\\n\"\n", - "\n", - " # Add course summaries (optimized format)\n", - " course_summaries = []\n", - " for course in courses[:10]: # Limit for demo\n", - " summary = f\"- {course.course_code}: {course.title} ({course.difficulty_level.value})\"\n", - " course_summaries.append(summary)\n", - "\n", - " dept_section += \"\\n\".join(course_summaries)\n", - " catalog_sections.append(dept_section)\n", - "\n", - " catalog_view = \"# Redis University Course Catalog\\n\" + \"\\n\".join(catalog_sections)\n", - " return catalog_view\n", - "\n", - "\n", - "# Create and cache the view\n", - "catalog_view = await create_catalog_view()\n", - "catalog_tokens = count_tokens(catalog_view)\n", - "\n", - "# Store in Redis for reuse\n", - "redis_client.set(\"course_catalog_view\", catalog_view)\n", - "\n", - "print(\n", - " f\"\"\"📊 Structured View Approach Results:\n", - " Total courses: {len(all_courses)}\n", - " Token count: {catalog_tokens:,}\n", - " Cached in Redis: ✅\n", - "\n", - "📄 Catalog Preview:\n", - "{catalog_view[:600]}...\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "a8297b02702e162a", - "metadata": {}, - "source": [ - "### Approach 3: Hybrid (Best of Both Worlds)\n", - "\n", - "Combine structured view (overview) + RAG (specific details):" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "f1316764e1710f88", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:42.408022Z", - "start_time": "2025-11-04T21:16:42.402929Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.915343Z", - "iopub.status.busy": "2025-11-05T13:43:22.915253Z", - "iopub.status.idle": "2025-11-05T13:43:22.918650Z", - "shell.execute_reply": "2025-11-05T13:43:22.918244Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Hybrid Approach Results:\n", - " Query: \"What machine learning courses are available?\"\n", - " Token count: 760\n", - "\n", - " Components:\n", - " - Catalog overview: 585 tokens\n", - " - Specific details (RAG): 270 tokens\n", - "\n", - "📄 Context Structure:\n", - " 1. Full catalog overview (all departments)\n", - " 2. Detailed info for 3 most relevant courses\n", - "\n" - ] - } - ], - "source": [ - "# Approach 3: Hybrid\n", - "\n", - "\n", - "async def hybrid_approach(query: str) -> str:\n", - " \"\"\"Combine catalog overview with RAG for specific details.\"\"\"\n", - "\n", - " # Part 1: Get catalog overview (from cache)\n", - " catalog_overview = redis_client.get(\"course_catalog_view\")\n", - "\n", - " # Part 2: Get specific course details via RAG\n", - " specific_courses = await rag_approach(query, limit=3)\n", - "\n", - " # Combine\n", - " hybrid_context = f\"\"\"# Course Catalog Overview\n", - "{catalog_overview}\n", - "\n", - "---\n", - "\n", - "# Detailed Information for Your Query\n", - "{specific_courses}\n", - "\"\"\"\n", - "\n", - " return hybrid_context\n", - "\n", - "\n", - "# Test hybrid approach\n", - "hybrid_context = await hybrid_approach(query)\n", - "hybrid_tokens = count_tokens(hybrid_context)\n", - "\n", - "print(\n", - " f\"\"\"📊 Hybrid Approach Results:\n", - " Query: \"{query}\"\n", - " Token count: {hybrid_tokens:,}\n", - "\n", - " Components:\n", - " - Catalog overview: {catalog_tokens:,} tokens\n", - " - Specific details (RAG): {rag_tokens:,} tokens\n", - "\n", - "📄 Context Structure:\n", - " 1. Full catalog overview (all departments)\n", - " 2. Detailed info for 3 most relevant courses\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "b810bfe1cef703fd", - "metadata": {}, - "source": [ - "### Compare All Three Approaches\n", - "\n", - "Let's test all three with the same query and compare results:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "9cb3ddacd3f133f9", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:47.445269Z", - "start_time": "2025-11-04T21:16:43.510177Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:22.920072Z", - "iopub.status.busy": "2025-11-05T13:43:22.919993Z", - "iopub.status.idle": "2025-11-05T13:43:26.239645Z", - "shell.execute_reply": "2025-11-05T13:43:26.238709Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "COMPARING THREE APPROACHES\n", - "================================================================================\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:24 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:25 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:26 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Query: \"What machine learning courses are available?\"\n", - "\n", - "================================================================================\n", - "APPROACH 1: RAG (Semantic Search)\n", - "================================================================================\n", - "Token count: 270\n", - "Response:\n", - "I'm sorry, but there are no machine learning courses currently available in the course list provided. If you are interested in related fields, you might consider taking \"MATH022: Linear Algebra,\" as it covers essential topics like vector spaces and matrices that are foundational for machine learning.\n", - "\n", - "================================================================================\n", - "APPROACH 2: Structured View (Pre-Computed)\n", - "================================================================================\n", - "Token count: 585\n", - "Response:\n", - "We offer one advanced machine learning course:\n", - "\n", - "- CS007: Machine Learning (advanced)\n", - "\n", - "================================================================================\n", - "APPROACH 3: Hybrid (View + RAG)\n", - "================================================================================\n", - "Token count: 760\n", - "Response:\n", - "The available machine learning course is:\n", - "\n", - "- CS007: Machine Learning (advanced)\n", - "\n", - "================================================================================\n", - "\n" - ] - } - ], - "source": [ - "# Test all three approaches\n", - "query = \"What machine learning courses are available?\"\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"COMPARING THREE APPROACHES\")\n", - "print(\"=\" * 80)\n", - "\n", - "# Approach 1: RAG\n", - "messages_rag = [\n", - " SystemMessage(\n", - " content=f\"\"\"You are a Redis University course advisor.\n", - "\n", - "Available Courses:\n", - "{rag_context}\n", - "\n", - "Help students find relevant courses.\"\"\"\n", - " ),\n", - " HumanMessage(content=query),\n", - "]\n", - "response_rag = llm.invoke(messages_rag)\n", - "\n", - "# Approach 2: Structured View\n", - "messages_view = [\n", - " SystemMessage(\n", - " content=f\"\"\"You are a Redis University course advisor.\n", - "\n", - "{catalog_view}\n", - "\n", - "Help students find relevant courses.\"\"\"\n", - " ),\n", - " HumanMessage(content=query),\n", - "]\n", - "response_view = llm.invoke(messages_view)\n", - "\n", - "# Approach 3: Hybrid\n", - "messages_hybrid = [\n", - " SystemMessage(\n", - " content=f\"\"\"You are a Redis University course advisor.\n", - "\n", - "{hybrid_context}\n", - "\n", - "Help students find relevant courses.\"\"\"\n", - " ),\n", - " HumanMessage(content=query),\n", - "]\n", - "response_hybrid = llm.invoke(messages_hybrid)\n", - "\n", - "# Display comparison\n", - "print(\n", - " f\"\"\"\n", - "Query: \"{query}\"\n", - "\n", - "{'=' * 80}\n", - "APPROACH 1: RAG (Semantic Search)\n", - "{'=' * 80}\n", - "Token count: {rag_tokens:,}\n", - "Response:\n", - "{response_rag.content}\n", - "\n", - "{'=' * 80}\n", - "APPROACH 2: Structured View (Pre-Computed)\n", - "{'=' * 80}\n", - "Token count: {catalog_tokens:,}\n", - "Response:\n", - "{response_view.content}\n", - "\n", - "{'=' * 80}\n", - "APPROACH 3: Hybrid (View + RAG)\n", - "{'=' * 80}\n", - "Token count: {hybrid_tokens:,}\n", - "Response:\n", - "{response_hybrid.content}\n", - "\n", - "{'=' * 80}\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "74ae3ea8350df39", - "metadata": {}, - "source": [ - "### Decision Framework: Which Approach to Use?\n", - "\n", - "Here's how to choose based on YOUR requirements:\n", - "\n", - "| Factor | RAG | Structured Views | Hybrid |\n", - "|--------|-----|------------------|--------|\n", - "| **Token Efficiency** | ✅ Good (3K) | ✅✅ Excellent (2K) | ⚠️ Moderate (5K) |\n", - "| **Response Quality** | ✅ Good (relevant) | ✅ Good (overview) | ✅✅ Excellent (both) |\n", - "| **Latency** | ⚠️ Moderate (search) | ✅✅ Fast (cached) | ⚠️ Moderate (search) |\n", - "| **Maintenance** | ✅ Low (auto-updates) | ⚠️ Higher (rebuild views) | ⚠️ Higher (both) |\n", - "| **Best For** | Specific queries | Overview queries | Real-world systems |\n", - "\n", - "**Decision Process:**\n", - "\n", - "1. **Analyze YOUR data characteristics:**\n", - " - How many items? (10s, 100s, 1000s, millions?)\n", - " - How often does it change? (Real-time, daily, weekly?)\n", - " - What's the average item size? (100 words, 1000 words, 10K words?)\n", - "\n", - "2. **Analyze YOUR query patterns:**\n", - " - Specific queries (\"Show me RU101\") → RAG\n", - " - Overview queries (\"What courses exist?\") → Structured Views\n", - " - Mixed queries → Hybrid\n", - "\n", - "3. **Analyze YOUR constraints:**\n", - " - Tight token budget → Structured Views\n", - " - Real-time updates required → RAG\n", - " - Best quality needed → Hybrid\n", - "\n", - "**Example Decision:**\n", - "\n", - "For Redis University:\n", - "- ✅ **Data:** 100-500 courses, updated weekly, 200-500 words each\n", - "- ✅ **Queries:** Mix of overview (\"What's available?\") and specific (\"ML courses?\")\n", - "- ✅ **Constraints:** Moderate token budget, weekly updates acceptable\n", - "- ✅ **Decision:** **Hybrid approach** (pre-compute catalog + RAG for details)" - ] - }, - { - "cell_type": "markdown", - "id": "725b924daaecb8ae", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## Part 4: Introduction to Chunking - When and Why\n", - "\n", - "So far, we've worked with course data where each course is a complete, self-contained unit. But what happens when you have **long documents** that contain multiple distinct topics?\n", - "\n", - "This is where **chunking** *may* become necessary—but it's not always the right choice.\n", - "\n", - "### The Critical First Question: Does My Data Need Chunking?\n", - "\n", - "**Chunking is NOT a default step** - it's an engineering decision that depends on multiple factors:\n", - "\n", - "1. **Document type:** Structured records vs. long-form text vs. PDFs\n", - "2. **Data characteristics:** Small discrete items vs. large continuous documents\n", - "3. **Application requirements:** Query patterns, retrieval precision needs\n", - "4. **Embedding model limitations:** Context window size\n", - "\n", - "⚠️ **Important:** With modern long-context models (128K+ tokens), \"fitting in context\" is less of a concern. The real question is about **retrieval precision** and **data modeling**.\n", - "\n", - "Let's understand when chunking helps—and when it hurts." - ] - }, - { - "cell_type": "markdown", - "id": "5ef992eb86e53dda", - "metadata": {}, - "source": [ - "### The \"Don't Chunk\" Strategy: A Valid Option\n", - "\n", - "For structured data and naturally small documents, **not chunking is often the best strategy**:\n", - "\n", - "**Examples where whole-record embedding works better:**\n", - "- ✅ **Course catalogs** - Each course is a complete, self-contained unit\n", - "- ✅ **Product listings** - All product info should be retrieved together\n", - "- ✅ **FAQ entries** - Question + answer form an atomic unit\n", - "- ✅ **Database records** - Structured data with natural boundaries\n", - "- ✅ **Support tickets** - Single issue with context\n", - "\n", - "**Why \"don't chunk\" works here:**\n", - "- Each unit is **semantically complete** - all relevant info is together\n", - "- Natural boundaries exist - chunking would split related information\n", - "- Retrieval precision is maximized - you get exactly what's relevant\n", - "- Simpler implementation - no chunking logic, no overlap decisions\n", - "\n", - "> 💡 **Key Insight:** For our course catalog, each course is already an optimal retrieval unit. Chunking it would only hurt quality." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "192ce568978f11a1", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:47.462636Z", - "start_time": "2025-11-04T21:16:47.459982Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:26.241917Z", - "iopub.status.busy": "2025-11-05T13:43:26.241753Z", - "iopub.status.idle": "2025-11-05T13:43:26.245254Z", - "shell.execute_reply": "2025-11-05T13:43:26.244475Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Example: Course Description\n", - "================================================================================\n", - "CS004: Database Systems\n", - "Department: Computer Science\n", - "Credits: 3\n", - "Level: intermediate\n", - "Format: online\n", - "Instructor: John Zamora\n", - "Description: Design and implementation of database systems. SQL, normalization, transactions, and database administration.\n", - " \n", - "================================================================================\n", - "\n", - "Token count: 50\n", - "Semantic completeness: ✅ Complete (has all info about this course)\n", - "Chunking needed? ❌ NO\n", - "\n", - "Why not?\n", - "- Under 500 tokens (well within limits)\n", - "- Self-contained (doesn't reference other sections)\n", - "- Semantically complete (has all course details)\n", - "- Breaking it up would lose context\n", - "\n" - ] - } - ], - "source": [ - "# Example: Course data (NO chunking needed)\n", - "sample_course_text = transform_course_to_text(all_courses[0])\n", - "sample_tokens = count_tokens(sample_course_text)\n", - "\n", - "print(\n", - " f\"\"\"📊 Example: Course Description\n", - "{'=' * 80}\n", - "{sample_course_text}\n", - "{'=' * 80}\n", - "\n", - "Token count: {sample_tokens}\n", - "Semantic completeness: ✅ Complete (has all info about this course)\n", - "Chunking needed? ❌ NO\n", - "\n", - "Why whole-record embedding works here:\n", - "- Self-contained (doesn't reference other sections)\n", - "- Semantically complete (has all course details)\n", - "- Natural boundary (one course = one retrieval unit)\n", - "- Breaking it up would hurt retrieval quality\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "828c1dca350c1f2d", - "metadata": {}, - "source": [ - "### When Chunking May Help\n", - "\n", - "Chunking *can* improve retrieval when documents have certain characteristics:\n", - "\n", - "**Document types that may benefit from chunking:**\n", - "- Research papers with multiple distinct sections\n", - "- Technical documentation spanning many topics\n", - "- Books and long-form content\n", - "- Legal contracts with multiple clauses\n", - "- Medical records with multiple visits/conditions\n", - "\n", - "**Why chunking helps in these cases:**\n", - "- **Multiple distinct topics** - Different sections should be retrieved separately for precision\n", - "- **Improves retrieval precision** - Find specific sections, not whole document\n", - "- **Better data modeling** - Just like database design, structure affects quality\n", - "- **Addresses research-documented context quality problems** (see below)\n", - "\n", - "⚠️ **Note:** Modern embedding models (jina-embeddings-v2, etc.) support 8K+ tokens. Model limits are less of a concern than **retrieval precision**.\n", - "\n", - "### Research Background: Why Long Context Can Hurt\n", - "\n", - "Even with large context windows (128K+ tokens), research shows that **how you structure context matters more than fitting everything in**:\n", - "\n", - "**1. \"Lost in the Middle\" (Stanford/UC Berkeley, 2023)**\n", - "\n", - "*Source: [arXiv:2307.03172](https://arxiv.org/abs/2307.03172), published in TACL 2024*\n", - "\n", - "LLMs exhibit a **\"U-shaped\" attention pattern**:\n", - "- High recall for information at the **beginning** and **end** of context\n", - "- **Significantly degraded performance** for information in the middle\n", - "- This happens even in models explicitly designed for long contexts\n", - "\n", - "**Implication for chunking:** For long documents, chunking ensures the relevant section is retrieved and placed prominently in context, rather than buried in the middle of a 50-page document.\n", - "\n", - "**2. \"Context Rot\" (Chroma Research, 2025)**\n", - "\n", - "*Source: [research.trychroma.com/context-rot](https://research.trychroma.com/context-rot)*\n", - "\n", - "Tested 18 LLMs (GPT-4.1, Claude 4, Gemini 2.5, Qwen3) and found:\n", - "- **Performance degrades as input length increases**, even when relevant info is present\n", - "- **Distractor effect**: Irrelevant content actively hurts model performance\n", - "- Even 4 distractor documents can significantly degrade output quality\n", - "- Position of irrelevant content matters (middle is worst)\n", - "\n", - "**Implication for chunking:** Retrieving smaller, focused chunks reduces \"distractor tokens\" that poison the context.\n", - "\n", - "**3. Needle in the Haystack (NIAH) Benchmark**\n", - "\n", - "*Source: [Greg Kamradt, github.com/gkamradt/LLMTest_NeedleInAHaystack](https://github.com/gkamradt/LLMTest_NeedleInAHaystack)*\n", - "\n", - "Tests whether LLMs can find a specific fact (\"needle\") buried in long context (\"haystack\"):\n", - "- Models often **fail to retrieve information** even when it's present in context\n", - "- Performance varies by position (middle is typically worst)\n", - "- **Limitation**: NIAH tests lexical retrieval only, not semantic understanding\n", - "\n", - "**Implication for chunking:** For structured data like course catalogs, NIAH is **irrelevant**—each record IS the needle. Chunking would only fragment complete units.\n", - "\n", - "---\n", - "\n", - "**The Key Insight:**\n", - "\n", - "These research findings don't prescribe a universal chunking rule—they inform your design decisions:\n", - "\n", - "- **Structured records** (courses, products, FAQs): The \"lost in the middle\" problem typically doesn't apply because each record is already a focused, atomic unit. However, if your records are unusually large or contain multiple distinct topics, chunking may still help.\n", - "\n", - "- **Long-form documents**: Context rot and positional bias become more relevant as document length increases, but the degree depends on your specific content, query patterns, and model capabilities. Chunking can help surface relevant sections, but over-chunking fragments context.\n", - "\n", - "- **Mixed content types**: Real-world data rarely fits neat categories. A research paper with embedded tables, a product listing with extensive reviews, or a FAQ with nested sub-questions all require case-by-case judgment.\n", - "\n", - "The research provides **mental models for reasoning about trade-offs**, not binary rules. Experiment with your actual data and queries.\n", - "\n", - "### Emerging Strategies (2024)\n", - "\n", - "Recent research has introduced new approaches that challenge traditional chunking:\n", - "\n", - "1. **Late Chunking** (Jina AI): Embed the entire document first, then chunk the embeddings. Preserves cross-chunk context without ColBERT-level storage costs.\n", - "\n", - "2. **Contextual Retrieval** (Anthropic): Add LLM-generated context to each chunk before embedding. Can reduce retrieval failures by 49-67%.\n", - "\n", - "3. **Hybrid Search**: Combine vector embeddings with BM25 keyword search. Often outperforms either approach alone.\n", - "\n", - "The key insight: **chunking strategy is a design choice, not a one-size-fits-all prescription**.\n" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## Advanced Chunking: Three Distinct Document Types\n", - "\n", - "**Critical Insight:** Chunking is **subjective and document-dependent**. There is no universal strategy.\n", - "\n", - "The optimal approach depends entirely on:\n", - "- **Document type and structure** (research papers vs. contracts vs. transcripts)\n", - "- **Content heterogeneity** (text, tables, equations, code, images)\n", - "- **Query patterns** (specific facts vs. conceptual understanding)\n", - "- **Domain requirements** (legal precision vs. scientific accuracy vs. conversational context)\n", - "- **Models being used** (embedding model capabilities, LLM context windows)\n", - "- **Performance metrics** (retrieval precision, answer quality, latency, cost)\n", - "\n", - "This section explores three fundamentally different document types that require distinct chunking approaches:\n", - "\n", - "1. **Research Papers & Long-Form Documents** (Multimodal Content)\n", - "2. **Legal Contracts & Clause-Level Documents** (Advanced Data Engineering)\n", - "3. **Transcripts & Meeting Notes** (Temporal & Speaker-Based Chunking)\n" - ], - "id": "53c612523bb5301a" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Document Type 1: Research Papers & Long-Form Documents (Multimodal Content)\n", - "\n", - "**⚠️ Important:** This category is **broad and subjective**. It includes:\n", - "- Research papers (scientific, technical, medical)\n", - "- Books and textbooks\n", - "- Technical documentation\n", - "- Financial reports\n", - "- Medical records\n", - "- Product manuals\n", - "- **Even legal contracts** (which we'll discuss separately due to unique challenges)\n", - "\n", - "**What makes these documents similar:**\n", - "- Heterogeneous content types (text, tables, equations, figures, code)\n", - "- Clear or implicit structural hierarchy (sections, chapters, subsections)\n", - "- Multiple distinct topics within single document\n", - "- Cross-references between sections\n", - "- Length varies from 10 pages to 1,000+ pages\n", - "\n", - "**Key Challenge:** Multimodal content requires specialized handling to preserve meaning.\n", - "\n", - "#### Why Chunking Matters: Research-Backed Benefits\n", - "\n", - "**1. Token Limit Management**\n", - "- Ensures content fits within model context windows\n", - "- Even with 128K+ context models, focused chunks improve processing efficiency\n", - "- Reduces computational costs and latency\n", - "- *Source: Anthropic Contextual Retrieval (2024)*\n", - "\n", - "**2. Improved Retrieval Precision**\n", - "- Smaller, focused chunks create more accurate embeddings\n", - "- **49-67% reduction in retrieval failures** with proper chunking + contextual retrieval\n", - "- Reduces \"distractor effect\" from irrelevant content\n", - "- *Source: Anthropic Contextual Retrieval, September 2024*\n", - "\n", - "**3. Context Preservation**\n", - "- Keeps semantically related information together\n", - "- Maintains author's logical flow and argumentation\n", - "- Prevents fragmentation of complex ideas\n", - "- **Chunk overlap (10-20%)** helps preserve context across boundaries\n", - "\n", - "**4. Computational Efficiency**\n", - "- Faster processing with smaller chunks\n", - "- Reduced costs (fewer tokens per query)\n", - "- Better cache hit rates in production systems\n", - "- *Source: \"Advancing Semantic Caching for LLMs\" (Redis/Virginia Tech, arXiv:2504.02268, 2025)*\n", - "\n", - "#### Chunking Strategies for Long-Form Documents\n", - "\n", - "**Strategy 1: Page-Level Chunking**\n", - "- **Best for:** Financial reports, legal documents, books with natural page boundaries\n", - "- **How:** Split by page numbers, preserving page-level context\n", - "- **Pros:** Natural boundaries, easy to cite sources (\"See page 42\")\n", - "- **Cons:** May split mid-sentence or mid-paragraph\n", - "\n", - "**Strategy 2: Structure-Aware Chunking (Markdown/HTML)**\n", - "- **Best for:** Documents with clear hierarchical structure (research papers, technical docs)\n", - "- **How:** Split by headings (H1, H2, H3), sections, subsections\n", - "- **Pros:** Respects logical boundaries, preserves semantic units\n", - "- **Cons:** Requires structured input (Markdown, HTML, LaTeX)\n", - "\n", - "**Strategy 3: Recursive Chunking**\n", - "- **Best for:** Mixed content with varying structure\n", - "- **How:** Try splitting by paragraphs → sentences → words (progressive fallback)\n", - "- **Pros:** Handles edge cases gracefully, respects natural boundaries\n", - "- **Cons:** More complex implementation\n", - "\n", - "**Strategy 4: Semantic Chunking**\n", - "- **Best for:** Unstructured text without clear boundaries\n", - "- **How:** Use embeddings to detect topic shifts, group semantically similar sentences\n", - "- **Pros:** Content-aware, doesn't rely on formatting\n", - "- **Cons:** Computationally expensive, may not align with author's structure\n", - "\n", - "**Strategy 5: Hybrid Approaches**\n", - "- **Best for:** Production systems with diverse document types\n", - "- **How:** Combine multiple strategies (e.g., structure-aware + semantic)\n", - "- **Pros:** Flexible, adapts to different content types\n", - "- **Cons:** More complex to implement and maintain\n", - "\n", - "**⚠️ Important:** The \"best\" strategy depends on YOUR specific documents and query patterns. **Experimentation is required.**\n", - "\n", - "#### Chunk Overlap: Preserving Context Across Boundaries\n", - "\n", - "**Why overlap matters:**\n", - "- Prevents information loss at chunk boundaries\n", - "- Maintains context for sentences that span chunks\n", - "- Improves retrieval recall (same info appears in multiple chunks)\n", - "\n", - "**Recommended overlap:**\n", - "- **10-20% of chunk size** is typical\n", - "- Example: 1,000-token chunks with 100-200 token overlap\n", - "- Too little: Risk losing context at boundaries\n", - "- Too much: Redundancy, increased storage/compute costs\n", - "\n", - "**Example:**\n", - "```\n", - "Chunk 1: [Tokens 1-1000]\n", - "Chunk 2: [Tokens 900-1900] ← 100 tokens overlap with Chunk 1\n", - "Chunk 3: [Tokens 1800-2800] ← 100 tokens overlap with Chunk 2\n", - "```\n" - ], - "id": "9770175b8757aa7c" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "#### Real-World Example: Analyzing a Research Paper\n", - "\n", - "Let's analyze a **real research paper** to understand chunking decisions:\n", - "\n", - "**Paper:** \"Advancing Semantic Caching for LLMs with Domain-Specific Embeddings and Synthetic Data\"\n", - "**Source:** arXiv:2504.02268 (Redis/Virginia Tech, April 2025)\n", - "**Length:** 12 pages, ~42,000 characters\n", - "\n", - "**Paper Structure:**\n", - "- Abstract (1 paragraph, ~200 words)\n", - "- Introduction (3 pages, ~1,500 words)\n", - "- Methodology (4 pages, includes equations and algorithms)\n", - "- Experimental Results (3 pages, includes tables and figures)\n", - "- Discussion & Conclusion (2 pages)\n", - "- References (1 page)\n", - "\n", - "**Content Types Present:**\n", - "1. **Text sections**: Standard prose (Introduction, Discussion)\n", - "2. **Mathematical formulas**: Contrastive loss functions, similarity metrics\n", - "3. **Tables**: Performance comparison across 13 embedding models (5 metrics each)\n", - "4. **Figures**: Bar charts showing precision/recall/F1 scores\n", - "5. **Code snippets**: Python examples for fine-tuning ModernBERT\n", - "6. **References**: Citations to related work\n", - "\n", - "**Critical Question: Is chunking the ONLY way to process this paper?**\n", - "\n", - "❌ **NO** - Chunking is ONE approach, but not the only one. Consider these alternatives:\n", - "\n", - "**Option 1: Hierarchical Retrieval (No Chunking)**\n", - "- Create summary embedding for entire paper\n", - "- Store full paper as retrievable unit\n", - "- Use summary for initial search, full paper for detailed analysis\n", - "- **Best for:** Overview queries (\"What papers discuss semantic caching?\")\n", - "- **Pros:** Simple, preserves full context\n", - "- **Cons:** Poor precision for specific queries\n", - "\n", - "**Option 2: Section-Based Chunking (Structure-Aware)**\n", - "- Chunk by major sections (Abstract, Intro, Methods, Results, Discussion)\n", - "- Keep tables/figures WITH their explanatory text\n", - "- Preserve mathematical formulas with variable definitions\n", - "- **Best for:** Specific queries (\"What methodology did they use?\")\n", - "- **Pros:** Good precision, respects paper structure\n", - "- **Cons:** Sections may still be large (1,500+ words)\n", - "\n", - "**Option 3: Hybrid Approach (Recommended)**\n", - "- Summary embedding + section embeddings + full paper storage\n", - "- Multi-level retrieval: summary → relevant sections → full context\n", - "- **Best for:** Production systems with diverse query patterns\n", - "- **Pros:** Flexible, handles both overview and specific queries\n", - "- **Cons:** More complex implementation\n", - "\n", - "**Option 4: Multimodal RAG**\n", - "- Extract tables/figures as separate entities\n", - "- Use vision models (GPT-4V, Claude 3) for figure understanding\n", - "- Link text chunks to related visual elements\n", - "- **Best for:** Papers with critical visual information (charts, diagrams)\n", - "- **Pros:** Handles visual content that text embeddings miss\n", - "- **Cons:** Expensive (vision model API costs), complex pipeline\n", - "\n", - "**Our Expert Recommendation for This Paper:**\n", - "\n", - "Use **Option 3 (Hybrid)** because:\n", - "1. Paper has clear section structure (good for structure-aware chunking)\n", - "2. Contains multimodal content (tables, figures) that need special handling\n", - "3. Queries could be overview (\"What's this paper about?\") or specific (\"What were the precision results?\")\n", - "4. Hybrid approach provides flexibility without excessive complexity\n" - ], - "id": "4a9e75572032c2a0" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "#### Handling Multimodal Content: Tables, Figures, Equations, Code\n", - "\n", - "**Critical Challenge:** Research papers and technical documents contain heterogeneous content types that require specialized handling.\n", - "\n", - "**Content Type 1: Tables**\n", - "\n", - "**Problem:** Tables are structured data that lose meaning when chunked mid-table or separated from context.\n", - "\n", - "**Best Practices:**\n", - "- ✅ **Chunk table WITH its caption and explanation**\n", - " - Include: Table title, column headers, data rows, AND explanatory text\n", - " - Example: \"Table 1 shows HNSW performance trade-offs. As M increases from 16 to 64, recall improves from 0.89 to 0.97, but latency increases from 2.1ms to 8.7ms...\"\n", - "- ✅ **Preserve table structure** in text format (Markdown, CSV, or structured description)\n", - "- ✅ **Add metadata** to chunk: table number, section, key findings\n", - "- ❌ **Don't chunk table separately** from its context - it becomes meaningless\n", - "- ❌ **Don't split tables** across multiple chunks\n", - "\n", - "**Advanced Approach:** Extract tables as structured data (JSON/CSV) and store separately with links to text chunks.\n", - "\n", - "**Content Type 2: Mathematical Formulas**\n", - "\n", - "**Problem:** Formulas without context are meaningless. Variables need definitions.\n", - "\n", - "**Best Practices:**\n", - "- ✅ **Chunk formula WITH its explanation and variable definitions**\n", - " - Include: Formula, variable definitions, interpretation, example\n", - " - Example: \"The recall-latency trade-off can be modeled as: Latency(M, ef) = α·M² + β·ef + γ, where M = number of connections per layer, ef = size of dynamic candidate list...\"\n", - "- ✅ **Keep formula + derivation + application** together\n", - "- ✅ **Include units and constraints** (e.g., \"where M ∈ [16, 64]\")\n", - "- ❌ **Don't separate formula** from its meaning\n", - "- ❌ **Don't chunk mid-derivation**\n", - "\n", - "**Advanced Approach:** Use LaTeX-aware chunking to preserve mathematical notation.\n", - "\n", - "**Content Type 3: Figures and Charts**\n", - "\n", - "**Problem:** Figures contain visual information that text embeddings cannot capture.\n", - "\n", - "**Best Practices:**\n", - "- ✅ **Chunk figure caption WITH its discussion in text**\n", - " - Include: Figure number, caption, key findings, interpretation\n", - " - Example: \"Figure 1 shows precision/recall comparison across 13 embedding models. LangCache-Embed achieves 0.84 precision, outperforming OpenAI's text-embedding-3-small (0.65) by 29%...\"\n", - "- ✅ **Describe visual patterns** in text (trends, comparisons, outliers)\n", - "- ✅ **Extract data from charts** if possible (convert to table/text)\n", - "- ❌ **Don't rely on figure alone** - text embeddings can't \"see\" images\n", - "\n", - "**Advanced Approach (Multimodal RAG):**\n", - "- Use vision models (GPT-4V, Claude 3, Gemini) to generate figure descriptions\n", - "- Store figure embeddings separately using CLIP or similar vision-language models\n", - "- Link text chunks to related figures for retrieval\n", - "\n", - "**Content Type 4: Code Snippets**\n", - "\n", - "**Problem:** Code without context is hard to understand. Why these values? What's the use case?\n", - "\n", - "**Best Practices:**\n", - "- ✅ **Chunk code WITH its context and rationale**\n", - " - Include: Code, explanation, use case, parameter justification\n", - " - Example: \"For real-world deployment, we recommend M=32 and ef_construction=200 because this balances recall (0.94) and latency (4.3ms)...\"\n", - "- ✅ **Include comments and docstrings** in the chunk\n", - "- ✅ **Add example usage** if relevant\n", - "- ❌ **Don't chunk code** without explaining WHY these values\n", - "- ❌ **Don't separate code** from its output/results\n", - "\n", - "**Advanced Approach:** Use code-specific embeddings (CodeBERT, GraphCodeBERT) for better semantic understanding.\n", - "\n", - "**Summary: Multimodal Content Chunking Principles**\n", - "\n", - "1. **Context is king**: Never chunk content (table/formula/figure/code) without its explanation\n", - "2. **Preserve structure**: Maintain formatting that aids understanding (table structure, code indentation)\n", - "3. **Add metadata**: Enrich chunks with type, section, number (e.g., \"Table 3 from Section 4.2\")\n", - "4. **Consider alternatives**: For critical visual content, multimodal RAG may be necessary\n", - "5. **Experiment**: Test retrieval quality with your actual queries and documents\n" - ], - "id": "d41ba887c65c93d4" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Example: Research paper (NEEDS chunking)\n", - "# Let's simulate a long research paper about Redis\n", - "\n", - "research_paper = \"\"\"\n", - "# Optimizing Vector Search Performance in Redis\n", - "\n", - "## Abstract\n", - "This paper presents a comprehensive analysis of vector search optimization techniques in Redis,\n", - "examining the trade-offs between search quality, latency, and memory usage. We evaluate multiple\n", - "indexing strategies including HNSW and FLAT indexes across datasets ranging from 10K to 10M vectors.\n", - "Our results demonstrate that careful index configuration can improve search latency by up to 10x\n", - "while maintaining 95%+ recall. We also introduce novel compression techniques that reduce memory\n", - "usage by 75% with minimal impact on search quality.\n", - "\n", - "## 1. Introduction\n", - "Vector databases have become essential infrastructure for modern AI applications, enabling semantic\n", - "search, recommendation systems, and retrieval-augmented generation (RAG). Redis, traditionally known\n", - "as an in-memory data structure store, has evolved to support high-performance vector search through\n", - "the RediSearch module. However, optimizing vector search performance requires understanding complex\n", - "trade-offs between multiple dimensions...\n", - "\n", - "[... 5,000 more words covering methodology, experiments, results, discussion ...]\n", - "\n", - "## 2. Background and Related Work\n", - "Previous work on vector search optimization has focused primarily on algorithmic improvements to\n", - "approximate nearest neighbor (ANN) search. Malkov and Yashunin (2018) introduced HNSW, which has\n", - "become the de facto standard for high-dimensional vector search. Johnson et al. (2019) developed\n", - "FAISS, demonstrating that product quantization can significantly reduce memory usage...\n", - "\n", - "[... 2,000 more words ...]\n", - "\n", - "## 3. Performance Analysis and Results\n", - "\n", - "### 3.1 HNSW Configuration Trade-offs\n", - "\n", - "Table 1 shows the performance comparison across different HNSW configurations. As M increases from 16 to 64,\n", - "we observe significant improvements in recall (0.89 to 0.97) but at the cost of increased latency (2.1ms to 8.7ms)\n", - "and memory usage (1.2GB to 3.8GB). The sweet spot for most real-world workloads is M=32 with ef_construction=200,\n", - "which achieves 0.94 recall with 4.3ms latency.\n", - "\n", - "Table 1: HNSW Performance Comparison\n", - "| M | ef_construction | Recall@10 | Latency (ms) | Memory (GB) | Build Time (min) |\n", - "|----|-----------------|-----------|--------------|-------------|------------------|\n", - "| 16 | 100 | 0.89 | 2.1 | 1.2 | 8 |\n", - "| 32 | 200 | 0.94 | 4.3 | 2.1 | 15 |\n", - "| 64 | 400 | 0.97 | 8.7 | 3.8 | 32 |\n", - "\n", - "The data clearly demonstrates the fundamental trade-off between search quality and resource consumption.\n", - "For applications requiring high recall (>0.95), the increased latency and memory costs are unavoidable.\n", - "\n", - "### 3.2 Mathematical Model\n", - "\n", - "The recall-latency trade-off can be modeled as a quadratic function of the HNSW parameters:\n", - "\n", - "Latency(M, ef) = α·M² + β·ef + γ\n", - "\n", - "Where:\n", - "- M = number of connections per layer (controls graph connectivity)\n", - "- ef = size of dynamic candidate list (controls search breadth)\n", - "- α, β, γ = dataset-specific constants (fitted from experimental data)\n", - "\n", - "For our e-commerce dataset, we fitted: α=0.002, β=0.015, γ=1.2 (R²=0.94)\n", - "\n", - "This model allows us to predict latency for untested configurations and optimize for specific\n", - "recall targets. The quadratic dependency on M explains why doubling M more than doubles latency.\n", - "\n", - "## 4. Implementation Recommendations\n", - "\n", - "Based on our findings, we recommend the following configuration for real-world deployments:\n", - "\n", - "```python\n", - "# Optimal HNSW configuration for balanced performance\n", - "index_params = {\n", - " \"M\": 32, # Balance recall and latency\n", - " \"ef_construction\": 200, # Higher quality index\n", - " \"ef_runtime\": 100 # Fast search with good recall\n", - "}\n", - "```\n", - "\n", - "This configuration achieves 0.94 recall with 4.3ms p95 latency, suitable for most real-time applications.\n", - "For applications with stricter latency requirements (<2ms), consider M=16 with ef_construction=100,\n", - "accepting the lower recall of 0.89. For applications requiring maximum recall (>0.95), use M=64\n", - "with ef_construction=400, but ensure adequate memory and accept higher latency.\n", - "\n", - "[... 1,500 more words with additional analysis ...]\n", - "\n", - "## 5. Discussion and Conclusion\n", - "Our findings demonstrate that vector search optimization is fundamentally about understanding\n", - "YOUR specific requirements and constraints. There is no one-size-fits-all configuration. The choice\n", - "between HNSW parameters depends on your specific recall requirements, latency budget, and memory constraints.\n", - "We provide a mathematical model and practical guidelines to help practitioners make informed decisions...\n", - "\"\"\"\n", - "\n", - "paper_tokens = count_tokens(research_paper)\n", - "print(f\"Token count: {paper_tokens:,} | Words: ~{len(research_paper.split())}\")" - ], - "id": "e4f638f39d95535c" - }, - { - "cell_type": "markdown", - "id": "5fa2bdec6f414d76", - "metadata": {}, - "source": [ - "**📊 Analysis: Research Paper Example**\n", - "\n", - "**Document:** \"Optimizing Vector Search Performance in Redis\"\n", - "\n", - "**Structure:** Abstract, Introduction, Background, Methodology, Results, Discussion\n", - "\n", - "**Chunking needed?** ✅ **YES**\n", - "\n", - "**Why This Document May Benefit from Chunking (Even with Large Context Windows):**\n", - "\n", - "> **Note:** Modern LLMs can handle 128K+ tokens, so \"fitting in context\" isn't the issue. The real value of chunking is **better data modeling and retrieval precision**.\n", - "\n", - "**1. Retrieval Precision vs. Recall Trade-off**\n", - "\n", - "Without chunking (embed entire paper):\n", - "- Query: \"What compression techniques were used?\"\n", - "- Retrieved: Entire 15,000-token paper (includes Abstract, Background, Results, Discussion)\n", - "- Problem: 80% of retrieved content is irrelevant to the query\n", - "- LLM must process 15,000 tokens to find 200 tokens of relevant information\n", - "\n", - "With chunking (embed by section):\n", - "- Query: \"What compression techniques were used?\"\n", - "- Retrieved: Methodology section (800 tokens)\n", - "- Result: 90%+ of retrieved content is directly relevant\n", - "- LLM processes 800 focused tokens with high signal-to-noise ratio\n", - "\n", - "**2. Structured Content Requires Specialized Chunking**\n", - "\n", - "Research papers contain heterogeneous content types that need different handling. Without specialized chunking, there will be a danger of mixing incompatible content types, chunking in the middle of tables, etc.\n", - "\n", - "**Tables and Charts:**\n", - "```\n", - "Table 1: HNSW Performance Comparison\n", - "| M | ef_construction | Recall@10 | Latency (ms) | Memory (GB) |\n", - "|----|-----------------|-----------|--------------|-------------|\n", - "| 16 | 100 | 0.89 | 2.1 | 1.2 |\n", - "| 32 | 200 | 0.94 | 4.3 | 2.1 |\n", - "| 64 | 400 | 0.97 | 8.7 | 3.8 |\n", - "```\n", - "\n", - "**Best practice:** Chunk table WITH its caption and explanation:\n", - "- ✅ \"Table 1 shows HNSW performance trade-offs. As M increases from 16 to 64, recall improves from 0.89 to 0.97, but latency increases from 2.1ms to 8.7ms...\"\n", - "- ❌ Don't chunk table separately from context - it becomes meaningless\n", - "\n", - "**Mathematical Formulas:**\n", - "```\n", - "The recall-latency trade-off can be modeled as:\n", - "Latency(M, ef) = α·M² + β·ef + γ\n", - "\n", - "Where:\n", - "- M = number of connections per layer\n", - "- ef = size of dynamic candidate list\n", - "- α, β, γ = dataset-specific constants\n", - "```\n", - "\n", - "**Best practice:** Chunk formula WITH its explanation and variable definitions\n", - "- ✅ Keep formula + explanation + interpretation together\n", - "- ❌ Don't separate formula from its meaning\n", - "\n", - "**Code Snippets:**\n", - "```python\n", - "# Optimal HNSW configuration for our use case\n", - "index_params = {\n", - " \"M\": 32, # Balance recall and latency\n", - " \"ef_construction\": 200, # Higher quality index\n", - " \"ef_runtime\": 100 # Fast search\n", - "}\n", - "```\n", - "\n", - "**Best practice:** Chunk code WITH its context and rationale\n", - "- ✅ \"For real-world deployment, we recommend M=32 and ef_construction=200 because...\"\n", - "- ❌ Don't chunk code without explaining WHY these values\n", - "\n", - "**3. Query-Specific Retrieval Patterns**\n", - "\n", - "Different queries need different chunks:\n", - "\n", - "| Query | Needs | Without Chunking | With Chunking |\n", - "|-------|-------|------------------|---------------|\n", - "| \"What compression techniques?\" | Methodology section | Entire paper (15K tokens) | Methodology (800 tokens) |\n", - "| \"What were recall results?\" | Results + Table 1 | Entire paper (15K tokens) | Results section (600 tokens) |\n", - "| \"How does HNSW work?\" | Background + Formula | Entire paper (15K tokens) | Background (500 tokens) |\n", - "| \"What's the recommended config?\" | Discussion + Code | Entire paper (15K tokens) | Discussion (400 tokens) |\n", - "\n", - "**Impact:** 10-20x reduction in irrelevant context, leading to faster responses and better quality.\n", - "\n", - "**4. Embedding Quality: Focused vs. Averaged**\n", - "\n", - "**Without chunking:**\n", - "- Embedding represents \"a paper about vector search, HNSW, compression, benchmarks, Redis...\"\n", - "- Generic, averaged representation\n", - "- Matches weakly with specific queries\n", - "\n", - "**With chunking:**\n", - "- Methodology chunk: \"compression techniques, quantization, memory reduction, implementation details...\"\n", - "- Results chunk: \"recall metrics, latency measurements, performance comparisons, benchmark data...\"\n", - "- Each embedding is focused and matches strongly with relevant queries\n", - "\n", - "**💡 Key Insight:** Chunking isn't about fitting in context windows - it's about **data modeling for retrieval**. Just like you wouldn't store all customer data in one database row, you shouldn't embed all document content in one vector." - ] - }, - { - "cell_type": "markdown", - "id": "9a6dbd30ec917f3", - "metadata": {}, - "source": [ - "### Chunking Strategies: Engineering Trade-Offs\n", - "\n", - "Once you've determined that your data needs chunking, the next question is: **How should you chunk it?**\n", - "\n", - "There's no single \"best\" chunking strategy - the optimal approach depends on YOUR data characteristics and query patterns. Let's explore different strategies and their trade-offs.\n", - "\n", - "**🔧 Using LangChain for Professional-Grade Chunking**\n", - "\n", - "In this section, we'll use **LangChain's text splitting utilities** for Strategies 2 and 3. LangChain provides battle-tested, robust implementations that handle edge cases and optimize for LLM consumption.\n", - "\n", - "**Why LangChain?**\n", - "- **Industry-standard**: Used by thousands of real-world applications\n", - "- **Smart boundary detection**: Respects natural text boundaries (paragraphs, sentences, words)\n", - "- **Local embeddings**: Free semantic chunking with HuggingFace models (no API costs)\n", - "- **Well-tested**: Handles edge cases (empty chunks, unicode, special characters)\n", - "\n", - "We'll use:\n", - "- `RecursiveCharacterTextSplitter` (Strategy 2): Smart fixed-size chunking with boundary awareness\n", - "- `SemanticChunker` + `HuggingFaceEmbeddings` (Strategy 3): Meaning-based chunking with local models\n", - "\n", - "### Strategy 1: Document-Based Chunking (Structure-Aware)\n", - "\n", - "**Concept:** Split documents based on their inherent structure (sections, paragraphs, headings, and as mentioned earlier, tables, code, and formulas).\n", - "\n", - "**Best for:** Structured documents with clear logical divisions (research papers, technical docs, books, etc.)." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "e395e0c41fc50ae5", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:48.570565Z", - "start_time": "2025-11-04T21:16:48.565095Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:26.253942Z", - "iopub.status.busy": "2025-11-05T13:43:26.253817Z", - "iopub.status.idle": "2025-11-05T13:43:26.257900Z", - "shell.execute_reply": "2025-11-05T13:43:26.257513Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Strategy 1: Document-Based (Structure-Aware) Chunking\n", - "================================================================================\n", - "Original document: 1,035 tokens\n", - "Number of chunks: 7\n", - "\n", - "Chunk breakdown:\n", - "\n", - " Chunk 1: 8 tokens - # Optimizing Vector Search Performance in Redis...\n", - "\n", - " Chunk 2: 108 tokens - ## Abstract This paper presents a comprehensive analysis of vector search optimization techniques in Redis, examining the trade-offs between search quality, latency, and memory usage. We evaluate multiple indexing strategies including HNSW and FLAT indexes across datasets ranging from 10K to 10M vec...\n", - "\n", - " Chunk 3: 98 tokens - ## 1. Introduction Vector databases have become essential infrastructure for modern AI applications, enabling semantic search, recommendation systems, and retrieval-augmented generation (RAG). Redis, traditionally known as an in-memory data structure store, has evolved to support high-performance ve...\n", - "\n", - " Chunk 4: 98 tokens - ## 2. Background and Related Work Previous work on vector search optimization has focused primarily on algorithmic improvements to approximate nearest neighbor (ANN) search. Malkov and Yashunin (2018) introduced HNSW, which has become the de facto standard for high-dimensional vector search. Johnson...\n", - "\n", - " Chunk 5: 464 tokens - ## 3. Performance Analysis and Results ### 3.1 HNSW Configuration Trade-offs Table 1 shows the performance comparison across different HNSW configurations. As M increases from 16 to 64, we observe significant improvements in recall (0.89 to 0.97) but at the cost of increased latency (2.1ms to 8.7m...\n", - "\n", - " Chunk 6: 187 tokens - ## 4. Implementation Recommendations Based on our findings, we recommend the following configuration for production deployments: ```python # Optimal HNSW configuration for balanced performance index_params = { \"M\": 32, # Balance recall and latency \"ef_construction\": 200, ...\n", - "\n", - " Chunk 7: 73 tokens - ## 5. Discussion and Conclusion Our findings demonstrate that vector search optimization is fundamentally about understanding YOUR specific requirements and constraints. There is no one-size-fits-all configuration. The choice between HNSW parameters depends on your specific recall requirements, late...\n", - "\n" - ] - } - ], - "source": [ - "# Strategy 1: Document-Based Chunking\n", - "# Split research paper by sections (using markdown headers)\n", - "\n", - "\n", - "def chunk_by_structure(text: str, separator: str = \"\\n## \") -> List[str]:\n", - " \"\"\"Split text by structural markers (e.g., markdown headers).\"\"\"\n", - "\n", - " # Split by headers\n", - " sections = text.split(separator)\n", - "\n", - " # Clean and format chunks\n", - " chunks = []\n", - " for i, section in enumerate(sections):\n", - " if section.strip():\n", - " # Add header back (except for first chunk which is title)\n", - " if i > 0:\n", - " chunk = \"## \" + section\n", - " else:\n", - " chunk = section\n", - " chunks.append(chunk.strip())\n", - "\n", - " return chunks\n", - "\n", - "\n", - "# Apply to research paper\n", - "structure_chunks = chunk_by_structure(research_paper)\n", - "\n", - "print(\n", - " f\"\"\"📊 Strategy 1: Document-Based (Structure-Aware) Chunking\n", - "{'=' * 80}\n", - "Original document: {paper_tokens:,} tokens\n", - "Number of chunks: {len(structure_chunks)}\n", - "\n", - "Chunk breakdown:\n", - "\"\"\"\n", - ")\n", - "\n", - "for i, chunk in enumerate(structure_chunks):\n", - " chunk_tokens = count_tokens(chunk)\n", - " # Show first 100 chars of each chunk\n", - " preview = chunk[:300].replace(\"\\n\", \" \")\n", - " print(f\" Chunk {i+1}: {chunk_tokens:,} tokens - {preview}...\\n\")\n" - ] - }, - { - "cell_type": "markdown", - "id": "96f1d657ce79b657", - "metadata": {}, - "source": [ - "**Strategy 1 Analysis:**\n", - "\n", - "✅ **Advantages:**\n", - "- Respects document structure (sections stay together)\n", - "- Semantically coherent (each chunk is a complete section)\n", - "- Easy to implement for structured documents\n", - "- Preserves author's logical organization\n", - "- **Keeps tables, formulas, and code WITH their context** (e.g., \"## 3. Performance Analysis\" section includes Table 1 WITH its explanation, and \"## 3.2 Mathematical Model\" includes the formula WITH its variable definitions)\n", - "\n", - "⚠️ **Trade-offs:**\n", - "- Variable chunk sizes (some sections longer than others)\n", - "- Requires documents to have clear structure\n", - "- May create chunks that are still too large\n", - "- Doesn't work for unstructured text\n", - "\n", - "🎯 **Best for:**\n", - "- Research papers with clear sections\n", - "- Technical documentation with headers\n", - "- Books with chapters/sections\n", - "- Any markdown/HTML content with structural markers\n", - "\n", - "💡 **Key Insight:**\n", - "Notice how Chunk 3 (\"## 3. Performance Analysis and Results\") contains Table 1 along with its explanation and interpretation. This is the correct approach - the table is meaningless without context. Similarly, the mathematical formula in section 3.2 stays with its variable definitions and interpretation. This is why structure-aware chunking is superior to fixed-size chunking for technical documents." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e76ccfaddbd73afe", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:16:59.014056Z", - "start_time": "2025-11-04T21:16:59.012297Z" - } - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "35cb95169c19d8fd", - "metadata": {}, - "source": [ - "### Strategy 2: Fixed-Size Chunking (Token-Based)\n", - "\n", - "**Concept:** Split text into chunks of a predetermined size (e.g., 512 tokens) with overlap.\n", - "\n", - "**Best for:** Unstructured text, quick prototyping, when you need consistent chunk sizes.\n", - "\n", - "Trade-offs:\n", - "- Ignores document structure (may split mid-sentence or mid-paragraph or mid-table)\n", - "- Can break semantic coherence\n", - "- May split important information across chunks" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "c370a104c561f59a", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:17:00.068503Z", - "start_time": "2025-11-04T21:17:00.051846Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:26.259835Z", - "iopub.status.busy": "2025-11-05T13:43:26.259723Z", - "iopub.status.idle": "2025-11-05T13:43:26.273094Z", - "shell.execute_reply": "2025-11-05T13:43:26.272720Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🔄 Running fixed-size chunking with LangChain...\n", - " Trying to split on: paragraphs → sentences → words → characters\n", - "\n", - "📊 Strategy 2: Fixed-Size (LangChain) Chunking\n", - "================================================================================\n", - "Original document: 1,035 tokens\n", - "Target chunk size: 800 characters (~200 words)\n", - "Overlap: 100 characters\n", - "Number of chunks: 8\n", - "\n", - "Chunk breakdown:\n", - "\n", - " Chunk 1: 117 tokens - # Optimizing Vector Search Performance in Redis ## Abstract This paper presents a comprehensive ana...\n", - " Chunk 2: 98 tokens - ## 1. Introduction Vector databases have become essential infrastructure for modern AI applications,...\n", - " Chunk 3: 134 tokens - [... 5,000 more words covering methodology, experiments, results, discussion ...] ## 2. Background ...\n", - " Chunk 4: 128 tokens - ## 3. Performance Analysis and Results ### 3.1 HNSW Configuration Trade-offs Table 1 shows the per...\n", - " Chunk 5: 206 tokens - Table 1: HNSW Performance Comparison | M | ef_construction | Recall@10 | Latency (ms) | Memory (GB)...\n", - "... (3 more chunks)\n" - ] - } - ], - "source": [ - "# Strategy 2: Fixed-Size Chunking (Using LangChain)\n", - "# Industry-standard approach with smart boundary detection\n", - "\n", - "from langchain_text_splitters import RecursiveCharacterTextSplitter\n", - "\n", - "# Create text splitter with smart boundary detection\n", - "text_splitter = RecursiveCharacterTextSplitter(\n", - " chunk_size=800, # Target chunk size in characters\n", - " chunk_overlap=100, # Overlap to preserve context\n", - " length_function=len,\n", - " separators=[\"\\n\\n\", \"\\n\", \". \", \" \", \"\"], # Try these in order\n", - " is_separator_regex=False,\n", - ")\n", - "\n", - "print(\"🔄 Running fixed-size chunking with LangChain...\")\n", - "print(\" Trying to split on: paragraphs → sentences → words → characters\\n\")\n", - "\n", - "# Apply to research paper\n", - "fixed_chunks_docs = text_splitter.create_documents([research_paper])\n", - "fixed_chunks = [doc.page_content for doc in fixed_chunks_docs]\n", - "\n", - "print(\n", - " f\"\"\"📊 Strategy 2: Fixed-Size (LangChain) Chunking\n", - "{'=' * 80}\n", - "Original document: {paper_tokens:,} tokens\n", - "Target chunk size: 800 characters (~200 words)\n", - "Overlap: 100 characters\n", - "Number of chunks: {len(fixed_chunks)}\n", - "\n", - "Chunk breakdown:\n", - "\"\"\"\n", - ")\n", - "\n", - "for i, chunk in enumerate(fixed_chunks[:5]): # Show first 5\n", - " chunk_tokens = count_tokens(chunk)\n", - " preview = chunk[:100].replace(\"\\n\", \" \")\n", - " print(f\" Chunk {i+1}: {chunk_tokens:,} tokens - {preview}...\")\n", - "\n", - "print(f\"... ({len(fixed_chunks) - 5} more chunks)\")" - ] - }, - { - "cell_type": "markdown", - "id": "e403c38d9a9d0a06", - "metadata": {}, - "source": [ - "**Strategy 2 Analysis:**\n", - "\n", - "✅ **Advantages:**\n", - "- **Respects natural boundaries**: Tries paragraphs → sentences → words → characters\n", - "- Consistent chunk sizes (predictable token usage)\n", - "- Works on any text (structured or unstructured)\n", - "- Fast processing\n", - "- **Doesn't split mid-sentence** (unless absolutely necessary)\n", - "\n", - "⚠️ **Trade-offs:**\n", - "- Ignores document structure (doesn't understand sections)\n", - "- Can break semantic coherence (may split related content)\n", - "- Overlap creates redundancy (increases storage/cost)\n", - "- May split important information across chunks\n", - "\n", - "🎯 **Best for:**\n", - "- Unstructured text (no clear sections)\n", - "- Quick prototyping and baselines\n", - "- When consistent chunk sizes are required\n", - "- Simple documents where structure doesn't matter\n", - "\n", - "💡 **How RecursiveCharacterTextSplitter Works:**\n", - "\n", - "Unlike naive fixed-size splitting, this algorithm:\n", - "\n", - "1. **Tries separators in order**: `[\"\\n\\n\", \"\\n\", \". \", \" \", \"\"]`\n", - "2. **Splits on first successful separator** that keeps chunks under target size\n", - "3. **Falls back to next separator** if chunks are still too large\n", - "4. **Preserves natural boundaries** (paragraphs > sentences > words > characters)\n", - "\n", - "**Example:**\n", - "- Target: 800 characters\n", - "- First try: Split on `\\n\\n` (paragraphs)\n", - "- If paragraph > 800 chars: Split on `\\n` (lines)\n", - "- If line > 800 chars: Split on `. ` (sentences)\n", - "- And so on...\n", - "\n", - "**Why this is better than naive splitting:**\n", - "- ✅ Respects natural text boundaries\n", - "- ✅ Doesn't split mid-sentence (unless necessary)\n", - "- ✅ Maintains readability\n", - "- ✅ Better for LLM comprehension" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5f37f437b3aa4541", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:17:04.920222Z", - "start_time": "2025-11-04T21:17:04.917767Z" - } - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "ca46498e87604fa5", - "metadata": {}, - "source": [ - "### Strategy 3: Semantic Chunking (Meaning-Based)\n", - "\n", - "**Concept:** Split text based on semantic similarity using embeddings - create new chunks when topic changes significantly.\n", - "\n", - "**How it works:**\n", - "1. Split text into sentences or paragraphs\n", - "2. Generate embeddings for each segment\n", - "3. Calculate similarity between consecutive segments\n", - "4. Create chunk boundaries where similarity drops (topic shift detected)\n", - "\n", - "**Best for:** Dense academic text, legal documents, narratives where semantic boundaries don't align with structure." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "de5dadba814863e0", - "metadata": { - "ExecuteTime": { - "end_time": "2025-11-04T21:17:06.687906Z", - "start_time": "2025-11-04T21:17:06.551885Z" - }, - "execution": { - "iopub.execute_input": "2025-11-05T13:43:26.274572Z", - "iopub.status.busy": "2025-11-05T13:43:26.274474Z", - "iopub.status.idle": "2025-11-05T13:43:28.853108Z", - "shell.execute_reply": "2025-11-05T13:43:28.852649Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:27 sentence_transformers.SentenceTransformer INFO Load pretrained SentenceTransformer: sentence-transformers/all-MiniLM-L6-v2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🔄 Running semantic chunking with LangChain...\n", - " Using local embeddings (sentence-transformers/all-MiniLM-L6-v2)\n", - " Breakpoint detection: 25th percentile of similarity scores\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Strategy 3: Semantic (LangChain) Chunking\n", - "================================================================================\n", - "Original document: 1,035 tokens\n", - "Breakpoint method: Percentile (25th percentile)\n", - "Number of chunks: 25\n", - "\n", - "Chunk breakdown:\n", - "\n", - " Chunk 1: 70 tokens - # Optimizing Vector Search Performance in Redis ## Abstract This paper presents a comprehensive analysis of vector search optimization techniques in Redis, examining the trade-offs between search qu...\n", - "\n", - " Chunk 2: 26 tokens - Our results demonstrate that careful index configuration can improve search latency by up to 10x while maintaining 95%+ recall....\n", - "\n", - " Chunk 3: 22 tokens - We also introduce novel compression techniques that reduce memory usage by 75% with minimal impact on search quality....\n", - "\n", - " Chunk 4: 4 tokens - ## 1....\n", - "\n", - " Chunk 5: 60 tokens - Introduction Vector databases have become essential infrastructure for modern AI applications, enabling semantic search, recommendation systems, and retrieval-augmented generation (RAG). Redis, tradit...\n", - "\n", - " Chunk 6: 16 tokens - However, optimizing vector search performance requires understanding complex trade-offs between multiple dimensions......\n", - "\n", - " Chunk 7: 2 tokens - [......\n", - "\n", - " Chunk 8: 18 tokens - 5,000 more words covering methodology, experiments, results, discussion ...] ## 2....\n", - "\n", - " Chunk 9: 60 tokens - Background and Related Work Previous work on vector search optimization has focused primarily on algorithmic improvements to approximate nearest neighbor (ANN) search. Malkov and Yashunin (2018) intro...\n", - "\n", - " Chunk 10: 4 tokens - Johnson et al....\n", - "\n", - " Chunk 11: 20 tokens - (2019) developed FAISS, demonstrating that product quantization can significantly reduce memory usage......\n", - "\n", - " Chunk 12: 2 tokens - [......\n", - "\n", - " Chunk 13: 10 tokens - 2,000 more words ...] ## 3....\n", - "\n", - " Chunk 14: 91 tokens - Performance Analysis and Results ### 3.1 HNSW Configuration Trade-offs Table 1 shows the performance comparison across different HNSW configurations. As M increases from 16 to 64, we observe signifi...\n", - "\n", - " Chunk 15: 33 tokens - The sweet spot for most production workloads is M=32 with ef_construction=200, which achieves 0.94 recall with 4.3ms latency....\n", - "\n", - " Chunk 16: 177 tokens - Table 1: HNSW Performance Comparison | M | ef_construction | Recall@10 | Latency (ms) | Memory (GB) | Build Time (min) | |----|-----------------|-----------|--------------|-------------|-------------...\n", - "\n", - " Chunk 17: 159 tokens - ### 3.2 Mathematical Model The recall-latency trade-off can be modeled as a quadratic function of the HNSW parameters: Latency(M, ef) = α·M² + β·ef + γ Where: - M = number of connections per layer ...\n", - "\n", - " Chunk 18: 4 tokens - ## 4....\n", - "\n", - " Chunk 19: 139 tokens - Implementation Recommendations Based on our findings, we recommend the following configuration for production deployments: ```python # Optimal HNSW configuration for balanced performance index_param...\n", - "\n", - " Chunk 20: 31 tokens - For applications requiring maximum recall (>0.95), use M=64 with ef_construction=400, but ensure adequate memory and accept higher latency....\n", - "\n", - " Chunk 21: 2 tokens - [......\n", - "\n", - " Chunk 22: 35 tokens - 1,500 more words with additional analysis ...] ## 5. Discussion and Conclusion Our findings demonstrate that vector search optimization is fundamentally about understanding YOUR specific requirements...\n", - "\n", - " Chunk 23: 10 tokens - There is no one-size-fits-all configuration....\n", - "\n", - " Chunk 24: 37 tokens - The choice between HNSW parameters depends on your specific recall requirements, latency budget, and memory constraints. We provide a mathematical model and practical guidelines to help practitioners ...\n", - "\n", - " Chunk 25: 0 tokens - ...\n", - "\n" - ] - } - ], - "source": [ - "# Strategy 3: Semantic Chunking (Using LangChain)\n", - "# Industry-standard approach with local embeddings (no API costs!)\n", - "\n", - "from langchain_experimental.text_splitter import SemanticChunker\n", - "from langchain_huggingface import HuggingFaceEmbeddings\n", - "import os\n", - "\n", - "# Suppress tokenizer warnings\n", - "os.environ[\"TOKENIZERS_PARALLELISM\"] = \"false\"\n", - "\n", - "# Initialize local embeddings (no API costs!)\n", - "embeddings = HuggingFaceEmbeddings(\n", - " model_name=\"sentence-transformers/all-MiniLM-L6-v2\",\n", - " model_kwargs={\"device\": \"cpu\"},\n", - " encode_kwargs={\"normalize_embeddings\": True},\n", - ")\n", - "\n", - "# Create semantic chunker with percentile-based breakpoint detection\n", - "semantic_chunker = SemanticChunker(\n", - " embeddings=embeddings,\n", - " breakpoint_threshold_type=\"percentile\", # Split at bottom 25% of similarities\n", - " breakpoint_threshold_amount=25, # 25th percentile\n", - " buffer_size=1, # Compare consecutive sentences\n", - ")\n", - "\n", - "print(\"🔄 Running semantic chunking with LangChain...\")\n", - "print(\" Using local embeddings (sentence-transformers/all-MiniLM-L6-v2)\")\n", - "print(\" Breakpoint detection: 25th percentile of similarity scores\\n\")\n", - "\n", - "# Apply to research paper\n", - "semantic_chunks_docs = semantic_chunker.create_documents([research_paper])\n", - "\n", - "# Extract text from Document objects\n", - "semantic_chunks = [doc.page_content for doc in semantic_chunks_docs]\n", - "\n", - "print(\n", - " f\"\"\"📊 Strategy 3: Semantic (LangChain) Chunking\n", - "{'=' * 80}\n", - "Original document: {paper_tokens:,} tokens\n", - "Breakpoint method: Percentile (25th percentile)\n", - "Number of chunks: {len(semantic_chunks)}\n", - "\n", - "Chunk breakdown:\n", - "\"\"\"\n", - ")\n", - "\n", - "for i, chunk in enumerate(semantic_chunks):\n", - " chunk_tokens = count_tokens(chunk)\n", - " preview = chunk[:200].replace(\"\\n\", \" \")\n", - " print(f\" Chunk {i+1}: {chunk_tokens:,} tokens - {preview}...\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "29c4d65b4ad36fd9", - "metadata": {}, - "source": [ - "**Strategy 3 Analysis:**\n", - "\n", - "✅ **Advantages:**\n", - "- **Detects actual topic changes** using semantic similarity (not just structural markers)\n", - "- Preserves semantic coherence (topics stay together even without headers)\n", - "- Better retrieval quality (chunks are topically focused)\n", - "- Adapts to content (works on unstructured text)\n", - "- Reduces context loss at boundaries (doesn't split mid-topic)\n", - "- **Free and local**: Uses sentence-transformers (no API costs)\n", - "\n", - "⚠️ **Trade-offs:**\n", - "- Slower processing (must compute embeddings for each sentence)\n", - "- Variable chunk sizes (depends on topic boundaries)\n", - "- Higher computational cost (embedding computation + similarity calculations)\n", - "- Requires initial model download (~90MB for all-MiniLM-L6-v2)\n", - "\n", - "🎯 **Best for:**\n", - "- Dense academic papers with complex topic transitions\n", - "- Legal documents where semantic sections don't have headers\n", - "- Narratives where topics don't align with structure\n", - "- Unstructured text (emails, transcripts, conversations)\n", - "- When retrieval quality is more important than processing speed\n", - "\n", - "💡 **How Percentile-Based Breakpoint Detection Works:**\n", - "\n", - "Instead of using a fixed similarity threshold (e.g., 0.75), the percentile method:\n", - "\n", - "1. **Computes all similarities** between consecutive sentences\n", - "2. **Calculates percentiles** of the similarity distribution\n", - "3. **Creates breakpoints** where similarity is in the bottom X percentile\n", - "\n", - "**Example:**\n", - "- Similarities: [0.92, 0.88, 0.45, 0.91, 0.35, 0.89]\n", - "- 25th percentile: 0.45\n", - "- Breakpoints created at: positions 2 (0.45) and 4 (0.35)\n", - "\n", - "**Why this is better than fixed threshold:**\n", - "- ✅ Adapts to document's similarity distribution\n", - "- ✅ Works across different document types\n", - "- ✅ No manual threshold tuning needed\n", - "- ✅ More robust to outliers\n", - "\n", - "**Alternative Breakpoint Methods:**\n", - "- `\"gradient\"`: Detects sudden drops in similarity (topic shifts)\n", - "- `\"standard_deviation\"`: Uses statistical deviation from mean\n", - "- `\"interquartile\"`: Uses IQR-based outlier detection\n", - "\n", - "This is fundamentally different from structure-based chunking - it detects semantic boundaries regardless of headers or formatting." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "20fca0e15cdba8d9", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## Deep Dive: Document Types and Specialized Chunking Strategies\n", - "\n", - "The chunking strategies we've covered (document-based, fixed-size, semantic) are foundational approaches. However, real-world documents often require specialized handling based on their content type and structure.\n", - "\n", - "Let's explore three distinct document categories that require different chunking considerations:\n", - "\n", - "### 1. Multi-Modal Documents: Research Papers, Books, Technical Reports\n", - "\n", - "These documents contain **heterogeneous content types** that require specialized handling beyond simple text chunking.\n", - "\n", - "**Content Types in Multi-Modal Documents:**\n", - "\n", - "1. **Text sections** (prose, paragraphs)\n", - " - Standard semantic or structure-aware chunking works well\n", - " - Can use any of the strategies we've covered\n", - "\n", - "2. **Mathematical formulas and equations**\n", - " - ⚠️ **Critical:** Must be kept intact with surrounding context\n", - " - Splitting a formula from its explanation renders it meaningless\n", - " - Example: `Latency(M, ef) = α·M² + β·ef + γ` needs variable definitions\n", - "\n", - "3. **Charts, graphs, and figures**\n", - " - May require **image extraction** and separate processing\n", - " - Options:\n", - " - **Multimodal embeddings** (CLIP, GPT-4V) to embed images directly\n", - " - **OCR** to extract text from images\n", - " - **Caption + description** as text proxy\n", - " - Keep figure WITH its caption and reference in text\n", - "\n", - "4. **Tables**\n", - " - ⚠️ **Critical:** Should be kept as complete units\n", - " - Options:\n", - " - Keep table WITH caption and explanation (best for retrieval)\n", - " - Convert to structured format (JSON, CSV) for programmatic access\n", - " - Use multimodal models to understand table structure\n", - " - Never split a table across chunks\n", - "\n", - "**Key Benefits of Proper Chunking for Multi-Modal Documents:**\n", - "\n", - "Based on research and industry best practices:\n", - "\n", - "1. **Token Limit Management**\n", - " - Ensures content fits within model context windows\n", - " - Prevents truncation of critical information\n", - " - Allows processing of arbitrarily large documents\n", - "\n", - "2. **Improved Retrieval Precision** ([Chroma Research, 2024](https://research.trychroma.com/evaluating-chunking))\n", - " - Smaller, focused chunks create more accurate embeddings\n", - " - Reduces \"distractor effect\" from irrelevant content\n", - " - Improves ranking of relevant information\n", - "\n", - "3. **Context Preservation**\n", - " - Keeps semantically related information together\n", - " - Maintains the author's logical flow\n", - " - Preserves relationships between text, formulas, and figures\n", - "\n", - "4. **Computational Efficiency**\n", - " - Faster embedding generation (smaller chunks)\n", - " - Reduced API costs (fewer tokens per request)\n", - " - Better memory utilization\n", - "\n", - "**Chunk Overlap: A Critical Technique**\n", - "\n", - "For multi-modal documents, **chunk overlap** (10-20%) is often beneficial:\n", - "\n", - "- **Prevents splitting mid-concept**: Overlap ensures related information isn't fragmented\n", - "- **Preserves context across boundaries**: Important for formulas, tables, and figures\n", - "- **Improves retrieval recall**: Increases chances of capturing relevant information\n", - "\n", - "**Example:**\n", - "```\n", - "Chunk 1: \"...The HNSW algorithm uses parameter M to control connectivity. [OVERLAP START] Higher M values improve recall but increase latency. [OVERLAP END]\"\n", - "\n", - "Chunk 2: \"[OVERLAP START] Higher M values improve recall but increase latency. [OVERLAP END] Table 1 shows the trade-offs...\"\n", - "```\n", - "\n", - "This ensures that if a query matches \"M parameter effects,\" both chunks can be retrieved." - ], - "id": "e5562d68caafb951" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "132c0b2f24f99ace" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Other Effective Chunking Strategies (Beyond the Basics)\n", - "\n", - "While we've covered the four main strategies, research and industry practice have identified several other effective approaches:\n", - "\n", - "**1. Page-Level Chunking**\n", - "\n", - "**Concept:** Use natural page boundaries as chunk boundaries.\n", - "\n", - "**Best for:** Structured documents like financial reports, legal filings, academic papers\n", - "\n", - "**Why it works:**\n", - "- Page boundaries often align with coherent information units\n", - "- Preserves visual layout (tables, figures stay with their page)\n", - "- Proven effective for financial documents ([NVIDIA Research, 2024](https://developer.nvidia.com/blog/finding-the-best-chunking-strategy-for-accurate-ai-responses/))\n", - "\n", - "**Trade-offs:**\n", - "- Variable chunk sizes (pages vary in content density)\n", - "- May not work for digital-first documents without page concept\n", - "- Requires PDF or paginated source\n", - "\n", - "**Example use case:** 10-K financial reports where each page contains related financial data, tables, and explanations.\n", - "\n", - "**2. Structure-Aware (Markdown/HTML) Chunking**\n", - "\n", - "**Concept:** Split by hierarchical boundaries (headings, subheadings) while preserving document structure.\n", - "\n", - "**Best for:** Technical documentation, wikis, markdown-based content\n", - "\n", - "**Why it works:**\n", - "- Maintains logical flow of information\n", - "- Respects author's intended organization\n", - "- Natural semantic boundaries\n", - "\n", - "**Implementation:**\n", - "```python\n", - "# Split by heading hierarchy\n", - "def chunk_by_headers(markdown_text):\n", - " # Split on ## headers (sections)\n", - " # Keep ### subsections with their parent section\n", - " # Preserve code blocks, tables within sections\n", - "```\n", - "\n", - "**3. Recursive Chunking**\n", - "\n", - "**Concept:** Split by progressively smaller separators until target size is reached.\n", - "\n", - "**Separator hierarchy:** `paragraphs → sentences → words → characters`\n", - "\n", - "**Why it works:**\n", - "- Preserves semantic coherence at multiple levels\n", - "- Adapts to content structure\n", - "- Avoids hard breaks mid-sentence\n", - "\n", - "**This is what LangChain's `RecursiveCharacterTextSplitter` does** (Strategy 2 above).\n", - "\n", - "**4. Semantic Chunking with Embeddings**\n", - "\n", - "**Concept:** Use embeddings to group semantically related sentences into coherent ideas.\n", - "\n", - "**Why it works:**\n", - "- Detects topic boundaries even without structural markers\n", - "- Works across structural boundaries (e.g., related content in different sections)\n", - "- Adapts to content semantics, not just structure\n", - "\n", - "**This is what LangChain's `SemanticChunker` does** (Strategy 3 above).\n", - "\n", - "**5. Contextual Retrieval** ([Anthropic, 2024](https://www.anthropic.com/news/contextual-retrieval))\n", - "\n", - "**Concept:** Add LLM-generated context to each chunk before embedding.\n", - "\n", - "**How it works:**\n", - "1. For each chunk, generate a brief context: \"This chunk is from Section 3.2 discussing HNSW parameters...\"\n", - "2. Prepend context to chunk before embedding\n", - "3. Embed: `[context] + [chunk]`\n", - "\n", - "**Results:** Reduces retrieval failures by 49-67% (Anthropic research)\n", - "\n", - "**Why it works:**\n", - "- Chunks become self-contained (don't rely on surrounding context)\n", - "- Improves embedding quality (more context = better representation)\n", - "- Helps with cross-references and dependencies\n", - "\n", - "**6. Late Chunking** ([Jina AI, 2024](https://arxiv.org/abs/2409.04701))\n", - "\n", - "**Concept:** Embed the entire document first, then chunk the embeddings.\n", - "\n", - "**How it works:**\n", - "1. Generate embeddings for entire document using long-context model\n", - "2. Chunk the embedding space (not the text)\n", - "3. Each chunk's embedding preserves full document context\n", - "\n", - "**Results:** Preserves cross-chunk context without ColBERT-level storage costs\n", - "\n", - "**Why it works:**\n", - "- Embeddings capture full document context\n", - "- Chunking happens in embedding space, preserving relationships\n", - "- Best of both worlds: whole-document context + chunk-level retrieval\n", - "\n", - "**7. Agentic/Proposition-Based Chunking**\n", - "\n", - "**Concept:** Use LLMs to extract atomic propositions (facts) from text, then chunk by propositions.\n", - "\n", - "**How it works:**\n", - "1. LLM extracts individual facts/claims from text\n", - "2. Group related propositions into chunks\n", - "3. Each chunk contains semantically related facts\n", - "\n", - "**Best for:** Dense academic text, legal documents, fact-heavy content\n", - "\n", - "**Trade-offs:** High computational cost (LLM calls for every document)" - ], - "id": "c1c97b3ecb80ab64" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "9245017126688c70" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### 2. Legal Contracts and Clause-Level Documents\n", - "\n", - "**⚠️ Important:** Legal contracts represent a **fundamentally different challenge** that goes beyond simple chunking into the realm of **complex data engineering and knowledge modeling**.\n", - "\n", - "**Why Legal Documents Are Different:**\n", - "\n", - "1. **Clause-Level Granularity**\n", - " - Each clause may need to be a separate retrieval unit\n", - " - Clauses have specific legal meanings and purposes\n", - " - Example: \"Termination Clause,\" \"Indemnification Clause,\" \"Force Majeure\"\n", - "\n", - "2. **Cross-References and Dependencies**\n", - " - Clauses often reference other clauses: \"as defined in Section 3.2\"\n", - " - Understanding one clause may require reading referenced clauses\n", - " - Circular dependencies are common\n", - "\n", - "3. **Hierarchical Structure**\n", - " - Parent-child relationships: Sections → Subsections → Clauses → Sub-clauses\n", - " - Inheritance of terms and conditions\n", - " - Nested definitions and exceptions\n", - "\n", - "4. **Legal Precedence and Overrides**\n", - " - Some clauses modify or override others\n", - " - \"Notwithstanding Section 2.1...\" creates dependency\n", - " - Amendment clauses change earlier provisions\n", - "\n", - "5. **Rich Metadata Requirements**\n", - " - Clause type (termination, payment, liability, etc.)\n", - " - Parties involved (which party has obligations)\n", - " - Effective dates and conditions\n", - " - Jurisdiction and governing law\n", - "\n", - "**What This Requires:**\n", - "\n", - "Simple chunking is **insufficient** for legal documents. You need:\n", - "\n", - "**1. Advanced Data Modeling**\n", - "- **Knowledge graphs** to capture clause relationships\n", - "- **Hierarchical structures** to preserve document organization\n", - "- **Dependency tracking** for cross-references\n", - "\n", - "**Example knowledge graph:**\n", - "```\n", - "Clause 3.2 (Payment Terms)\n", - " ├─ references → Clause 1.5 (Definitions: \"Net 30\")\n", - " ├─ modified_by → Clause 8.1 (Amendment: \"Net 45 for Q4\")\n", - " └─ depends_on → Clause 2.1 (Delivery Conditions)\n", - "```\n", - "\n", - "**2. Custom Chunking Logic**\n", - "- Domain-specific rules for legal document structure\n", - "- Clause boundary detection (not just paragraphs)\n", - "- Preservation of numbering and hierarchy\n", - "\n", - "**3. Context Assembly Strategies**\n", - "- **Recursive retrieval**: When retrieving Clause 3.2, also fetch referenced clauses\n", - "- **Graph traversal**: Follow dependency links to build complete context\n", - "- **Hierarchical expansion**: Include parent section context\n", - "\n", - "**Example Retrieval Flow:**\n", - "```\n", - "Query: \"What are the payment terms?\"\n", - "\n", - "1. Retrieve: Clause 3.2 (Payment Terms)\n", - "2. Detect references: \"as defined in Section 1.5\"\n", - "3. Fetch: Clause 1.5 (Definitions)\n", - "4. Detect modifications: Clause 8.1 modifies 3.2\n", - "5. Fetch: Clause 8.1 (Amendment)\n", - "6. Assemble context: [3.2 + 1.5 + 8.1] with relationship metadata\n", - "```\n", - "\n", - "**Research and Industry Approaches:**\n", - "\n", - "- **Multi-Graph Multi-Agent Systems** ([Medium, 2024](https://medium.com/enterprise-rag/legal-document-rag-multi-graph-multi-agent-recursive-retrieval-through-legal-clauses-c90e073e0052))\n", - " - Use multiple knowledge graphs to model different relationship types\n", - " - Agent-based recursive retrieval through clause dependencies\n", - "\n", - "- **GraphRAG for Legal Contracts** ([Neo4j, 2024](https://neo4j.com/blog/developer/agentic-graphrag-for-commercial-contracts/))\n", - " - Build knowledge graphs from contract structure\n", - " - Use graph queries to navigate clause relationships\n", - "\n", - "**💡 Discussion Question:**\n", - "\n", - "Do you agree that legal contracts represent a fundamentally different challenge that goes beyond chunking into the realm of complex data engineering and knowledge modeling?\n", - "\n", - "**Our Position:** Yes, absolutely. Legal documents require:\n", - "- **Not just chunking**, but **relationship modeling**\n", - "- **Not just retrieval**, but **dependency resolution**\n", - "- **Not just embeddings**, but **structured knowledge graphs**\n", - "\n", - "This is an **advanced topic beyond the scope of this module**, but it's important to recognize when simple chunking strategies are insufficient.\n", - "\n", - "**Recommendation:** For legal document RAG systems:\n", - "1. Start with clause-level chunking as a baseline\n", - "2. Add metadata enrichment (clause type, parties, dates)\n", - "3. Build knowledge graphs for relationships\n", - "4. Implement recursive retrieval for dependencies\n", - "5. Consider specialized legal NLP tools (e.g., LexNLP, Blackstone)\n", - "\n", - "This is a **research-level problem** that requires domain expertise in both legal document structure and advanced RAG techniques." - ], - "id": "7e805120e59e95d3" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "b224e9547a53e10f" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### 3. Transcripts and Meeting Notes: Temporal and Speaker-Based Chunking\n", - "\n", - "**Document Characteristics:**\n", - "- Conversational flow with speaker changes\n", - "- Temporal structure (time-based progression)\n", - "- Topic shifts without clear structural markers\n", - "- Interruptions, overlaps, and informal language\n", - "- Context depends on who said what and when\n", - "\n", - "**Examples:**\n", - "- Meeting transcripts (Zoom, Teams, Google Meet)\n", - "- Podcast transcripts\n", - "- Interview transcripts\n", - "- Customer service call recordings\n", - "- Presentation Q&A sessions\n", - "\n", - "**Why Standard Chunking Fails:**\n", - "\n", - "Traditional chunking strategies (fixed-size, semantic) don't account for:\n", - "- **Speaker identity**: Who said what matters for context\n", - "- **Temporal flow**: Conversations build on previous statements\n", - "- **Turn-taking**: Natural conversation boundaries\n", - "- **Topic drift**: Conversations meander without clear section breaks\n", - "\n", - "**Specialized Chunking Strategies for Transcripts:**\n", - "\n", - "**Strategy 1: Speaker-Based Chunking**\n", - "\n", - "**Concept:** Chunk by speaker turns, keeping each speaker's complete statement together.\n", - "\n", - "**Best for:** Interviews, Q&A sessions, debates\n", - "\n", - "**Implementation:**\n", - "```python\n", - "def chunk_by_speaker(transcript):\n", - " \"\"\"\n", - " Input: \"Speaker A: Hello, how are you? Speaker B: I'm good, thanks!\"\n", - " Output: [\n", - " \"Speaker A: Hello, how are you?\",\n", - " \"Speaker B: I'm good, thanks!\"\n", - " ]\n", - " \"\"\"\n", - " # Split on speaker labels\n", - " # Keep speaker identity with each chunk\n", - " # Preserve turn-taking structure\n", - "```\n", - "\n", - "**Pros:**\n", - "- Preserves speaker context\n", - "- Natural conversation boundaries\n", - "- Easy to attribute statements\n", - "\n", - "**Cons:**\n", - "- Variable chunk sizes (some speakers talk more)\n", - "- May split related topics across speakers\n", - "\n", - "**Strategy 2: Time-Based Chunking**\n", - "\n", - "**Concept:** Chunk by time intervals (e.g., 2-minute segments).\n", - "\n", - "**Best for:** Long meetings, podcasts, lectures\n", - "\n", - "**Implementation:**\n", - "```python\n", - "def chunk_by_time(transcript_with_timestamps, interval_seconds=120):\n", - " \"\"\"\n", - " Input: [(0, \"Speaker A: ...\"), (45, \"Speaker B: ...\"), (130, \"Speaker A: ...\")]\n", - " Output: [\n", - " \"00:00-02:00: [Speaker A: ...] [Speaker B: ...]\",\n", - " \"02:00-04:00: [Speaker A: ...]\"\n", - " ]\n", - " \"\"\"\n", - " # Group utterances by time windows\n", - " # Preserve timestamps for reference\n", - "```\n", - "\n", - "**Pros:**\n", - "- Consistent chunk sizes\n", - "- Easy to reference (\"at 15:30 in the meeting\")\n", - "- Works well for long recordings\n", - "\n", - "**Cons:**\n", - "- May split mid-sentence or mid-topic\n", - "- Doesn't respect conversation flow\n", - "\n", - "**Strategy 3: Topic-Based Chunking (Semantic + Speaker-Aware)**\n", - "\n", - "**Concept:** Detect topic shifts using embeddings + speaker changes.\n", - "\n", - "**Best for:** Multi-topic meetings, panel discussions\n", - "\n", - "**Implementation:**\n", - "```python\n", - "def chunk_by_topic_and_speaker(transcript):\n", - " \"\"\"\n", - " 1. Compute embeddings for each utterance\n", - " 2. Detect topic shifts (low similarity between consecutive utterances)\n", - " 3. Also create boundaries at speaker changes\n", - " 4. Merge short chunks (< min_size)\n", - " \"\"\"\n", - " # Hybrid approach: semantic + speaker-aware\n", - "```\n", - "\n", - "**Pros:**\n", - "- Respects both topic and speaker boundaries\n", - "- Most semantically coherent chunks\n", - "- Adapts to conversation structure\n", - "\n", - "**Cons:**\n", - "- Computationally expensive (embeddings for each utterance)\n", - "- Requires speaker diarization\n", - "\n", - "**Strategy 4: Silence-Aware Merging**\n", - "\n", - "**Concept:** Use silence/pauses in audio to detect natural boundaries.\n", - "\n", - "**Best for:** Presentations, lectures with clear pauses\n", - "\n", - "**How it works:**\n", - "- Audio processing detects pauses (e.g., >2 seconds of silence)\n", - "- Merge utterances between pauses into chunks\n", - "- Preserves natural speaking rhythm\n", - "\n", - "**Source:** VoxRAG (arXiv:2505.17326, 2025) - transcription-free RAG using silence-aware chunking\n", - "\n", - "**Pros:**\n", - "- Natural conversation boundaries\n", - "- Works without speaker diarization\n", - "- Respects speaker's pacing\n", - "\n", - "**Cons:**\n", - "- Requires audio access (not just transcript)\n", - "- Pauses don't always align with topic shifts\n", - "\n", - "**Advanced Technique: Speaker Diarization + Chunking**\n", - "\n", - "**What is Speaker Diarization?**\n", - "- Automatic detection of \"who spoke when\"\n", - "- Assigns speaker labels (Speaker 1, Speaker 2, etc.)\n", - "- Essential for multi-speaker transcripts\n", - "\n", - "**How to combine with chunking:**\n", - "1. **Diarize audio** → identify speakers\n", - "2. **Transcribe with speaker labels** → \"Speaker A: Hello...\"\n", - "3. **Chunk by speaker + topic** → preserve context\n", - "\n", - "**Tools:**\n", - "- **Parakeet/Whisper**: Fast transcription with speaker labels\n", - "- **pyannote.audio**: State-of-the-art speaker diarization\n", - "- **AssemblyAI**: Commercial API with built-in diarization\n", - "\n", - "**Example Use Case: Meeting Minutes RAG**\n", - "\n", - "**Scenario:** Build a RAG system for company meeting transcripts.\n", - "\n", - "**Requirements:**\n", - "- Answer questions like \"What did Sarah say about the budget?\"\n", - "- Retrieve action items assigned to specific people\n", - "- Find discussions about specific topics\n", - "\n", - "**Recommended Approach:**\n", - "1. **Transcribe with speaker diarization** (Whisper + pyannote)\n", - "2. **Chunk by speaker + topic** (hybrid approach)\n", - "3. **Enrich with metadata**:\n", - " - Speaker name\n", - " - Timestamp\n", - " - Meeting title/date\n", - " - Detected topics (using LLM)\n", - "4. **Store chunks with metadata** in vector DB\n", - "5. **Implement metadata filtering** (e.g., \"speaker:Sarah AND topic:budget\")\n", - "\n", - "**Metadata Enrichment Example:**\n", - "```python\n", - "chunk = {\n", - " \"text\": \"Sarah: I think we should increase the marketing budget by 20%...\",\n", - " \"metadata\": {\n", - " \"speaker\": \"Sarah Johnson\",\n", - " \"timestamp\": \"00:15:30\",\n", - " \"meeting\": \"Q4 Planning - 2025-04-15\",\n", - " \"topic\": \"budget\",\n", - " \"action_item\": False\n", - " }\n", - "}\n", - "```\n", - "\n", - "**💡 Key Insight:** Transcripts require **context-aware chunking** that preserves:\n", - "- **Who** said it (speaker identity)\n", - "- **When** they said it (temporal context)\n", - "- **What** they were discussing (topic/semantic content)\n", - "\n", - "Simple text chunking loses this critical context.\n", - "\n", - "**Recommendation:** For transcript RAG systems:\n", - "1. Start with speaker-based chunking as baseline\n", - "2. Add speaker diarization for multi-speaker content\n", - "3. Enrich chunks with metadata (speaker, time, topic)\n", - "4. Consider hybrid chunking (speaker + semantic) for complex conversations\n", - "5. Use metadata filtering to improve retrieval precision\n", - "\n", - "This is an **emerging area** with active research (VoxRAG, 2025) exploring transcription-free approaches." - ], - "id": "f7fddfa635761eb1" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "ff972f09018f8a7" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### 4. Implementation Guidance: Choosing Your Chunking Strategy\n", - "\n", - "The optimal chunking strategy requires **experimentation** based on your specific context. There's no universal \"best practice.\"\n", - "\n", - "**Factors to Consider:**\n", - "\n", - "1. **Specific Use Case and Query Patterns**\n", - " - What questions will users ask?\n", - " - Do they need summaries or specific facts?\n", - " - Are queries broad or narrow?\n", - "\n", - "2. **Document Type and Structure**\n", - " - Structured (sections, headers) or unstructured (prose)?\n", - " - Multi-modal (text + images + tables) or text-only?\n", - " - Single-topic or multi-topic documents?\n", - "\n", - "3. **Models Being Used**\n", - " - **Embedding model**: Context window size, quality on long vs. short text\n", - " - **LLM**: Context window, attention patterns, cost per token\n", - " - **Multimodal capabilities**: Can it handle images, tables?\n", - "\n", - "4. **Performance Metrics**\n", - " - **Retrieval precision**: Are you getting the right chunks?\n", - " - **Answer quality**: Are LLM responses accurate and complete?\n", - " - **Latency**: How fast do you need results?\n", - " - **Cost**: Token usage, API calls, storage\n", - "\n", - "**Experimentation Framework:**\n", - "\n", - "```python\n", - "# 1. Define your test queries\n", - "test_queries = [\n", - " \"What are the payment terms?\",\n", - " \"Explain the HNSW algorithm\",\n", - " \"What compression techniques were used?\"\n", - "]\n", - "\n", - "# 2. Try multiple chunking strategies\n", - "strategies = [\n", - " (\"no_chunking\", whole_document),\n", - " (\"document_based\", chunk_by_structure),\n", - " (\"fixed_size_512\", fixed_chunking_512),\n", - " (\"fixed_size_1024\", fixed_chunking_1024),\n", - " (\"semantic\", semantic_chunking),\n", - "]\n", - "\n", - "# 3. Measure performance\n", - "for strategy_name, chunking_fn in strategies:\n", - " chunks = chunking_fn(documents)\n", - "\n", - " # Measure retrieval precision\n", - " precision = evaluate_retrieval(chunks, test_queries)\n", - "\n", - " # Measure answer quality (LLM evaluation)\n", - " quality = evaluate_answers(chunks, test_queries, llm)\n", - "\n", - " # Measure efficiency\n", - " avg_chunk_size = np.mean([len(c) for c in chunks])\n", - " total_tokens = sum([count_tokens(c) for c in chunks])\n", - "\n", - " print(f\"{strategy_name}: Precision={precision:.2f}, Quality={quality:.2f}, Tokens={total_tokens}\")\n", - "```\n", - "\n", - "**Key Metrics to Track:**\n", - "\n", - "| Metric | What It Measures | How to Evaluate |\n", - "|--------|------------------|-----------------|\n", - "| **Retrieval Precision** | Are the right chunks retrieved? | Manual review or automated eval (LLM-as-judge) |\n", - "| **Answer Quality** | Are LLM responses accurate? | Human evaluation or LLM-based scoring |\n", - "| **Token Efficiency** | How many tokens per query? | Count tokens in retrieved chunks |\n", - "| **Latency** | How fast is retrieval? | Measure end-to-end query time |\n", - "| **Coverage** | Do chunks cover all important info? | Check if key facts are retrievable |\n", - "\n", - "**Iterative Improvement Process:**\n", - "\n", - "1. **Start simple**: Begin with fixed-size or document-based chunking\n", - "2. **Measure baseline**: Establish performance metrics\n", - "3. **Identify failures**: Where does retrieval fail? Where are answers wrong?\n", - "4. **Hypothesize improvements**: \"Tables are being split\" → Try structure-aware chunking\n", - "5. **Test and compare**: Measure impact of changes\n", - "6. **Iterate**: Repeat until performance is acceptable\n", - "\n", - "**Common Failure Patterns and Solutions:**\n", - "\n", - "| Problem | Likely Cause | Solution |\n", - "|---------|--------------|----------|\n", - "| Tables split across chunks | Fixed-size chunking | Use structure-aware chunking |\n", - "| Formulas without context | Naive chunking | Keep formulas with explanations |\n", - "| Missing cross-references | Single-chunk retrieval | Implement recursive retrieval |\n", - "| Generic answers | Chunks too large | Reduce chunk size or use semantic chunking |\n", - "| Incomplete answers | Chunks too small | Increase chunk size or add overlap |\n", - "\n", - "**💡 Final Insight:**\n", - "\n", - "Chunking is **data modeling for retrieval**. Just like database schema design, there's no one-size-fits-all solution. The \"best\" chunking strategy is the one that:\n", - "- Matches your document structure\n", - "- Aligns with your query patterns\n", - "- Meets your performance requirements\n", - "- Balances complexity with maintainability\n", - "\n", - "**Experiment, measure, iterate.**" - ], - "id": "bf1ee61a2c702ebd" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "1239169f5ffbbee9" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Strategy 4: Hierarchical Chunking (Multi-Level)\n", - "\n", - "**Concept:** Create multiple levels of chunks - large chunks for overview, small chunks for details.\n", - "\n", - "**Best for:** Very large documents where users need both high-level summaries and specific details." - ], - "id": "af4a3f5fe1886cd5" - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "7299e6c8f02028dc", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-05T13:43:28.854802Z", - "iopub.status.busy": "2025-11-05T13:43:28.854432Z", - "iopub.status.idle": "2025-11-05T13:43:28.858931Z", - "shell.execute_reply": "2025-11-05T13:43:28.858526Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Strategy 4: Hierarchical (Multi-Level) Chunking\n", - "================================================================================\n", - "Original document: 1,035 tokens\n", - "\n", - "Level 1 (Sections): 7 chunks\n", - "\n", - " L1-1: 8 tokens - # Optimizing Vector Search Performance in Redis...\n", - " L1-2: 108 tokens - ## Abstract This paper presents a comprehensive analysis of vector search optimi...\n", - " L1-3: 98 tokens - ## 1. Introduction Vector databases have become essential infrastructure for mod...\n", - " L1-4: 98 tokens - ## 2. Background and Related Work Previous work on vector search optimization ha...\n", - " L1-5: 464 tokens - ## 3. Performance Analysis and Results ### 3.1 HNSW Configuration Trade-offs T...\n", - " L1-6: 187 tokens - ## 4. Implementation Recommendations Based on our findings, we recommend the fo...\n", - " L1-7: 73 tokens - ## 5. Discussion and Conclusion Our findings demonstrate that vector search opti...\n", - "\n", - "Level 2 (Subsections): 13 chunks\n", - "\n", - " L2-1: 8 tokens - # Optimizing Vector Search Performance in Redis...\n", - " L2-2: 108 tokens - ## Abstract This paper presents a comprehensive analysis of vector search optimi...\n", - " L2-3: 98 tokens - ## 1. Introduction Vector databases have become essential infrastructure for mod...\n", - " L2-4: 98 tokens - ## 2. Background and Related Work Previous work on vector search optimization ha...\n", - " L2-5: 107 tokens - Table 1 shows the performance comparison across different HNSW configurations. A...\n", - "... (8 more L2 chunks)\n" - ] - } - ], - "source": [ - "# Strategy 4: Hierarchical Chunking\n", - "\n", - "\n", - "def chunk_hierarchically(text: str) -> Dict[str, List[str]]:\n", - " \"\"\"\n", - " Create multiple levels of chunks.\n", - " Level 1: Large sections (by ## headers)\n", - " Level 2: Subsections (by paragraphs within sections)\n", - " \"\"\"\n", - "\n", - " # Level 1: Split by major sections\n", - " level1_chunks = chunk_by_structure(text, separator=\"\\n## \")\n", - "\n", - " # Level 2: Further split large sections into paragraphs\n", - " level2_chunks = []\n", - " for section in level1_chunks:\n", - " # If section is large, split into paragraphs\n", - " if count_tokens(section) > 400:\n", - " paragraphs = [\n", - " p.strip() for p in section.split(\"\\n\\n\") if p.strip() and len(p) > 50\n", - " ]\n", - " level2_chunks.extend(paragraphs)\n", - " else:\n", - " level2_chunks.append(section)\n", - "\n", - " return {\n", - " \"level1\": level1_chunks, # Large sections\n", - " \"level2\": level2_chunks, # Smaller subsections\n", - " }\n", - "\n", - "\n", - "# Apply to research paper\n", - "hierarchical_chunks = chunk_hierarchically(research_paper)\n", - "\n", - "print(\n", - " f\"\"\"📊 Strategy 4: Hierarchical (Multi-Level) Chunking\n", - "{'=' * 80}\n", - "Original document: {paper_tokens:,} tokens\n", - "\n", - "Level 1 (Sections): {len(hierarchical_chunks['level1'])} chunks\n", - "\"\"\"\n", - ")\n", - "\n", - "for i, chunk in enumerate(hierarchical_chunks[\"level1\"]):\n", - " chunk_tokens = count_tokens(chunk)\n", - " preview = chunk[:80].replace(\"\\n\", \" \")\n", - " print(f\" L1-{i+1}: {chunk_tokens:,} tokens - {preview}...\")\n", - "\n", - "print(\n", - " f\"\"\"\n", - "Level 2 (Subsections): {len(hierarchical_chunks['level2'])} chunks\n", - "\"\"\"\n", - ")\n", - "\n", - "for i, chunk in enumerate(hierarchical_chunks[\"level2\"][:5]): # Show first 5\n", - " chunk_tokens = count_tokens(chunk)\n", - " preview = chunk[:80].replace(\"\\n\", \" \")\n", - " print(f\" L2-{i+1}: {chunk_tokens:,} tokens - {preview}...\")\n", - "\n", - "print(f\"... ({len(hierarchical_chunks['level2']) - 5} more L2 chunks)\")" - ] - }, - { - "cell_type": "markdown", - "id": "bdf78622dce4de75", - "metadata": {}, - "source": [ - "**Strategy 4 Analysis:**\n", - "\n", - "✅ **Advantages:**\n", - "- Supports both overview and detailed queries\n", - "- Flexible retrieval (can search at different levels)\n", - "- Preserves document hierarchy\n", - "- Better for complex documents\n", - "\n", - "⚠️ **Trade-offs:**\n", - "- More complex to implement and maintain\n", - "- Requires more storage (multiple levels)\n", - "- Need strategy to choose which level to search\n", - "- Higher indexing cost\n", - "\n", - "🎯 **Best for:**\n", - "- Very large documents (textbooks, manuals)\n", - "- When users need both summaries and details\n", - "- Technical documentation with nested structure\n", - "- Legal contracts with sections and subsections\n", - "\n", - "💡 **Retrieval Strategy:**\n", - "- Start with Level 1 for overview\n", - "- If user needs more detail, retrieve Level 2 chunks\n", - "- Can combine: \"Show section summary + relevant details\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8811e94608a8eef", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "8cc19c72b00b7f36", - "metadata": {}, - "source": [ - "### Comparing Chunking Strategies: Decision Framework\n", - "\n", - "Now let's compare all four strategies side-by-side:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "33137223a8d1c166", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-05T13:43:28.860140Z", - "iopub.status.busy": "2025-11-05T13:43:28.860075Z", - "iopub.status.idle": "2025-11-05T13:43:28.864102Z", - "shell.execute_reply": "2025-11-05T13:43:28.863676Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "================================================================================\n", - "CHUNKING STRATEGY COMPARISON\n", - "================================================================================\n", - "\n", - "Document: Research Paper (1,035 tokens)\n", - "\n", - "Strategy | Chunks | Avg Size | Complexity | Best For\n", - "--------------------- | ------ | -------- | ---------- | --------\n", - "Document-Based | 7 | 148 | Low | Structured docs\n", - "Fixed-Size | 8 | 140 | Low | Unstructured text\n", - "Semantic | 25 | 41 | High | Dense academic text\n", - "Hierarchical (L1) | 7 | 148 | Medium | Large complex docs\n", - "Hierarchical (L2) | 13 | 76 | Medium | Large complex docs\n", - "\n", - "================================================================================\n", - "\n" - ] - } - ], - "source": [ - "print(\n", - " f\"\"\"\n", - "{'=' * 80}\n", - "CHUNKING STRATEGY COMPARISON\n", - "{'=' * 80}\n", - "\n", - "Document: Research Paper ({paper_tokens:,} tokens)\n", - "\n", - "Strategy | Chunks | Avg Size | Complexity | Best For\n", - "--------------------- | ------ | -------- | ---------- | --------\n", - "Document-Based | {len(structure_chunks):>6} | {sum(count_tokens(c) for c in structure_chunks) // len(structure_chunks):>8} | Low | Structured docs\n", - "Fixed-Size | {len(fixed_chunks):>6} | {sum(count_tokens(c) for c in fixed_chunks) // len(fixed_chunks):>8} | Low | Unstructured text\n", - "Semantic | {len(semantic_chunks):>6} | {sum(count_tokens(c) for c in semantic_chunks) // len(semantic_chunks):>8} | High | Dense academic text\n", - "Hierarchical (L1) | {len(hierarchical_chunks['level1']):>6} | {sum(count_tokens(c) for c in hierarchical_chunks['level1']) // len(hierarchical_chunks['level1']):>8} | Medium | Large complex docs\n", - "Hierarchical (L2) | {len(hierarchical_chunks['level2']):>6} | {sum(count_tokens(c) for c in hierarchical_chunks['level2']) // len(hierarchical_chunks['level2']):>8} | Medium | Large complex docs\n", - "\n", - "{'=' * 80}\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "5b1367dee484df00", - "metadata": {}, - "source": [ - "### YOUR Chunking Decision Framework\n", - "\n", - "Chunking strategy is a **design choice** that depends on your specific context. There's no universal \"correct\" chunk size.\n", - "\n", - "**Step 1: Start with Document Type**\n", - "\n", - "| Document Type | Default Approach | Reasoning |\n", - "|---------------|------------------|----------|\n", - "| **Structured records** (courses, products, FAQs) | Don't chunk | Natural boundaries already exist |\n", - "| **Long-form text** (papers, books, docs) | Consider chunking | May need retrieval precision |\n", - "| **PDFs with visual layout** | Page-level | Preserves tables, figures |\n", - "| **Code** | Function/class boundaries | Semantic structure matters |\n", - "\n", - "**Step 2: Evaluate These Factors**\n", - "\n", - "1. **Semantic completeness:** Is each item self-contained?\n", - " - ✅ Yes → Don't chunk (preserve natural boundaries)\n", - " - ❌ No → Consider chunking strategy\n", - "\n", - "2. **Query patterns:** What will users ask?\n", - " - Specific facts → Smaller, focused chunks help\n", - " - Summaries/overviews → Larger chunks or hierarchical\n", - " - Mixed → Consider hierarchical approach\n", - "\n", - "3. **Topic density:** How many distinct topics per document?\n", - " - Single topic → Whole-document embedding often works\n", - " - Multiple distinct topics → Chunking may improve precision\n", - "\n", - "4. **Embedding model:** What's your model's context window?\n", - " - Modern models (jina-v2, etc.) support 8K+ tokens\n", - " - Model limits are often less constraining than retrieval precision needs\n", - "\n", - "**Step 3: Consider Constraints**\n", - "\n", - "- **Latency:** Simple approaches (fixed-size, no chunking) are faster\n", - "- **Quality:** Semantic chunking adds cost but may improve relevance\n", - "- **Complexity:** More sophisticated ≠ better for your use case\n", - "\n", - "**Example Decisions:**\n", - "\n", - "| Domain | Data Characteristics | Decision | Why |\n", - "|--------|---------------------|----------|-----|\n", - "| **Course Catalog** | Small, self-contained records | **Don't chunk** | Each course is a complete retrieval unit |\n", - "| **Research Papers** | Multi-section, dense topics | Document-Based | Sections are natural semantic units |\n", - "| **Support Tickets** | Single issue per ticket | **Don't chunk** | Already at optimal granularity |\n", - "| **Legal Contracts** | Nested structure, many clauses | Hierarchical | Need both overview and clause-level detail |\n", - "| **Product Docs** | Mixed structure, varied content | Fixed-Size or Semantic | Balance simplicity with quality |\n", - "\n", - "> 💡 **Key Takeaway:** Ask \"What is my natural retrieval unit?\" before deciding on a chunking strategy. For many structured data use cases, the answer is \"don't chunk.\"" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## Summary: Chunking is Subjective, Document-Dependent, and Requires Experimentation\n", - "\n", - "**What We've Learned:**\n", - "\n", - "Chunking is **not a one-size-fits-all solution**. The optimal strategy depends entirely on:\n", - "\n", - "1. **Document Type and Structure**\n", - " - Research papers → Structure-aware or hybrid (summary + sections)\n", - " - Legal contracts → Knowledge graphs + recursive retrieval (beyond simple chunking)\n", - " - Transcripts → Speaker-aware + temporal chunking\n", - " - Structured records → Often don't chunk at all\n", - "\n", - "2. **Content Heterogeneity**\n", - " - Text-only → Standard chunking strategies work\n", - " - Multimodal (tables, figures, equations, code) → Specialized handling required\n", - " - Keep content WITH its context (table + caption, formula + definitions)\n", - "\n", - "3. **Query Patterns**\n", - " - Overview queries → Larger chunks or hierarchical (summary level)\n", - " - Specific facts → Smaller, focused chunks\n", - " - Mixed queries → Hybrid approach (multiple retrieval levels)\n", - "\n", - "4. **Models Being Used**\n", - " - Embedding model capabilities (context window, quality on long vs. short text)\n", - " - LLM context window and attention patterns\n", - " - Multimodal capabilities (vision models for figures)\n", - "\n", - "5. **Performance Requirements**\n", - " - Retrieval precision (are you getting the right chunks?)\n", - " - Answer quality (are LLM responses accurate?)\n", - " - Latency (how fast do you need results?)\n", - " - Cost (token usage, API calls, storage)\n", - "\n", - "**Key Insights from Research:**\n", - "\n", - "- **49-67% improvement** in retrieval with contextual retrieval (Anthropic, 2024)\n", - "- **Chunk overlap (10-20%)** preserves context across boundaries\n", - "- **Lost in the Middle** and **Context Rot** show that structure matters more than fitting everything in\n", - "- **Semantic chunking doesn't always outperform fixed-size** - experimentation is required\n", - "\n", - "**Three Document Types, Three Different Approaches:**\n", - "\n", - "| Document Type | Key Challenge | Recommended Approach |\n", - "|---------------|---------------|----------------------|\n", - "| **Research Papers & Long-Form** | Multimodal content (text, tables, figures, equations) | Hybrid: summary + section-based + multimodal handling |\n", - "| **Legal Contracts** | Cross-references, hierarchical dependencies, legal precedence | Knowledge graphs + recursive retrieval (advanced topic) |\n", - "| **Transcripts & Meetings** | Speaker identity, temporal flow, topic drift | Speaker-aware + time-based + metadata enrichment |\n", - "\n", - "**The Expert's Approach:**\n", - "\n", - "1. **Analyze your documents** - What content types? What structure?\n", - "2. **Understand your queries** - What will users ask? How specific?\n", - "3. **Start simple** - Fixed-size or structure-aware chunking as baseline\n", - "4. **Measure performance** - Retrieval precision, answer quality, latency\n", - "5. **Identify failures** - Where does retrieval fail? Where are answers wrong?\n", - "6. **Iterate and improve** - Test alternatives, measure impact, refine\n", - "7. **Consider alternatives** - Sometimes chunking isn't the answer (hierarchical retrieval, knowledge graphs)\n", - "\n", - "**Critical Questions to Ask:**\n", - "\n", - "- **Is chunking even necessary?** (For structured records, often NO)\n", - "- **What is my natural retrieval unit?** (Course, section, clause, speaker turn?)\n", - "- **What content types need special handling?** (Tables, formulas, figures, code?)\n", - "- **What are my query patterns?** (Overview vs. specific facts?)\n", - "- **What are my performance constraints?** (Latency, cost, quality trade-offs?)\n", - "\n", - "**Final Insight:**\n", - "\n", - "Chunking is **data modeling for retrieval**. Just like database schema design, there's no universal solution. The \"best\" chunking strategy is the one that:\n", - "- Matches your document structure\n", - "- Aligns with your query patterns\n", - "- Meets your performance requirements\n", - "- Balances complexity with maintainability\n", - "\n", - "**Experiment, measure, iterate.** This is engineering, not magic.\n" - ], - "id": "d8c55e7b505ca453" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## Part 5: Building Practical Context Pipelines\n", - "\n", - "Now that you understand data transformation and chunking, let's discuss how to build reusable pipelines.\n", - "\n", - "### Three Pipeline Architectures\n", - "\n", - "There are three main approaches to context preparation in real-world applications:\n", - "\n", - "### Architecture 1: Request-Time Processing\n", - "\n", - "**Concept:** Transform data on-the-fly when a query arrives.\n", - "\n", - "```\n", - "User Query → Retrieve Raw Data → Transform → Chunk (if needed) → Embed → Search → Return Context\n", - "```\n", - "\n", - "**Pros:**\n", - "- ✅ Always up-to-date (no stale data)\n", - "- ✅ No pre-processing required\n", - "- ✅ Simple to implement\n", - "\n", - "**Cons:**\n", - "- ❌ Higher latency (processing happens during request)\n", - "- ❌ Repeated work (same transformations for every query)\n", - "- ❌ Not suitable for large datasets\n", - "\n", - "**Best for:**\n", - "- Small datasets (< 1,000 documents)\n", - "- Frequently changing data\n", - "- Simple transformations" - ], - "id": "374f309f47646cce" - }, - { - "cell_type": "markdown", - "id": "785624fc38e46d77", - "metadata": {}, - "source": [ - "### Architecture 2: Batch Processing\n", - "\n", - "**Concept:** Pre-process all data in batches (nightly, weekly) and store results.\n", - "\n", - "```\n", - "[Scheduled Job]\n", - "Raw Data → Extract → Clean → Transform → Chunk → Embed → Store in Vector DB\n", - "\n", - "[Query Time]\n", - "User Query → Search Vector DB → Return Pre-Processed Context\n", - "```\n", - "\n", - "**Pros:**\n", - "- ✅ Fast query time (all processing done ahead)\n", - "- ✅ Efficient (process once, use many times)\n", - "- ✅ Can use expensive transformations (LLM-based chunking, semantic analysis)\n", - "\n", - "**Cons:**\n", - "- ❌ Data can be stale (until next batch run)\n", - "- ❌ Requires scheduling infrastructure\n", - "- ❌ Higher storage costs (store processed data)\n", - "\n", - "**Best for:**\n", - "- Large datasets (> 10,000 documents)\n", - "- Infrequently changing data (daily/weekly updates)\n", - "- Complex transformations (semantic chunking, LLM summaries)" - ] - }, - { - "cell_type": "markdown", - "id": "c7d956da9e767913", - "metadata": {}, - "source": [ - "### Architecture 3: Event-Driven Processing\n", - "\n", - "**Concept:** Process data as it changes (real-time updates).\n", - "\n", - "```\n", - "Data Change Event → Trigger Pipeline → Extract → Clean → Transform → Chunk → Embed → Update Vector DB\n", - "\n", - "[Query Time]\n", - "User Query → Search Vector DB → Return Context\n", - "```\n", - "\n", - "**Pros:**\n", - "- ✅ Always up-to-date (real-time)\n", - "- ✅ Fast query time (pre-processed)\n", - "- ✅ Efficient (only process changed data)\n", - "\n", - "**Cons:**\n", - "- ❌ Complex infrastructure (event streams, queues)\n", - "- ❌ Requires change detection\n", - "- ❌ Higher operational complexity\n", - "\n", - "**Best for:**\n", - "- Real-time data (news, social media, live updates)\n", - "- Large datasets that change frequently\n", - "- When both freshness and speed are critical" - ] - }, - { - "cell_type": "markdown", - "id": "d8677cf43366989a", - "metadata": {}, - "source": [ - "### Choosing YOUR Pipeline Architecture\n", - "\n", - "Use this decision tree:\n", - "\n", - "**Question 1: How often does your data change?**\n", - "- Real-time (seconds/minutes) → Event-Driven\n", - "- Frequently (hourly/daily) → Batch or Event-Driven\n", - "- Infrequently (weekly/monthly) → Batch\n", - "- Rarely (manual updates) → Request-Time or Batch\n", - "\n", - "**Question 2: How large is your dataset?**\n", - "- Small (< 1,000 docs) → Request-Time\n", - "- Medium (1,000-100,000 docs) → Batch\n", - "- Large (> 100,000 docs) → Batch or Event-Driven\n", - "\n", - "**Question 3: What are your latency requirements?**\n", - "- Real-time (< 100ms) → Batch or Event-Driven (pre-processed)\n", - "- Interactive (< 1s) → Any approach\n", - "- Batch queries → Request-Time acceptable\n", - "\n", - "**Question 4: How complex are your transformations?**\n", - "- Simple (cleaning, formatting) → Any approach\n", - "- Moderate (chunking, basic NLP) → Batch or Event-Driven\n", - "- Complex (LLM-based, semantic analysis) → Batch (pre-compute)\n", - "\n", - "**Example Decision:**\n", - "\n", - "For Redis University:\n", - "- ✅ **Data changes:** Weekly (new courses added)\n", - "- ✅ **Dataset size:** 100-500 courses (medium)\n", - "- ✅ **Latency:** Interactive (< 1s acceptable)\n", - "- ✅ **Transformations:** Moderate (structured views + embeddings)\n", - "- ✅ **Decision:** **Batch Processing** (weekly job to rebuild catalog + embeddings)" - ] - }, - { - "cell_type": "markdown", - "id": "8e4003fc42ee8ddc", - "metadata": {}, - "source": [ - "### Example: Batch Processing Pipeline for Redis University" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "68dc14ed5084daaf", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-05T13:43:28.865267Z", - "iopub.status.busy": "2025-11-05T13:43:28.865199Z", - "iopub.status.idle": "2025-11-05T13:43:29.552062Z", - "shell.execute_reply": "2025-11-05T13:43:29.551626Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "BATCH PROCESSING PIPELINE - Redis University Courses\n", - "================================================================================\n", - "\n", - "[Step 1/5] Extracting course data...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:29 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Extracted 50 courses\n", - "\n", - " 📄 Sample raw course:\n", - " CS004: Database Systems\n", - " Department: Computer Science, Credits: 3, Level: intermediate\n", - "\n", - "[Step 2/5] Cleaning data...\n", - " ✅ Cleaned: 20 courses (removed 30 test courses)\n", - "\n", - " 📄 Example removed course:\n", - " 🗑️ BUS033: Marketing Strategy (filtered out)\n", - "\n", - "[Step 3/5] Transforming to LLM-friendly format...\n", - " ✅ Transformed: 20 courses (1,087 total tokens)\n", - "\n", - " 📄 Transformation example:\n", - " Before: CS004 (Course object)\n", - " After (LLM-friendly text):\n", - " CS004: Database Systems\n", - " Department: Computer Science\n", - " Credits: 3\n", - " Level: intermediate\n", - " Format: online\n", - " Instructor: John Zamora\n", - " Description: Design and implementation of database systems. SQL, normalization, transaction...\n", - "\n", - "[Step 4/5] Creating structured catalog view...\n", - " ✅ Created catalog view (585 tokens)\n", - " ✅ Cached in Redis\n", - "\n", - " 📄 Catalog view structure:\n", - " # Redis University Course Catalog\n", - " \n", - " ## Business (10 courses)\n", - " - BUS033: Marketing Strategy (intermediate)\n", - " - BUS035: Marketing Strategy (intermediate)\n", - " - BUS032: Marketing Strategy (intermediate)\n", - " - BUS034: Marketing Strategy (intermediate)\n", - " - BUS037: Marketing Strategy (intermediate)\n", - " - BUS039: Marketing ...\n", - "\n", - "[Step 5/5] Storing processed data...\n", - " ✅ Stored 20 processed courses in Redis\n", - "\n", - " 📄 Storage example:\n", - " Key: course:processed:CS004\n", - " Value: CS004: Database Systems\n", - "Department: Computer Science\n", - "Credits: 3\n", - "Level: intermediate\n", - "Format: online\n", - "I...\n", - "\n", - "================================================================================\n", - "BATCH PROCESSING COMPLETE\n", - "================================================================================\n", - "\n", - "Summary:\n", - "- Courses processed: 20\n", - "- Total tokens: 1,087\n", - "- Catalog view tokens: 585\n", - "- Storage: Redis\n", - "- Next run: 2024-10-07 (weekly)\n", - "\n" - ] - } - ], - "source": [ - "# Example: Batch Processing Pipeline\n", - "# This would run as a scheduled job (e.g., weekly)\n", - "\n", - "\n", - "async def batch_process_courses():\n", - " \"\"\"\n", - " Batch processing pipeline for Redis University courses.\n", - " Runs weekly to update catalog and embeddings.\n", - " \"\"\"\n", - "\n", - " print(\"=\" * 80)\n", - " print(\"BATCH PROCESSING PIPELINE - Redis University Courses\")\n", - " print(\"=\" * 80)\n", - "\n", - " # Step 1: Extract\n", - " print(\"\\n[Step 1/5] Extracting course data...\")\n", - " all_courses = await course_manager.get_all_courses()\n", - " print(f\" ✅ Extracted {len(all_courses)} courses\")\n", - "\n", - " # Show sample raw data\n", - " if all_courses:\n", - " sample = all_courses[0]\n", - " print(f\"\\n 📄 Sample raw course:\")\n", - " print(f\" {sample.course_code}: {sample.title}\")\n", - " print(f\" Department: {sample.department}, Credits: {sample.credits}, Level: {sample.difficulty_level.value}\")\n", - "\n", - " # Step 2: Clean\n", - " print(\"\\n[Step 2/5] Cleaning data...\")\n", - " # Remove test courses, validate fields, etc.\n", - " cleaned_courses = [\n", - " c for c in all_courses if c.course_code.startswith((\"RU\", \"CS\", \"MATH\"))\n", - " ]\n", - " print(\n", - " f\" ✅ Cleaned: {len(cleaned_courses)} courses (removed {len(all_courses) - len(cleaned_courses)} test courses)\"\n", - " )\n", - "\n", - " # Show what was filtered out\n", - " removed_courses = [c for c in all_courses if not c.course_code.startswith((\"RU\", \"CS\", \"MATH\"))]\n", - " if removed_courses:\n", - " print(f\"\\n 📄 Example removed course:\")\n", - " print(f\" 🗑️ {removed_courses[0].course_code}: {removed_courses[0].title} (filtered out)\")\n", - "\n", - " # Step 3: Transform\n", - " print(\"\\n[Step 3/5] Transforming to LLM-friendly format...\")\n", - " transformed_courses = [transform_course_to_text(c) for c in cleaned_courses]\n", - " total_tokens = sum(count_tokens(t) for t in transformed_courses)\n", - " print(\n", - " f\" ✅ Transformed: {len(transformed_courses)} courses ({total_tokens:,} total tokens)\"\n", - " )\n", - "\n", - " # Show before/after transformation\n", - " if cleaned_courses and transformed_courses:\n", - " print(f\"\\n 📄 Transformation example:\")\n", - " print(f\" Before: {cleaned_courses[0].course_code} (Course object)\")\n", - " print(f\" After (LLM-friendly text):\")\n", - " preview = transformed_courses[0].replace('\\n', '\\n ')\n", - " print(f\" {preview[:250]}...\")\n", - "\n", - " # Step 4: Create Structured Views\n", - " print(\"\\n[Step 4/5] Creating structured catalog view...\")\n", - " catalog_view = await create_catalog_view()\n", - " catalog_tokens = count_tokens(catalog_view)\n", - " redis_client.set(\"course_catalog_view\", catalog_view)\n", - " redis_client.set(\"course_catalog_view:updated\", \"2024-09-30\")\n", - " print(f\" ✅ Created catalog view ({catalog_tokens:,} tokens)\")\n", - " print(f\" ✅ Cached in Redis\")\n", - "\n", - " # Show catalog structure\n", - " print(f\"\\n 📄 Catalog view structure:\")\n", - " catalog_preview = catalog_view[:300].replace('\\n', '\\n ')\n", - " print(f\" {catalog_preview}...\")\n", - "\n", - " # Step 5: Store (in production, would also create embeddings and store in vector DB)\n", - " print(\"\\n[Step 5/5] Storing processed data...\")\n", - " for i, (course, text) in enumerate(zip(cleaned_courses, transformed_courses)):\n", - " key = f\"course:processed:{course.course_code}\"\n", - " redis_client.set(key, text)\n", - " print(f\" ✅ Stored {len(cleaned_courses)} processed courses in Redis\")\n", - "\n", - " # Show storage example\n", - " if cleaned_courses:\n", - " print(f\"\\n 📄 Storage example:\")\n", - " print(f\" Key: course:processed:{cleaned_courses[0].course_code}\")\n", - " print(f\" Value: {transformed_courses[0][:100]}...\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"BATCH PROCESSING COMPLETE\")\n", - " print(\"=\" * 80)\n", - " print(\n", - " f\"\"\"\n", - "Summary:\n", - "- Courses processed: {len(cleaned_courses)}\n", - "- Total tokens: {total_tokens:,}\n", - "- Catalog view tokens: {catalog_tokens:,}\n", - "- Storage: Redis\n", - "- Next run: 2024-10-07 (weekly)\n", - "\"\"\"\n", - " )\n", - "\n", - "\n", - "# Run the batch pipeline\n", - "await batch_process_courses()" - ] - }, - { - "cell_type": "markdown", - "id": "782e27e9e5b1bf93", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## Summary and Key Takeaways\n", - "\n", - "### What You Learned\n", - "\n", - "**1. Context is Data - and Data Requires Engineering**\n", - "- Context isn't just \"data you feed to an LLM\"\n", - "- It requires systematic transformation: Raw → Clean → Transform → Optimize → Store\n", - "- Engineering discipline: requirements analysis, design decisions, quality metrics, testing\n", - "\n", - "**2. The Data Engineering Pipeline**\n", - "- Extract: Get raw data from sources\n", - "- Clean: Remove noise, fix inconsistencies\n", - "- Transform: Structure for LLM consumption\n", - "- Optimize: Reduce tokens, improve clarity\n", - "- Store: Choose storage strategy (RAG, Views, Hybrid)\n", - "\n", - "**3. Three Engineering Approaches**\n", - "- **RAG:** Semantic search for relevant data (good for specific queries)\n", - "- **Structured Views:** Pre-computed summaries (excellent for overviews)\n", - "- **Hybrid:** Combine both (best for real-world use)\n", - "\n", - "**4. Chunking is a Design Choice, Not a Default**\n", - "- **\"Don't chunk\"** is a valid strategy for structured data (courses, products, FAQs)\n", - "- Consider chunking when documents have multiple distinct topics or need retrieval precision\n", - "- Four strategies when chunking: Document-Based, Fixed-Size, Semantic, Hierarchical\n", - "- Emerging approaches: Late Chunking, Contextual Retrieval, Hybrid Search\n", - "- Choose based on YOUR data type, query patterns, and application requirements\n", - "\n", - "**5. Context Pipeline Architectures**\n", - "- **Request-Time:** Process on-the-fly (simple, always fresh, higher latency)\n", - "- **Batch:** Pre-process in batches (fast queries, can be stale)\n", - "- **Event-Driven:** Process on changes (real-time, complex infrastructure)\n", - "\n", - "### The Engineering Mindset\n", - "\n", - "Every decision should be based on **YOUR specific requirements:**\n", - "\n", - "1. **Analyze YOUR data:** Size, structure, update frequency, topic density\n", - "2. **Analyze YOUR queries:** Specific vs. overview, single vs. cross-section\n", - "3. **Analyze YOUR constraints:** Token budget, latency, quality requirements\n", - "4. **Make informed decisions:** Choose approaches that match YOUR needs\n", - "5. **Measure and iterate:** Test with real queries, measure quality, optimize\n", - "\n", - "**Remember:** There is no \"best practice\" that works for everyone. Context engineering is about making deliberate, informed choices based on YOUR domain, application, and constraints.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "63994fc42bf9a188", - "metadata": {}, - "source": [ - "## Part 6: Quality Optimization - Measuring and Improving Context\n", - "\n", - "### The Systematic Optimization Process\n", - "\n", - "Now that you understand data engineering and context pipelines, let's learn how to systematically optimize context quality.\n", - "\n", - "**The Process:**\n", - "```\n", - "1. Define Quality Metrics (domain-specific)\n", - " ↓\n", - "2. Establish Baseline (measure current performance)\n", - " ↓\n", - "3. Experiment (try different approaches)\n", - " ↓\n", - "4. Measure (compare against metrics)\n", - " ↓\n", - "5. Iterate (refine based on results)\n", - "```\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "10c89199eb6b0330", - "metadata": {}, - "source": [ - "### Step 1: Define Quality Metrics for YOUR Domain\n", - "\n", - "**The Problem with Generic Metrics:**\n", - "\n", - "Don't aim for \"95% accuracy on benchmark X\" - that benchmark wasn't designed for YOUR domain.\n", - "\n", - "**DO this instead:** Define what \"quality\" means for YOUR domain, then measure it.\n", - "\n", - "### The Four Quality Dimensions\n", - "\n", - "Every context engineering solution should be evaluated across four dimensions:\n", - "\n", - "1. **Relevance** - Does context include information needed to answer the query?\n", - "2. **Completeness** - Does context include ALL necessary information?\n", - "3. **Efficiency** - Is context optimized for token usage?\n", - "4. **Accuracy** - Is context factually correct and up-to-date?\n", - "\n", - "Different domains prioritize these differently.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "385e5e35147ec43d", - "metadata": {}, - "source": [ - "### Example: Quality Metrics for Redis University Course Advisor\n", - "\n", - "Let's define specific, measurable quality metrics for our course advisor domain." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "be4e1aeb26cfc100", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-05T13:43:29.553570Z", - "iopub.status.busy": "2025-11-05T13:43:29.553489Z", - "iopub.status.idle": "2025-11-05T13:43:29.556597Z", - "shell.execute_reply": "2025-11-05T13:43:29.556153Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "QUALITY METRICS FOR REDIS UNIVERSITY COURSE ADVISOR\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "\n", - "Relevance:\n", - " Definition: Does context include courses relevant to the user's query?\n", - " Metric: % of queries where retrieved courses match query intent\n", - " How to measure: Manual review of 50 sample queries\n", - " Target: >90%\n", - " Why important: Irrelevant courses waste tokens and confuse users\n", - "\n", - "Completeness:\n", - " Definition: Does context include all information needed to answer?\n", - " Metric: % of responses that mention all prerequisites when asked\n", - " How to measure: Automated check: parse response for prerequisite mentions\n", - " Target: 100%\n", - " Why important: Missing prerequisites leads to hallucinations\n", - "\n", - "Efficiency:\n", - " Definition: Is context optimized for token usage?\n", - " Metric: Average tokens per query\n", - " How to measure: Token counter on all context strings\n", - " Target: <5,000 tokens\n", - " Why important: Exceeding budget increases cost and latency\n", - "\n", - "Accuracy:\n", - " Definition: Is context factually correct and up-to-date?\n", - " Metric: % of responses with correct course information\n", - " How to measure: Manual review against course database\n", - " Target: >95%\n", - " Why important: Incorrect information damages trust\n", - "\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" - ] - } - ], - "source": [ - "# Define domain-specific quality metrics\n", - "\n", - "quality_metrics = {\n", - " \"Relevance\": {\n", - " \"definition\": \"Does context include courses relevant to the user's query?\",\n", - " \"metric\": \"% of queries where retrieved courses match query intent\",\n", - " \"measurement\": \"Manual review of 50 sample queries\",\n", - " \"target\": \">90%\",\n", - " \"why_important\": \"Irrelevant courses waste tokens and confuse users\",\n", - " },\n", - " \"Completeness\": {\n", - " \"definition\": \"Does context include all information needed to answer?\",\n", - " \"metric\": \"% of responses that mention all prerequisites when asked\",\n", - " \"measurement\": \"Automated check: parse response for prerequisite mentions\",\n", - " \"target\": \"100%\",\n", - " \"why_important\": \"Missing prerequisites leads to hallucinations\",\n", - " },\n", - " \"Efficiency\": {\n", - " \"definition\": \"Is context optimized for token usage?\",\n", - " \"metric\": \"Average tokens per query\",\n", - " \"measurement\": \"Token counter on all context strings\",\n", - " \"target\": \"<5,000 tokens\",\n", - " \"why_important\": \"Exceeding budget increases cost and latency\",\n", - " },\n", - " \"Accuracy\": {\n", - " \"definition\": \"Is context factually correct and up-to-date?\",\n", - " \"metric\": \"% of responses with correct course information\",\n", - " \"measurement\": \"Manual review against course database\",\n", - " \"target\": \">95%\",\n", - " \"why_important\": \"Incorrect information damages trust\",\n", - " },\n", - "}\n", - "\n", - "print(\n", - " \"\"\"QUALITY METRICS FOR REDIS UNIVERSITY COURSE ADVISOR\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\"\"\"\n", - ")\n", - "for dimension, details in quality_metrics.items():\n", - " print(\n", - " f\"\"\"\n", - "{dimension}:\n", - " Definition: {details['definition']}\n", - " Metric: {details['metric']}\n", - " How to measure: {details['measurement']}\n", - " Target: {details['target']}\n", - " Why important: {details['why_important']}\"\"\"\n", - " )\n", - "print(\"\\n\" + \"━\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "c5331fe7c2b23131", - "metadata": {}, - "source": [ - "### Key Insight: Metrics Must Be Domain-Specific\n", - "\n", - "Notice how these metrics are specific to the course advisor domain:\n", - "\n", - "**Relevance metric:**\n", - "- ❌ Generic: \"Cosine similarity > 0.8\"\n", - "- ✅ Domain-specific: \"Retrieved courses match query intent\"\n", - "\n", - "**Completeness metric:**\n", - "- ❌ Generic: \"Context includes top-5 search results\"\n", - "- ✅ Domain-specific: \"All prerequisites mentioned when asked\"\n", - "\n", - "**Efficiency metric:**\n", - "- ❌ Generic: \"Minimize tokens\"\n", - "- ✅ Domain-specific: \"<5,000 tokens (fits our budget)\"\n", - "\n", - "**Accuracy metric:**\n", - "- ❌ Generic: \"95% on MMLU benchmark\"\n", - "- ✅ Domain-specific: \"Correct course information vs. database\"\n", - "\n", - "**Your metrics should reflect YOUR domain's requirements, not generic benchmarks.**\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "cb9936b76be5dd4f", - "metadata": {}, - "source": [ - "### Step 2-5: Baseline → Experiment → Measure → Iterate\n", - "\n", - "Let's demonstrate the optimization process with a concrete example.\n", - "\n", - "**Scenario:** We want to optimize our hybrid approach (catalog overview + RAG) to meet all quality targets." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "8ab33636bc9a2a42", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-05T13:43:29.557841Z", - "iopub.status.busy": "2025-11-05T13:43:29.557772Z", - "iopub.status.idle": "2025-11-05T13:43:29.763818Z", - "shell.execute_reply": "2025-11-05T13:43:29.762880Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:29 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "BASELINE (Hybrid Approach):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Tokens: 177\n", - "\n", - "Context:\n", - "Redis University Course Catalog Overview:\n", - "\n", - "Computer Science Department:\n", - "- RU101: Introduction to Redis Data Structures (Beginner, 4-6 hours)\n", - "- RU201: Redis for Python Developers (Intermediate, 6-8 hours)\n", - "- RU301: Vector Similarity Search with Redis (Advanced, 8-10 hours)\n", - "\n", - "Data Science Department:\n", - "- RU401: Machine Learning with Redis (Intermediate, 10-12 hours)\n", - "- RU402: Real-Time Analytics with Redis (Advanced, 8-10 hours)\n", - "\n", - "\n", - "Detailed Course Information:\n", - "CS007: Machine Learning (advanced)\n", - "Description: Introduction to machine learning algorithms and applications. Supervised and unsupervised learning, neural networks.\n", - "Prerequisites: None\n", - "\n", - "MATH022: Linear Algebra (intermediate)\n", - "Description: Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.\n", - "Prerequisites: None\n", - "\n" - ] - } - ], - "source": [ - "# Step 2: Establish Baseline (Hybrid Approach from Part 3)\n", - "\n", - "# Sample query\n", - "test_query = \"What machine learning courses are available for beginners?\"\n", - "\n", - "# Hybrid approach: Catalog overview + RAG\n", - "catalog_overview = \"\"\"Redis University Course Catalog Overview:\n", - "\n", - "Computer Science Department:\n", - "- RU101: Introduction to Redis Data Structures (Beginner, 4-6 hours)\n", - "- RU201: Redis for Python Developers (Intermediate, 6-8 hours)\n", - "- RU301: Vector Similarity Search with Redis (Advanced, 8-10 hours)\n", - "\n", - "Data Science Department:\n", - "- RU401: Machine Learning with Redis (Intermediate, 10-12 hours)\n", - "- RU402: Real-Time Analytics with Redis (Advanced, 8-10 hours)\n", - "\"\"\"\n", - "\n", - "# RAG: Get specific courses\n", - "rag_results = await course_manager.search_courses(test_query, limit=2)\n", - "rag_context = \"\\n\\n\".join(\n", - " [\n", - " f\"\"\"{course.course_code}: {course.title} ({course.difficulty_level.value})\n", - "Description: {course.description}\n", - "Prerequisites: {', '.join([p.course_code for p in course.prerequisites]) if course.prerequisites else 'None'}\"\"\"\n", - " for course in rag_results\n", - " ]\n", - ")\n", - "\n", - "# Combined context\n", - "baseline_context = f\"\"\"{catalog_overview}\n", - "\n", - "Detailed Course Information:\n", - "{rag_context}\"\"\"\n", - "\n", - "baseline_tokens = count_tokens(baseline_context)\n", - "\n", - "print(\n", - " f\"\"\"BASELINE (Hybrid Approach):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Tokens: {baseline_tokens:,}\n", - "\n", - "Context:\n", - "{baseline_context}\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "9835f424b4bba43e", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-05T13:43:29.765996Z", - "iopub.status.busy": "2025-11-05T13:43:29.765906Z", - "iopub.status.idle": "2025-11-05T13:43:29.768493Z", - "shell.execute_reply": "2025-11-05T13:43:29.768004Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "EXPERIMENT (Optimized Hybrid):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Tokens: 111\n", - "\n", - "Context:\n", - "Redis University - Relevant Departments:\n", - "\n", - "Data Science:\n", - "- RU401: Machine Learning with Redis (Intermediate)\n", - "- RU402: Real-Time Analytics (Advanced)\n", - "\n", - "Computer Science:\n", - "- RU301: Vector Search (Advanced)\n", - "\n", - "\n", - "CS007: Machine Learning (advanced)\n", - "Description: Introduction to machine learning algorithms and applications. Supervised and unsupervised learning, neural networks.\n", - "Prerequisites: None\n", - "\n", - "MATH022: Linear Algebra (intermediate)\n", - "Description: Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.\n", - "Prerequisites: None\n", - "\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Token Reduction: 66 tokens (37.3% reduction)\n", - "\n" - ] - } - ], - "source": [ - "# Step 3: Experiment - Try optimized version\n", - "\n", - "# Optimization: Reduce catalog overview to just relevant departments\n", - "optimized_catalog = \"\"\"Redis University - Relevant Departments:\n", - "\n", - "Data Science:\n", - "- RU401: Machine Learning with Redis (Intermediate)\n", - "- RU402: Real-Time Analytics (Advanced)\n", - "\n", - "Computer Science:\n", - "- RU301: Vector Search (Advanced)\n", - "\"\"\"\n", - "\n", - "optimized_context = f\"\"\"{optimized_catalog}\n", - "\n", - "{rag_context}\"\"\"\n", - "\n", - "optimized_tokens = count_tokens(optimized_context)\n", - "\n", - "print(\n", - " f\"\"\"EXPERIMENT (Optimized Hybrid):\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Tokens: {optimized_tokens:,}\n", - "\n", - "Context:\n", - "{optimized_context}\n", - "\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Token Reduction: {baseline_tokens - optimized_tokens:,} tokens ({((baseline_tokens - optimized_tokens) / baseline_tokens * 100):.1f}% reduction)\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "1e9f6bf32872925d", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-05T13:43:29.769722Z", - "iopub.status.busy": "2025-11-05T13:43:29.769629Z", - "iopub.status.idle": "2025-11-05T13:43:37.401544Z", - "shell.execute_reply": "2025-11-05T13:43:37.400237Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:34 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "08:43:37 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "BASELINE RESPONSE:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "In the Redis University course catalog, there isn't a specific machine learning course labeled as \"beginner.\" However, if you're interested in machine learning and are looking for a foundational course, you might consider starting with the Computer Science Department's RU101: Introduction to Redis Data Structures. This course is beginner-friendly and can provide a good foundation in understanding data structures, which is essential for working with machine learning algorithms.\n", - "\n", - "For a more direct introduction to machine learning concepts, you might want to look outside the Redis University catalog or consider CS007: Machine Learning, which is labeled as advanced but covers introductory topics in machine learning algorithms and applications.\n", - "\n", - "OPTIMIZED RESPONSE:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "At Redis University, we currently do not have any beginner-level machine learning courses. However, if you're interested in machine learning, you might consider starting with foundational courses in related areas, such as linear algebra, which is essential for understanding machine learning concepts. The course MATH022: Linear Algebra (intermediate) could be a good starting point. Once you have a solid foundation, you can explore more advanced machine learning courses like CS007: Machine Learning (advanced) or RU401: Machine Learning with Redis (Intermediate).\n", - "\n" - ] - } - ], - "source": [ - "# Step 4: Measure - Compare responses\n", - "\n", - "# Baseline response\n", - "messages_baseline = [\n", - " SystemMessage(content=f\"You are a Redis University course advisor.\\n\\n{baseline_context}\"),\n", - " HumanMessage(content=test_query),\n", - "]\n", - "response_baseline = llm.invoke(messages_baseline)\n", - "\n", - "# Optimized response\n", - "messages_optimized = [\n", - " SystemMessage(\n", - " content=f\"You are a Redis University course advisor.\\n\\n{optimized_context}\"\n", - " ),\n", - " HumanMessage(content=test_query),\n", - "]\n", - "response_optimized = llm.invoke(messages_optimized)\n", - "\n", - "print(\n", - " f\"\"\"BASELINE RESPONSE:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "{response_baseline.content}\n", - "\n", - "OPTIMIZED RESPONSE:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "{response_optimized.content}\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "73762d987cdf036d", - "metadata": {}, - "source": [ - "### Step 5: Iterate - Refine Based on Results\n", - "\n", - "Based on the measurements:\n", - "\n", - "**Quality Assessment:**\n", - "- ✅ **Relevance:** Both approaches retrieve relevant ML courses\n", - "- ✅ **Completeness:** Both mention prerequisites and difficulty levels\n", - "- ✅ **Efficiency:** Optimized version uses fewer tokens ({optimized_tokens} vs {baseline_tokens})\n", - "- ✅ **Accuracy:** Both provide correct course information\n", - "\n", - "**Decision:** The optimized hybrid approach meets all quality targets while reducing token usage.\n", - "\n", - "**Next Iteration:** Test with more queries to ensure consistency across different query types.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "6618ae42e227c5d1", - "metadata": {}, - "source": [ - "### Key Takeaways: Quality Optimization\n", - "\n", - "1. **Define Domain-Specific Metrics** - Don't rely on generic benchmarks\n", - "2. **Measure Systematically** - Baseline → Experiment → Measure → Iterate\n", - "3. **Balance Trade-offs** - Relevance vs. Efficiency, Completeness vs. Token Budget\n", - "4. **Test Before Deployment** - Validate with real queries from your domain\n", - "5. **Iterate Continuously** - Quality optimization is ongoing, not one-time\n", - "\n", - "**The Engineering Mindset:**\n", - "- Context quality is measurable\n", - "- Optimization is systematic, not guesswork\n", - "- Domain-specific metrics matter more than generic benchmarks\n", - "- Testing and iteration are essential\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "b76bb463b4f96e72", - "metadata": {}, - "source": [ - "## 📝 Summary\n", - "\n", - "You've mastered practical context engineering:\n", - "\n", - "**Part 1: The Engineering Mindset**\n", - "- ✅ Context is data requiring engineering discipline\n", - "- ✅ Naive approaches fail in real-world applications\n", - "- ✅ Engineering mindset: Requirements → Transformation → Quality → Testing\n", - "\n", - "**Part 2: Data Engineering Pipeline**\n", - "- ✅ Extract → Clean → Transform → Optimize → Store\n", - "- ✅ Concrete examples with course data\n", - "- ✅ Token optimization techniques\n", - "\n", - "**Part 3: Engineering Approaches**\n", - "- ✅ RAG (Semantic Search)\n", - "- ✅ Structured Views (Pre-Computed Summaries)\n", - "- ✅ Hybrid (Best of Both Worlds)\n", - "- ✅ Decision framework for choosing approaches\n", - "\n", - "**Part 4: Chunking Strategies**\n", - "- ✅ When to chunk (critical first question)\n", - "- ✅ Four strategies with LangChain integration\n", - "- ✅ Trade-offs and decision criteria\n", - "\n", - "**Part 5: Context Pipeline Architectures**\n", - "- ✅ Request-Time, Batch, Event-Driven\n", - "- ✅ Batch processing example with data\n", - "- ✅ Decision framework for architecture selection\n", - "\n", - "**Part 6: Quality Optimization**\n", - "- ✅ Domain-specific quality metrics\n", - "- ✅ Systematic optimization process\n", - "- ✅ Baseline → Experiment → Measure → Iterate\n", - "\n", - "**You're now ready to engineer practical context for any domain!** 🎉\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "869e80246eb4632a", - "metadata": {}, - "source": [ - "## 🚀 What's Next?\n", - "\n", - "### Section 3: Memory Systems for Context Engineering\n", - "\n", - "Now that you can engineer high-quality retrieved context, you'll learn to manage conversation context:\n", - "- **Working Memory:** Track conversation history within a session\n", - "- **Long-term Memory:** Remember user preferences across sessions\n", - "- **LangGraph Integration:** Manage stateful workflows with checkpointing\n", - "- **Redis Agent Memory Server:** Automatic memory extraction and retrieval\n", - "\n", - "### Section 4: Tool Use and Agents\n", - "\n", - "After adding memory, you'll build complete autonomous agents:\n", - "- **Tool Calling:** Let the AI use functions (search, enroll, check prerequisites)\n", - "- **LangGraph State Management:** Orchestrate complex multi-step workflows\n", - "- **Agent Reasoning:** Plan and execute multi-step tasks\n", - "- **Practical Patterns:** Error handling, retries, and monitoring\n", - "\n", - "```\n", - "Section 1: Context Engineering Fundamentals\n", - " ↓\n", - "Section 2, NB1: RAG Fundamentals\n", - " ↓\n", - "Section 2, NB2: Crafting and Optimizing Context ← You are here\n", - " ↓\n", - "Section 3: Memory Systems for Context Engineering ← Next\n", - " ↓\n", - "Section 4: Tool Use and Agents (Complete System)\n", - "```\n", - "\n", - "---\n", - "\n", - "## Additional Resources\n", - "\n", - "**Chunking Strategies:**\n", - "- [LangChain Text Splitters](https://python.langchain.com/docs/modules/data_connection/document_transformers/)\n", - "- [LlamaIndex Node Parsers](https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/)\n", - "\n", - "**Data Engineering for LLMs:**\n", - "- [OpenAI Best Practices](https://platform.openai.com/docs/guides/prompt-engineering)\n", - "- [Anthropic Prompt Engineering](https://docs.anthropic.com/claude/docs/prompt-engineering)\n", - "\n", - "**Vector Databases:**\n", - "- [Redis Vector Search Documentation](https://redis.io/docs/stack/search/reference/vectors/)\n", - "- [RedisVL Python Library](https://github.com/RedisVentures/redisvl)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e682e2447c50f133", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-2-retrieved-context-engineering/README.md b/notebooks/section-2-retrieved-context-engineering/README.md deleted file mode 100644 index e46e160..0000000 --- a/notebooks/section-2-retrieved-context-engineering/README.md +++ /dev/null @@ -1,303 +0,0 @@ -# Section 2: Retrieved Context Engineering - -## Overview - -This section teaches you to build production-ready RAG (Retrieval-Augmented Generation) systems and engineer high-quality context for LLMs. You'll learn both the fundamentals of RAG and the engineering discipline required to make it production-ready. - -**What You'll Build:** -- Complete RAG pipeline with Redis vector store -- Production-ready context engineering workflows -- Systematic quality optimization processes - -**Time to Complete:** 135-155 minutes (2.25-2.5 hours) - ---- - -## Learning Objectives - -By the end of this section, you will be able to: - -1. **Build RAG Systems** - - Understand vector embeddings and semantic search - - Implement complete RAG pipeline (Retrieve → Assemble → Generate) - - Use Redis vector store for production-scale retrieval - - Combine multiple context types (System + User + Retrieved) - -2. **Engineer Context for Production** - - Apply data engineering discipline to context preparation - - Transform raw data through systematic pipeline (Extract → Clean → Transform → Optimize → Store) - - Choose appropriate engineering approaches (RAG, Structured Views, Hybrid) - - Implement chunking strategies with LangChain - -3. **Optimize Context Quality** - - Define domain-specific quality metrics - - Measure context quality systematically - - Optimize through experimentation (Baseline → Experiment → Measure → Iterate) - - Build production-ready context pipelines - ---- - -## Prerequisites - -- Completed Section 1 (Context Engineering Foundations) -- Redis 8 running locally -- OpenAI API key configured -- Python 3.10+ with dependencies installed - ---- - -## Notebooks - -### 01_rag_fundamentals_and_implementation.ipynb - -**Time:** 45-50 minutes - -**What You'll Learn:** -- Why RAG matters for context engineering -- Vector embeddings fundamentals -- Building your first RAG system with Redis -- Why context quality matters (preview) - -**Key Topics:** -- Part 1: Why RAG Matters -- Part 2: Vector Embeddings Fundamentals -- Part 3: Building Your First RAG System -- Part 4: Context Quality Matters - -**Hands-On:** -- Generate course data using reference-agent utilities -- Set up Redis vector store -- Implement RAG pipeline -- Compare poor vs. well-engineered context - ---- - -### 02_crafting_and_optimizing_context.ipynb - -**Time:** 90-105 minutes - -**What You'll Learn:** -- Data engineering workflows for context -- Chunking strategies and when to use them -- Production pipeline architectures -- Quality optimization techniques - -**Key Topics:** -- Part 1: The Engineering Mindset -- Part 2: Data Engineering Pipeline -- Part 3: Engineering Approaches (RAG, Structured Views, Hybrid) -- Part 4: Chunking Strategies (4 strategies with LangChain) -- Part 5: Production Pipeline Architectures -- Part 6: Quality Optimization - -**Hands-On:** -- Transform raw data through 5-step pipeline -- Implement three engineering approaches -- Use LangChain text splitters (RecursiveCharacterTextSplitter, SemanticChunker) -- Build batch processing pipeline -- Optimize context quality systematically - ---- - -## Key Concepts - -### RAG (Retrieval-Augmented Generation) - -RAG solves the problem of static knowledge by dynamically retrieving relevant information: - -``` -User Query → Semantic Search → Retrieved Context → LLM Generation → Response -``` - -**Benefits:** -- Scales to millions of documents -- Token efficient (only retrieve what's relevant) -- Easy to update (no code changes) -- Personalized results - -### Three Engineering Approaches - -1. **RAG (Semantic Search)** - - Use when: Data changes frequently, huge dataset, need specific details - - Pros: Scalable, efficient, personalized - - Cons: May miss overview, requires good embeddings - -2. **Structured Views (Pre-Computed Summaries)** - - Use when: Data changes infrequently, need overview + details - - Pros: Complete overview, optimized format, fast - - Cons: Higher maintenance, storage overhead - -3. **Hybrid (Best of Both)** - - Use when: Need both overview and specific details - - Pros: Completeness + efficiency, best quality - - Cons: More complex, higher cost - -### Chunking Strategy: A Design Choice - -**Critical First Question:** What is your natural retrieval unit? - -Chunking is **not a default step** — it's an engineering decision based on your data characteristics. - -**When NOT to chunk (whole-record embedding):** -- Structured records with natural boundaries (courses, products, FAQs) -- Self-contained documents where splitting would break context -- Data where each item represents a complete concept - -**When chunking may help:** -- Long-form content with multiple distinct topics (research papers, books) -- Documents where users need to retrieve specific sections -- Content where retrieval precision is more important than context completeness - -**Research Background:** -- **"Lost in the Middle"** (Stanford, 2023): LLMs have poor recall for information in the middle of long context ([arXiv:2307.03172](https://arxiv.org/abs/2307.03172)) -- **"Context Rot"** (Chroma, 2025): Irrelevant content actively degrades model performance ([research.trychroma.com/context-rot](https://research.trychroma.com/context-rot)) -- These findings provide mental models for trade-offs, not binary rules—experiment with your data - -**Traditional Strategies:** -1. **Document-Based** - Structure-aware splitting (follows headers/sections) -2. **Fixed-Size** - LangChain RecursiveCharacterTextSplitter -3. **Semantic** - LangChain SemanticChunker with embeddings -4. **Hierarchical** - Multi-level chunking - -**Emerging Strategies (2024):** -- **Late Chunking** (Jina AI) - Embed document first, chunk embeddings after -- **Contextual Retrieval** (Anthropic) - Add LLM context to chunks before embedding -- **Hybrid Search** - Combine embeddings with BM25 keyword search - -> 💡 For our course catalog, we use **whole-record embedding** — each course is already an optimal retrieval unit. - -### Production Pipeline Architectures - -1. **Request-Time Processing** - - Transform data when query arrives - - Use when: Data changes frequently, simple transformations - -2. **Batch Processing** - - Pre-process data on schedule (e.g., weekly) - - Use when: Data changes infrequently, complex transformations - -3. **Event-Driven Processing** - - Process data when it changes - - Use when: Real-time updates required, event-driven architecture - -### Quality Metrics - -**Four Dimensions:** -1. **Relevance** - Does context include information needed to answer? -2. **Completeness** - Does context include ALL necessary information? -3. **Efficiency** - Is context optimized for token usage? -4. **Accuracy** - Is context factually correct and up-to-date? - -**Key Insight:** Define domain-specific metrics, not generic benchmarks. - ---- - -## Technologies Used - -- **LangChain** - RAG framework and text splitters -- **Redis** - Vector store for semantic search -- **RedisVL** - Redis Vector Library for Python -- **OpenAI** - Embeddings and LLM (GPT-4o) -- **HuggingFace** - Local embeddings (sentence-transformers) -- **tiktoken** - Token counting - -## Key Classes - -- **CourseManager** - Basic Redis vector search (used in source notebooks) -- **HierarchicalCourseManager** - Two-tier retrieval with summaries + details (used in workshop) -- **HierarchicalContextAssembler** - Progressive disclosure pattern for context assembly - ---- - -## Common Patterns - -### RAG Pipeline Pattern - -```python -# 1. Retrieve relevant documents -results = await course_manager.search_courses(query, top_k=3) - -# 2. Assemble context -context = assemble_context(system_context, user_context, results) - -# 3. Generate response -messages = [SystemMessage(content=context), HumanMessage(content=query)] -response = llm.invoke(messages) -``` - -### Data Engineering Pattern - -```python -# Extract → Clean → Transform → Optimize → Store -raw_data = extract_from_source() -cleaned_data = clean_and_filter(raw_data) -transformed_data = transform_to_llm_format(cleaned_data) -optimized_data = optimize_tokens(transformed_data) -store_in_vector_db(optimized_data) -``` - -### Quality Optimization Pattern - -```python -# Baseline → Experiment → Measure → Iterate -baseline_metrics = measure_quality(baseline_approach) -experiment_metrics = measure_quality(new_approach) -if experiment_metrics > baseline_metrics: - deploy(new_approach) -else: - iterate(new_approach) -``` - ---- - -## What's Next? - -After completing this section, you'll move to: - -**Section 3: Memory Systems for Context Engineering** -- Add working memory and long-term memory to your RAG system -- Manage conversation context across multiple turns -- Implement memory compression and summarization -- Use Redis Agent Memory Server - -**Section 4: Tool Use and Agents** -- Add tools for course enrollment, schedule management -- Build complete autonomous agent with LangGraph -- Combine all four context types into production system - ---- - -## Additional Resources - -### RAG and Vector Search -- [Retrieval-Augmented Generation Paper](https://arxiv.org/abs/2005.11401) - Original RAG paper -- [Redis Vector Similarity Search](https://redis.io/docs/stack/search/reference/vectors/) - Official Redis VSS docs -- [RedisVL Documentation](https://redisvl.com/) - Redis Vector Library - -### LangChain Integration -- [LangChain RAG Tutorial](https://python.langchain.com/docs/tutorials/rag/) - Building RAG applications -- [LangChain Text Splitters](https://python.langchain.com/docs/modules/data_connection/document_transformers/) - Chunking strategies -- [LangChain Redis Integration](https://python.langchain.com/docs/integrations/vectorstores/redis/) - Using Redis with LangChain - -### Embeddings and Semantic Search -- [OpenAI Embeddings Guide](https://platform.openai.com/docs/guides/embeddings) - Understanding text embeddings -- [Sentence Transformers](https://www.sbert.net/) - Open-source embedding models -- [HNSW Algorithm](https://arxiv.org/abs/1603.09320) - Hierarchical Navigable Small World graphs - -### Advanced RAG Techniques -- [Advanced RAG Patterns](https://blog.langchain.dev/deconstructing-rag/) - LangChain blog on RAG optimization -- [Advanced Search with RedisVL](https://docs.redisvl.com/en/latest/user_guide/11_advanced_queries.html) - Hybrid search techniques -- [RAG Evaluation](https://arxiv.org/abs/2309.15217) - Measuring RAG system performance - ---- - -## Tips for Success - -1. **Start Simple** - Build basic RAG first, then optimize -2. **Measure Everything** - Define metrics before optimizing -3. **Test with Real Queries** - Use queries from your actual domain -4. **Iterate Systematically** - Baseline → Experiment → Measure → Iterate -5. **Balance Trade-offs** - Relevance vs. Efficiency, Completeness vs. Token Budget - -**Remember:** Context engineering is real engineering. Apply the same rigor you would to any data engineering problem. - diff --git a/notebooks/section-2-retrieved-context-engineering/course_catalog_section2.json b/notebooks/section-2-retrieved-context-engineering/course_catalog_section2.json deleted file mode 100644 index 210b054..0000000 --- a/notebooks/section-2-retrieved-context-engineering/course_catalog_section2.json +++ /dev/null @@ -1,2224 +0,0 @@ -{ - "majors": [ - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9H", - "name": "Computer Science", - "code": "CS", - "department": "Computer Science", - "description": "Study of computational systems, algorithms, and software design", - "required_credits": 120, - "core_courses": [], - "elective_courses": [], - "career_paths": [ - "Software Engineer", - "Data Scientist", - "Systems Architect", - "AI Researcher" - ], - "created_at": "2025-12-05 12:35:49.630320" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9J", - "name": "Data Science", - "code": "DS", - "department": "Data Science", - "description": "Interdisciplinary field using statistics, programming, and domain expertise", - "required_credits": 120, - "core_courses": [], - "elective_courses": [], - "career_paths": [ - "Data Analyst", - "Machine Learning Engineer", - "Business Intelligence Analyst" - ], - "created_at": "2025-12-05 12:35:49.630334" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9K", - "name": "Mathematics", - "code": "MATH", - "department": "Mathematics", - "description": "Study of numbers, structures, patterns, and logical reasoning", - "required_credits": 120, - "core_courses": [], - "elective_courses": [], - "career_paths": [ - "Mathematician", - "Statistician", - "Actuary", - "Research Scientist" - ], - "created_at": "2025-12-05 12:35:49.630341" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9M", - "name": "Business Administration", - "code": "BUS", - "department": "Business", - "description": "Management, finance, marketing, and organizational behavior", - "required_credits": 120, - "core_courses": [], - "elective_courses": [], - "career_paths": [ - "Business Analyst", - "Project Manager", - "Consultant", - "Entrepreneur" - ], - "created_at": "2025-12-05 12:35:49.630346" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9N", - "name": "Psychology", - "code": "PSY", - "department": "Psychology", - "description": "Scientific study of mind, behavior, and mental processes", - "required_credits": 120, - "core_courses": [], - "elective_courses": [], - "career_paths": [ - "Clinical Psychologist", - "Counselor", - "Research Psychologist", - "HR Specialist" - ], - "created_at": "2025-12-05 12:35:49.630350" - } - ], - "courses": [ - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9P", - "course_code": "CS001", - "title": "Introduction to Programming", - "description": "Fundamental programming concepts using Python. Variables, control structures, functions, and basic data structures.", - "credits": 3, - "difficulty_level": "beginner", - "format": "hybrid", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "12:00:00", - "end_time": "12:50:00", - "location": "Engineering Building 328" - }, - "semester": "fall", - "year": 2024, - "instructor": "Ian Gilbert", - "max_enrollment": 89, - "current_enrollment": 11, - "tags": [ - "programming", - "python", - "fundamentals" - ], - "learning_objectives": [ - "Write basic Python programs", - "Understand variables and data types", - "Use control structures effectively", - "Create and use functions" - ], - "created_at": "2025-12-05 12:35:49.630537", - "updated_at": "2025-12-05 12:35:49.630538" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9Q", - "course_code": "CS002", - "title": "Web Development", - "description": "Full-stack web development using modern frameworks. HTML, CSS, JavaScript, React, and backend APIs.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "08:00:00", - "end_time": "10:30:00", - "location": "Engineering Building 195" - }, - "semester": "fall", - "year": 2024, - "instructor": "Sabrina Smith", - "max_enrollment": 91, - "current_enrollment": 25, - "tags": [ - "web development", - "javascript", - "react", - "apis" - ], - "learning_objectives": [ - "Build responsive web interfaces", - "Develop REST APIs", - "Use modern JavaScript frameworks", - "Deploy web applications" - ], - "created_at": "2025-12-05 12:35:49.630602", - "updated_at": "2025-12-05 12:35:49.630602" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9R", - "course_code": "CS003", - "title": "Web Development", - "description": "Full-stack web development using modern frameworks. HTML, CSS, JavaScript, React, and backend APIs.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "11:30:00", - "end_time": "14:00:00", - "location": "Liberal Arts Center 703" - }, - "semester": "spring", - "year": 2024, - "instructor": "Mark Schmidt", - "max_enrollment": 74, - "current_enrollment": 43, - "tags": [ - "web development", - "javascript", - "react", - "apis" - ], - "learning_objectives": [ - "Build responsive web interfaces", - "Develop REST APIs", - "Use modern JavaScript frameworks", - "Deploy web applications" - ], - "created_at": "2025-12-05 12:35:49.630655", - "updated_at": "2025-12-05 12:35:49.630655" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9S", - "course_code": "CS004", - "title": "Database Systems", - "description": "Design and implementation of database systems. SQL, normalization, transactions, and database administration.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "online", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "11:30:00", - "end_time": "12:45:00", - "location": "Science Hall 204" - }, - "semester": "summer", - "year": 2024, - "instructor": "Christopher Adams", - "max_enrollment": 97, - "current_enrollment": 33, - "tags": [ - "databases", - "sql", - "data management" - ], - "learning_objectives": [ - "Design relational databases", - "Write complex SQL queries", - "Understand database normalization", - "Implement database transactions" - ], - "created_at": "2025-12-05 12:35:49.630709", - "updated_at": "2025-12-05 12:35:49.630710" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9T", - "course_code": "CS005", - "title": "Introduction to Programming", - "description": "Fundamental programming concepts using Python. Variables, control structures, functions, and basic data structures.", - "credits": 3, - "difficulty_level": "beginner", - "format": "hybrid", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "16:00:00", - "end_time": "18:30:00", - "location": "Science Hall 487" - }, - "semester": "summer", - "year": 2024, - "instructor": "Scott Lane", - "max_enrollment": 93, - "current_enrollment": 24, - "tags": [ - "programming", - "python", - "fundamentals" - ], - "learning_objectives": [ - "Write basic Python programs", - "Understand variables and data types", - "Use control structures effectively", - "Create and use functions" - ], - "created_at": "2025-12-05 12:35:49.630757", - "updated_at": "2025-12-05 12:35:49.630758" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9V", - "course_code": "CS006", - "title": "Introduction to Programming", - "description": "Fundamental programming concepts using Python. Variables, control structures, functions, and basic data structures.", - "credits": 3, - "difficulty_level": "beginner", - "format": "in_person", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "18:00:00", - "end_time": "18:50:00", - "location": "Liberal Arts Center 891" - }, - "semester": "fall", - "year": 2024, - "instructor": "Jennifer Contreras", - "max_enrollment": 68, - "current_enrollment": 35, - "tags": [ - "programming", - "python", - "fundamentals" - ], - "learning_objectives": [ - "Write basic Python programs", - "Understand variables and data types", - "Use control structures effectively", - "Create and use functions" - ], - "created_at": "2025-12-05 12:35:49.630805", - "updated_at": "2025-12-05 12:35:49.630805" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9W", - "course_code": "CS007", - "title": "Machine Learning", - "description": "Introduction to machine learning algorithms and applications. Supervised and unsupervised learning, neural networks.", - "credits": 4, - "difficulty_level": "advanced", - "format": "hybrid", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "10:30:00", - "end_time": "11:45:00", - "location": "Engineering Building 463" - }, - "semester": "fall", - "year": 2024, - "instructor": "Kim Vazquez", - "max_enrollment": 97, - "current_enrollment": 21, - "tags": [ - "machine learning", - "ai", - "statistics" - ], - "learning_objectives": [ - "Understand ML algorithms", - "Implement classification and regression models", - "Evaluate model performance", - "Apply ML to real-world problems" - ], - "created_at": "2025-12-05 12:35:49.630851", - "updated_at": "2025-12-05 12:35:49.630851" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9X", - "course_code": "CS008", - "title": "Web Development", - "description": "Full-stack web development using modern frameworks. HTML, CSS, JavaScript, React, and backend APIs.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "10:30:00", - "end_time": "11:45:00", - "location": "Liberal Arts Center 488" - }, - "semester": "spring", - "year": 2024, - "instructor": "Christopher Thomas", - "max_enrollment": 61, - "current_enrollment": 7, - "tags": [ - "web development", - "javascript", - "react", - "apis" - ], - "learning_objectives": [ - "Build responsive web interfaces", - "Develop REST APIs", - "Use modern JavaScript frameworks", - "Deploy web applications" - ], - "created_at": "2025-12-05 12:35:49.630896", - "updated_at": "2025-12-05 12:35:49.630896" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9Y", - "course_code": "CS009", - "title": "Data Structures and Algorithms", - "description": "Study of fundamental data structures and algorithms. Arrays, linked lists, trees, graphs, sorting, and searching.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [ - { - "course_code": "CS001", - "course_title": "Prerequisite Course 1", - "minimum_grade": "B-", - "can_be_concurrent": false - }, - { - "course_code": "CS001", - "course_title": "Prerequisite Course 1", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "13:30:00", - "end_time": "14:20:00", - "location": "Science Hall 374" - }, - "semester": "summer", - "year": 2024, - "instructor": "Pamela Costa", - "max_enrollment": 94, - "current_enrollment": 54, - "tags": [ - "algorithms", - "data structures", - "problem solving" - ], - "learning_objectives": [ - "Implement common data structures", - "Analyze algorithm complexity", - "Solve problems using appropriate data structures", - "Understand time and space complexity" - ], - "created_at": "2025-12-05 12:35:49.630951", - "updated_at": "2025-12-05 12:35:49.630952" - }, - { - "id": "01KBQSB5VYQ55YPXGFV2CM0S9Z", - "course_code": "CS010", - "title": "Web Development", - "description": "Full-stack web development using modern frameworks. HTML, CSS, JavaScript, React, and backend APIs.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Computer Science", - "major": "Computer Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "13:00:00", - "end_time": "15:30:00", - "location": "Technology Center 241" - }, - "semester": "fall", - "year": 2024, - "instructor": "Shannon Johns", - "max_enrollment": 39, - "current_enrollment": 80, - "tags": [ - "web development", - "javascript", - "react", - "apis" - ], - "learning_objectives": [ - "Build responsive web interfaces", - "Develop REST APIs", - "Use modern JavaScript frameworks", - "Deploy web applications" - ], - "created_at": "2025-12-05 12:35:49.630999", - "updated_at": "2025-12-05 12:35:49.631000" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KA", - "course_code": "DS011", - "title": "Statistics for Data Science", - "description": "Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and statistical inference.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "17:00:00", - "end_time": "19:30:00", - "location": "Business Complex 494" - }, - "semester": "winter", - "year": 2024, - "instructor": "Emily Keller", - "max_enrollment": 87, - "current_enrollment": 32, - "tags": [ - "statistics", - "probability", - "data analysis" - ], - "learning_objectives": [ - "Apply statistical methods to data", - "Perform hypothesis testing", - "Understand probability distributions", - "Conduct statistical inference" - ], - "created_at": "2025-12-05 12:35:49.631053", - "updated_at": "2025-12-05 12:35:49.631054" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KB", - "course_code": "DS012", - "title": "Statistics for Data Science", - "description": "Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and statistical inference.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "18:30:00", - "end_time": "19:20:00", - "location": "Liberal Arts Center 887" - }, - "semester": "summer", - "year": 2024, - "instructor": "Debra Torres", - "max_enrollment": 75, - "current_enrollment": 20, - "tags": [ - "statistics", - "probability", - "data analysis" - ], - "learning_objectives": [ - "Apply statistical methods to data", - "Perform hypothesis testing", - "Understand probability distributions", - "Conduct statistical inference" - ], - "created_at": "2025-12-05 12:35:49.631103", - "updated_at": "2025-12-05 12:35:49.631104" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KC", - "course_code": "DS013", - "title": "Data Visualization", - "description": "Creating effective visualizations for data communication. Tools include Python matplotlib, seaborn, and Tableau.", - "credits": 3, - "difficulty_level": "beginner", - "format": "hybrid", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "12:00:00", - "end_time": "12:50:00", - "location": "Science Hall 619" - }, - "semester": "summer", - "year": 2024, - "instructor": "Jeremy Walter", - "max_enrollment": 84, - "current_enrollment": 77, - "tags": [ - "visualization", - "python", - "tableau", - "communication" - ], - "learning_objectives": [ - "Create effective data visualizations", - "Choose appropriate chart types", - "Use visualization tools", - "Communicate insights through visuals" - ], - "created_at": "2025-12-05 12:35:49.631150", - "updated_at": "2025-12-05 12:35:49.631150" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KD", - "course_code": "DS014", - "title": "Statistics for Data Science", - "description": "Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and statistical inference.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "13:00:00", - "end_time": "14:15:00", - "location": "Technology Center 652" - }, - "semester": "summer", - "year": 2024, - "instructor": "Taylor Lucero", - "max_enrollment": 82, - "current_enrollment": 2, - "tags": [ - "statistics", - "probability", - "data analysis" - ], - "learning_objectives": [ - "Apply statistical methods to data", - "Perform hypothesis testing", - "Understand probability distributions", - "Conduct statistical inference" - ], - "created_at": "2025-12-05 12:35:49.631197", - "updated_at": "2025-12-05 12:35:49.631197" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KE", - "course_code": "DS015", - "title": "Statistics for Data Science", - "description": "Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and statistical inference.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "12:00:00", - "end_time": "13:15:00", - "location": "Engineering Building 159" - }, - "semester": "fall", - "year": 2024, - "instructor": "Hannah Daugherty", - "max_enrollment": 82, - "current_enrollment": 8, - "tags": [ - "statistics", - "probability", - "data analysis" - ], - "learning_objectives": [ - "Apply statistical methods to data", - "Perform hypothesis testing", - "Understand probability distributions", - "Conduct statistical inference" - ], - "created_at": "2025-12-05 12:35:49.631243", - "updated_at": "2025-12-05 12:35:49.631243" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KF", - "course_code": "DS016", - "title": "Statistics for Data Science", - "description": "Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and statistical inference.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "online", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [ - { - "course_code": "DS002", - "course_title": "Prerequisite Course 2", - "minimum_grade": "B-", - "can_be_concurrent": false - }, - { - "course_code": "DS006", - "course_title": "Prerequisite Course 6", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "18:30:00", - "end_time": "19:45:00", - "location": "Engineering Building 662" - }, - "semester": "summer", - "year": 2024, - "instructor": "Leslie Johnson", - "max_enrollment": 76, - "current_enrollment": 66, - "tags": [ - "statistics", - "probability", - "data analysis" - ], - "learning_objectives": [ - "Apply statistical methods to data", - "Perform hypothesis testing", - "Understand probability distributions", - "Conduct statistical inference" - ], - "created_at": "2025-12-05 12:35:49.631293", - "updated_at": "2025-12-05 12:35:49.631294" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KG", - "course_code": "DS017", - "title": "Data Visualization", - "description": "Creating effective visualizations for data communication. Tools include Python matplotlib, seaborn, and Tableau.", - "credits": 3, - "difficulty_level": "beginner", - "format": "hybrid", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [ - { - "course_code": "DS004", - "course_title": "Prerequisite Course 4", - "minimum_grade": "C", - "can_be_concurrent": true - } - ], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "11:00:00", - "end_time": "11:50:00", - "location": "Liberal Arts Center 165" - }, - "semester": "fall", - "year": 2024, - "instructor": "Samantha Boyer", - "max_enrollment": 49, - "current_enrollment": 8, - "tags": [ - "visualization", - "python", - "tableau", - "communication" - ], - "learning_objectives": [ - "Create effective data visualizations", - "Choose appropriate chart types", - "Use visualization tools", - "Communicate insights through visuals" - ], - "created_at": "2025-12-05 12:35:49.631341", - "updated_at": "2025-12-05 12:35:49.631341" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KH", - "course_code": "DS018", - "title": "Statistics for Data Science", - "description": "Statistical methods and probability theory for data analysis. Hypothesis testing, regression, and statistical inference.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "online", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [ - { - "course_code": "DS008", - "course_title": "Prerequisite Course 8", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "09:00:00", - "end_time": "10:15:00", - "location": "Business Complex 385" - }, - "semester": "spring", - "year": 2024, - "instructor": "Shelia Reyes", - "max_enrollment": 32, - "current_enrollment": 12, - "tags": [ - "statistics", - "probability", - "data analysis" - ], - "learning_objectives": [ - "Apply statistical methods to data", - "Perform hypothesis testing", - "Understand probability distributions", - "Conduct statistical inference" - ], - "created_at": "2025-12-05 12:35:49.631394", - "updated_at": "2025-12-05 12:35:49.631395" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KJ", - "course_code": "DS019", - "title": "Data Visualization", - "description": "Creating effective visualizations for data communication. Tools include Python matplotlib, seaborn, and Tableau.", - "credits": 3, - "difficulty_level": "beginner", - "format": "hybrid", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "14:30:00", - "end_time": "15:45:00", - "location": "Science Hall 578" - }, - "semester": "fall", - "year": 2024, - "instructor": "Danielle Petersen", - "max_enrollment": 27, - "current_enrollment": 51, - "tags": [ - "visualization", - "python", - "tableau", - "communication" - ], - "learning_objectives": [ - "Create effective data visualizations", - "Choose appropriate chart types", - "Use visualization tools", - "Communicate insights through visuals" - ], - "created_at": "2025-12-05 12:35:49.631440", - "updated_at": "2025-12-05 12:35:49.631440" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KK", - "course_code": "DS020", - "title": "Data Visualization", - "description": "Creating effective visualizations for data communication. Tools include Python matplotlib, seaborn, and Tableau.", - "credits": 3, - "difficulty_level": "beginner", - "format": "online", - "department": "Data Science", - "major": "Data Science", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "11:00:00", - "end_time": "11:50:00", - "location": "Technology Center 294" - }, - "semester": "spring", - "year": 2024, - "instructor": "Christopher Gomez", - "max_enrollment": 55, - "current_enrollment": 59, - "tags": [ - "visualization", - "python", - "tableau", - "communication" - ], - "learning_objectives": [ - "Create effective data visualizations", - "Choose appropriate chart types", - "Use visualization tools", - "Communicate insights through visuals" - ], - "created_at": "2025-12-05 12:35:49.631484", - "updated_at": "2025-12-05 12:35:49.631484" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KM", - "course_code": "MATH021", - "title": "Calculus I", - "description": "Differential calculus including limits, derivatives, and applications. Foundation for advanced mathematics.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "15:00:00", - "end_time": "15:50:00", - "location": "Technology Center 151" - }, - "semester": "fall", - "year": 2024, - "instructor": "Tiffany Turner MD", - "max_enrollment": 50, - "current_enrollment": 21, - "tags": [ - "calculus", - "derivatives", - "limits" - ], - "learning_objectives": [ - "Understand limits and continuity", - "Calculate derivatives", - "Apply calculus to real problems", - "Understand fundamental theorem" - ], - "created_at": "2025-12-05 12:35:49.631532", - "updated_at": "2025-12-05 12:35:49.631533" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KN", - "course_code": "MATH022", - "title": "Linear Algebra", - "description": "Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "15:00:00", - "end_time": "17:30:00", - "location": "Business Complex 985" - }, - "semester": "spring", - "year": 2024, - "instructor": "Jeanette Jarvis", - "max_enrollment": 68, - "current_enrollment": 0, - "tags": [ - "linear algebra", - "matrices", - "vectors" - ], - "learning_objectives": [ - "Perform matrix operations", - "Understand vector spaces", - "Calculate eigenvalues and eigenvectors", - "Apply linear algebra to problems" - ], - "created_at": "2025-12-05 12:35:49.631578", - "updated_at": "2025-12-05 12:35:49.631578" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KP", - "course_code": "MATH023", - "title": "Linear Algebra", - "description": "Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "15:30:00", - "end_time": "16:45:00", - "location": "Technology Center 533" - }, - "semester": "winter", - "year": 2024, - "instructor": "Ryan Boyd", - "max_enrollment": 39, - "current_enrollment": 24, - "tags": [ - "linear algebra", - "matrices", - "vectors" - ], - "learning_objectives": [ - "Perform matrix operations", - "Understand vector spaces", - "Calculate eigenvalues and eigenvectors", - "Apply linear algebra to problems" - ], - "created_at": "2025-12-05 12:35:49.631622", - "updated_at": "2025-12-05 12:35:49.631622" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KQ", - "course_code": "MATH024", - "title": "Linear Algebra", - "description": "Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [ - { - "course_code": "MATH009", - "course_title": "Prerequisite Course 9", - "minimum_grade": "B-", - "can_be_concurrent": true - }, - { - "course_code": "MATH009", - "course_title": "Prerequisite Course 9", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "08:00:00", - "end_time": "09:15:00", - "location": "Liberal Arts Center 865" - }, - "semester": "fall", - "year": 2024, - "instructor": "Barbara King", - "max_enrollment": 50, - "current_enrollment": 51, - "tags": [ - "linear algebra", - "matrices", - "vectors" - ], - "learning_objectives": [ - "Perform matrix operations", - "Understand vector spaces", - "Calculate eigenvalues and eigenvectors", - "Apply linear algebra to problems" - ], - "created_at": "2025-12-05 12:35:49.631670", - "updated_at": "2025-12-05 12:35:49.631670" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KR", - "course_code": "MATH025", - "title": "Calculus I", - "description": "Differential calculus including limits, derivatives, and applications. Foundation for advanced mathematics.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [], - "schedule": { - "days": [ - "thursday" - ], - "start_time": "11:00:00", - "end_time": "13:30:00", - "location": "Science Hall 734" - }, - "semester": "summer", - "year": 2024, - "instructor": "Jennifer Dixon PhD", - "max_enrollment": 53, - "current_enrollment": 26, - "tags": [ - "calculus", - "derivatives", - "limits" - ], - "learning_objectives": [ - "Understand limits and continuity", - "Calculate derivatives", - "Apply calculus to real problems", - "Understand fundamental theorem" - ], - "created_at": "2025-12-05 12:35:49.631716", - "updated_at": "2025-12-05 12:35:49.631716" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KS", - "course_code": "MATH026", - "title": "Linear Algebra", - "description": "Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "12:30:00", - "end_time": "13:45:00", - "location": "Liberal Arts Center 234" - }, - "semester": "fall", - "year": 2024, - "instructor": "Ethan Bridges", - "max_enrollment": 78, - "current_enrollment": 79, - "tags": [ - "linear algebra", - "matrices", - "vectors" - ], - "learning_objectives": [ - "Perform matrix operations", - "Understand vector spaces", - "Calculate eigenvalues and eigenvectors", - "Apply linear algebra to problems" - ], - "created_at": "2025-12-05 12:35:49.631760", - "updated_at": "2025-12-05 12:35:49.631761" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KT", - "course_code": "MATH027", - "title": "Calculus I", - "description": "Differential calculus including limits, derivatives, and applications. Foundation for advanced mathematics.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [ - { - "course_code": "MATH003", - "course_title": "Prerequisite Course 3", - "minimum_grade": "C", - "can_be_concurrent": false - }, - { - "course_code": "MATH006", - "course_title": "Prerequisite Course 6", - "minimum_grade": "C+", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "16:00:00", - "end_time": "16:50:00", - "location": "Liberal Arts Center 618" - }, - "semester": "summer", - "year": 2024, - "instructor": "William Edwards", - "max_enrollment": 98, - "current_enrollment": 67, - "tags": [ - "calculus", - "derivatives", - "limits" - ], - "learning_objectives": [ - "Understand limits and continuity", - "Calculate derivatives", - "Apply calculus to real problems", - "Understand fundamental theorem" - ], - "created_at": "2025-12-05 12:35:49.631807", - "updated_at": "2025-12-05 12:35:49.631807" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KV", - "course_code": "MATH028", - "title": "Calculus I", - "description": "Differential calculus including limits, derivatives, and applications. Foundation for advanced mathematics.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [ - { - "course_code": "MATH018", - "course_title": "Prerequisite Course 18", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "thursday" - ], - "start_time": "12:00:00", - "end_time": "14:30:00", - "location": "Engineering Building 999" - }, - "semester": "spring", - "year": 2024, - "instructor": "Nicholas Simpson", - "max_enrollment": 63, - "current_enrollment": 26, - "tags": [ - "calculus", - "derivatives", - "limits" - ], - "learning_objectives": [ - "Understand limits and continuity", - "Calculate derivatives", - "Apply calculus to real problems", - "Understand fundamental theorem" - ], - "created_at": "2025-12-05 12:35:49.631853", - "updated_at": "2025-12-05 12:35:49.631853" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KW", - "course_code": "MATH029", - "title": "Linear Algebra", - "description": "Vector spaces, matrices, eigenvalues, and linear transformations. Essential for data science and engineering.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [ - { - "course_code": "MATH009", - "course_title": "Prerequisite Course 9", - "minimum_grade": "C", - "can_be_concurrent": true - }, - { - "course_code": "MATH005", - "course_title": "Prerequisite Course 5", - "minimum_grade": "B-", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "thursday" - ], - "start_time": "15:30:00", - "end_time": "18:00:00", - "location": "Science Hall 966" - }, - "semester": "winter", - "year": 2024, - "instructor": "Mr. Christopher Anderson", - "max_enrollment": 90, - "current_enrollment": 54, - "tags": [ - "linear algebra", - "matrices", - "vectors" - ], - "learning_objectives": [ - "Perform matrix operations", - "Understand vector spaces", - "Calculate eigenvalues and eigenvectors", - "Apply linear algebra to problems" - ], - "created_at": "2025-12-05 12:35:49.631902", - "updated_at": "2025-12-05 12:35:49.631902" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KX", - "course_code": "MATH030", - "title": "Calculus I", - "description": "Differential calculus including limits, derivatives, and applications. Foundation for advanced mathematics.", - "credits": 4, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Mathematics", - "major": "Mathematics", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "09:00:00", - "end_time": "09:50:00", - "location": "Science Hall 658" - }, - "semester": "spring", - "year": 2024, - "instructor": "Jasmine Knight", - "max_enrollment": 75, - "current_enrollment": 16, - "tags": [ - "calculus", - "derivatives", - "limits" - ], - "learning_objectives": [ - "Understand limits and continuity", - "Calculate derivatives", - "Apply calculus to real problems", - "Understand fundamental theorem" - ], - "created_at": "2025-12-05 12:35:49.631947", - "updated_at": "2025-12-05 12:35:49.631947" - }, - { - "id": "01KBQSB5VZ3490FT449SH6Y3KY", - "course_code": "BUS031", - "title": "Principles of Management", - "description": "Fundamental management concepts including planning, organizing, leading, and controlling organizational resources.", - "credits": 3, - "difficulty_level": "beginner", - "format": "hybrid", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "13:00:00", - "end_time": "14:15:00", - "location": "Engineering Building 466" - }, - "semester": "spring", - "year": 2024, - "instructor": "Mark Chang", - "max_enrollment": 33, - "current_enrollment": 45, - "tags": [ - "management", - "leadership", - "organization" - ], - "learning_objectives": [ - "Understand management principles", - "Apply leadership concepts", - "Organize teams effectively", - "Control organizational resources" - ], - "created_at": "2025-12-05 12:35:49.631991", - "updated_at": "2025-12-05 12:35:49.631991" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PE6", - "course_code": "BUS032", - "title": "Marketing Strategy", - "description": "Strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "thursday" - ], - "start_time": "10:00:00", - "end_time": "12:30:00", - "location": "Engineering Building 985" - }, - "semester": "winter", - "year": 2024, - "instructor": "Daniel Williams", - "max_enrollment": 23, - "current_enrollment": 22, - "tags": [ - "marketing", - "strategy", - "consumer behavior" - ], - "learning_objectives": [ - "Develop marketing strategies", - "Analyze market opportunities", - "Understand consumer behavior", - "Implement digital marketing" - ], - "created_at": "2025-12-05 12:35:49.632041", - "updated_at": "2025-12-05 12:35:49.632041" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PE7", - "course_code": "BUS033", - "title": "Marketing Strategy", - "description": "Strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "18:00:00", - "end_time": "20:30:00", - "location": "Engineering Building 373" - }, - "semester": "fall", - "year": 2024, - "instructor": "Amanda Jefferson", - "max_enrollment": 68, - "current_enrollment": 4, - "tags": [ - "marketing", - "strategy", - "consumer behavior" - ], - "learning_objectives": [ - "Develop marketing strategies", - "Analyze market opportunities", - "Understand consumer behavior", - "Implement digital marketing" - ], - "created_at": "2025-12-05 12:35:49.632091", - "updated_at": "2025-12-05 12:35:49.632091" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PE8", - "course_code": "BUS034", - "title": "Marketing Strategy", - "description": "Strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "11:30:00", - "end_time": "12:45:00", - "location": "Liberal Arts Center 458" - }, - "semester": "spring", - "year": 2024, - "instructor": "Roger Alexander", - "max_enrollment": 23, - "current_enrollment": 24, - "tags": [ - "marketing", - "strategy", - "consumer behavior" - ], - "learning_objectives": [ - "Develop marketing strategies", - "Analyze market opportunities", - "Understand consumer behavior", - "Implement digital marketing" - ], - "created_at": "2025-12-05 12:35:49.632136", - "updated_at": "2025-12-05 12:35:49.632136" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PE9", - "course_code": "BUS035", - "title": "Marketing Strategy", - "description": "Strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "12:00:00", - "end_time": "13:15:00", - "location": "Liberal Arts Center 891" - }, - "semester": "winter", - "year": 2024, - "instructor": "Robert Edwards", - "max_enrollment": 88, - "current_enrollment": 42, - "tags": [ - "marketing", - "strategy", - "consumer behavior" - ], - "learning_objectives": [ - "Develop marketing strategies", - "Analyze market opportunities", - "Understand consumer behavior", - "Implement digital marketing" - ], - "created_at": "2025-12-05 12:35:49.632180", - "updated_at": "2025-12-05 12:35:49.632180" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEA", - "course_code": "BUS036", - "title": "Principles of Management", - "description": "Fundamental management concepts including planning, organizing, leading, and controlling organizational resources.", - "credits": 3, - "difficulty_level": "beginner", - "format": "in_person", - "department": "Business", - "major": "Business Administration", - "prerequisites": [ - { - "course_code": "BUS012", - "course_title": "Prerequisite Course 12", - "minimum_grade": "B-", - "can_be_concurrent": false - }, - { - "course_code": "BUS014", - "course_title": "Prerequisite Course 14", - "minimum_grade": "B-", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "12:00:00", - "end_time": "12:50:00", - "location": "Liberal Arts Center 694" - }, - "semester": "winter", - "year": 2024, - "instructor": "Monica Clark", - "max_enrollment": 93, - "current_enrollment": 24, - "tags": [ - "management", - "leadership", - "organization" - ], - "learning_objectives": [ - "Understand management principles", - "Apply leadership concepts", - "Organize teams effectively", - "Control organizational resources" - ], - "created_at": "2025-12-05 12:35:49.632230", - "updated_at": "2025-12-05 12:35:49.632230" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEB", - "course_code": "BUS037", - "title": "Marketing Strategy", - "description": "Strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "14:00:00", - "end_time": "14:50:00", - "location": "Technology Center 632" - }, - "semester": "spring", - "year": 2024, - "instructor": "Devin Williams", - "max_enrollment": 66, - "current_enrollment": 55, - "tags": [ - "marketing", - "strategy", - "consumer behavior" - ], - "learning_objectives": [ - "Develop marketing strategies", - "Analyze market opportunities", - "Understand consumer behavior", - "Implement digital marketing" - ], - "created_at": "2025-12-05 12:35:49.632274", - "updated_at": "2025-12-05 12:35:49.632275" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEC", - "course_code": "BUS038", - "title": "Principles of Management", - "description": "Fundamental management concepts including planning, organizing, leading, and controlling organizational resources.", - "credits": 3, - "difficulty_level": "beginner", - "format": "online", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "17:30:00", - "end_time": "18:45:00", - "location": "Science Hall 779" - }, - "semester": "summer", - "year": 2024, - "instructor": "Rebecca Holmes", - "max_enrollment": 72, - "current_enrollment": 41, - "tags": [ - "management", - "leadership", - "organization" - ], - "learning_objectives": [ - "Understand management principles", - "Apply leadership concepts", - "Organize teams effectively", - "Control organizational resources" - ], - "created_at": "2025-12-05 12:35:49.632320", - "updated_at": "2025-12-05 12:35:49.632320" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PED", - "course_code": "BUS039", - "title": "Marketing Strategy", - "description": "Strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "online", - "department": "Business", - "major": "Business Administration", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "16:00:00", - "end_time": "17:15:00", - "location": "Business Complex 296" - }, - "semester": "spring", - "year": 2024, - "instructor": "Richard York", - "max_enrollment": 98, - "current_enrollment": 72, - "tags": [ - "marketing", - "strategy", - "consumer behavior" - ], - "learning_objectives": [ - "Develop marketing strategies", - "Analyze market opportunities", - "Understand consumer behavior", - "Implement digital marketing" - ], - "created_at": "2025-12-05 12:35:49.632364", - "updated_at": "2025-12-05 12:35:49.632365" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEE", - "course_code": "BUS040", - "title": "Marketing Strategy", - "description": "Strategic marketing planning, market analysis, consumer behavior, and digital marketing techniques.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "hybrid", - "department": "Business", - "major": "Business Administration", - "prerequisites": [ - { - "course_code": "BUS015", - "course_title": "Prerequisite Course 15", - "minimum_grade": "C+", - "can_be_concurrent": false - }, - { - "course_code": "BUS007", - "course_title": "Prerequisite Course 7", - "minimum_grade": "B-", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "16:00:00", - "end_time": "18:30:00", - "location": "Liberal Arts Center 411" - }, - "semester": "spring", - "year": 2024, - "instructor": "David Gonzalez", - "max_enrollment": 30, - "current_enrollment": 36, - "tags": [ - "marketing", - "strategy", - "consumer behavior" - ], - "learning_objectives": [ - "Develop marketing strategies", - "Analyze market opportunities", - "Understand consumer behavior", - "Implement digital marketing" - ], - "created_at": "2025-12-05 12:35:49.632412", - "updated_at": "2025-12-05 12:35:49.632412" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEF", - "course_code": "PSY041", - "title": "Cognitive Psychology", - "description": "Study of mental processes including perception, memory, thinking, and problem-solving.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "11:30:00", - "end_time": "12:20:00", - "location": "Engineering Building 330" - }, - "semester": "fall", - "year": 2024, - "instructor": "Heather Sanders DDS", - "max_enrollment": 25, - "current_enrollment": 31, - "tags": [ - "cognitive psychology", - "memory", - "perception" - ], - "learning_objectives": [ - "Understand cognitive processes", - "Study memory systems", - "Analyze problem-solving", - "Explore perception mechanisms" - ], - "created_at": "2025-12-05 12:35:49.632459", - "updated_at": "2025-12-05 12:35:49.632459" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEG", - "course_code": "PSY042", - "title": "Cognitive Psychology", - "description": "Study of mental processes including perception, memory, thinking, and problem-solving.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [], - "schedule": { - "days": [ - "thursday" - ], - "start_time": "09:30:00", - "end_time": "12:00:00", - "location": "Technology Center 524" - }, - "semester": "winter", - "year": 2024, - "instructor": "Kelly Rodgers", - "max_enrollment": 83, - "current_enrollment": 51, - "tags": [ - "cognitive psychology", - "memory", - "perception" - ], - "learning_objectives": [ - "Understand cognitive processes", - "Study memory systems", - "Analyze problem-solving", - "Explore perception mechanisms" - ], - "created_at": "2025-12-05 12:35:49.632504", - "updated_at": "2025-12-05 12:35:49.632504" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEH", - "course_code": "PSY043", - "title": "Introduction to Psychology", - "description": "Overview of psychological principles, research methods, and major areas of study in psychology.", - "credits": 3, - "difficulty_level": "beginner", - "format": "online", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [], - "schedule": { - "days": [ - "tuesday", - "thursday" - ], - "start_time": "18:00:00", - "end_time": "19:15:00", - "location": "Science Hall 868" - }, - "semester": "spring", - "year": 2024, - "instructor": "Austin Combs", - "max_enrollment": 42, - "current_enrollment": 66, - "tags": [ - "psychology", - "research methods", - "behavior" - ], - "learning_objectives": [ - "Understand psychological principles", - "Learn research methods", - "Explore areas of psychology", - "Apply psychological concepts" - ], - "created_at": "2025-12-05 12:35:49.632547", - "updated_at": "2025-12-05 12:35:49.632548" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEJ", - "course_code": "PSY044", - "title": "Cognitive Psychology", - "description": "Study of mental processes including perception, memory, thinking, and problem-solving.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "online", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "16:00:00", - "end_time": "16:50:00", - "location": "Science Hall 968" - }, - "semester": "summer", - "year": 2024, - "instructor": "Joel Mccoy", - "max_enrollment": 76, - "current_enrollment": 78, - "tags": [ - "cognitive psychology", - "memory", - "perception" - ], - "learning_objectives": [ - "Understand cognitive processes", - "Study memory systems", - "Analyze problem-solving", - "Explore perception mechanisms" - ], - "created_at": "2025-12-05 12:35:49.632591", - "updated_at": "2025-12-05 12:35:49.632591" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEK", - "course_code": "PSY045", - "title": "Cognitive Psychology", - "description": "Study of mental processes including perception, memory, thinking, and problem-solving.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [], - "schedule": { - "days": [ - "thursday" - ], - "start_time": "15:00:00", - "end_time": "17:30:00", - "location": "Business Complex 861" - }, - "semester": "summer", - "year": 2024, - "instructor": "Dylan Chavez", - "max_enrollment": 86, - "current_enrollment": 62, - "tags": [ - "cognitive psychology", - "memory", - "perception" - ], - "learning_objectives": [ - "Understand cognitive processes", - "Study memory systems", - "Analyze problem-solving", - "Explore perception mechanisms" - ], - "created_at": "2025-12-05 12:35:49.632634", - "updated_at": "2025-12-05 12:35:49.632635" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEM", - "course_code": "PSY046", - "title": "Introduction to Psychology", - "description": "Overview of psychological principles, research methods, and major areas of study in psychology.", - "credits": 3, - "difficulty_level": "beginner", - "format": "in_person", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [ - { - "course_code": "PSY021", - "course_title": "Prerequisite Course 21", - "minimum_grade": "B-", - "can_be_concurrent": true - }, - { - "course_code": "PSY010", - "course_title": "Prerequisite Course 10", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "15:00:00", - "end_time": "16:15:00", - "location": "Liberal Arts Center 830" - }, - "semester": "spring", - "year": 2024, - "instructor": "Megan Waters", - "max_enrollment": 28, - "current_enrollment": 53, - "tags": [ - "psychology", - "research methods", - "behavior" - ], - "learning_objectives": [ - "Understand psychological principles", - "Learn research methods", - "Explore areas of psychology", - "Apply psychological concepts" - ], - "created_at": "2025-12-05 12:35:49.632681", - "updated_at": "2025-12-05 12:35:49.632681" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEN", - "course_code": "PSY047", - "title": "Cognitive Psychology", - "description": "Study of mental processes including perception, memory, thinking, and problem-solving.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [ - { - "course_code": "PSY025", - "course_title": "Prerequisite Course 25", - "minimum_grade": "B-", - "can_be_concurrent": false - }, - { - "course_code": "PSY002", - "course_title": "Prerequisite Course 2", - "minimum_grade": "B-", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "monday", - "wednesday" - ], - "start_time": "16:30:00", - "end_time": "17:45:00", - "location": "Science Hall 525" - }, - "semester": "summer", - "year": 2024, - "instructor": "Ashley Mccarty", - "max_enrollment": 58, - "current_enrollment": 49, - "tags": [ - "cognitive psychology", - "memory", - "perception" - ], - "learning_objectives": [ - "Understand cognitive processes", - "Study memory systems", - "Analyze problem-solving", - "Explore perception mechanisms" - ], - "created_at": "2025-12-05 12:35:49.632728", - "updated_at": "2025-12-05 12:35:49.632729" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEP", - "course_code": "PSY048", - "title": "Cognitive Psychology", - "description": "Study of mental processes including perception, memory, thinking, and problem-solving.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "online", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [ - { - "course_code": "PSY002", - "course_title": "Prerequisite Course 2", - "minimum_grade": "C+", - "can_be_concurrent": false - }, - { - "course_code": "PSY026", - "course_title": "Prerequisite Course 26", - "minimum_grade": "B-", - "can_be_concurrent": true - } - ], - "schedule": { - "days": [ - "thursday" - ], - "start_time": "16:00:00", - "end_time": "18:30:00", - "location": "Engineering Building 599" - }, - "semester": "spring", - "year": 2024, - "instructor": "Joyce Gilbert", - "max_enrollment": 99, - "current_enrollment": 68, - "tags": [ - "cognitive psychology", - "memory", - "perception" - ], - "learning_objectives": [ - "Understand cognitive processes", - "Study memory systems", - "Analyze problem-solving", - "Explore perception mechanisms" - ], - "created_at": "2025-12-05 12:35:49.632775", - "updated_at": "2025-12-05 12:35:49.632775" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PEQ", - "course_code": "PSY049", - "title": "Introduction to Psychology", - "description": "Overview of psychological principles, research methods, and major areas of study in psychology.", - "credits": 3, - "difficulty_level": "beginner", - "format": "online", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [ - { - "course_code": "PSY012", - "course_title": "Prerequisite Course 12", - "minimum_grade": "C", - "can_be_concurrent": false - }, - { - "course_code": "PSY021", - "course_title": "Prerequisite Course 21", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "tuesday" - ], - "start_time": "17:00:00", - "end_time": "19:30:00", - "location": "Business Complex 185" - }, - "semester": "winter", - "year": 2024, - "instructor": "Kenneth Craig", - "max_enrollment": 55, - "current_enrollment": 53, - "tags": [ - "psychology", - "research methods", - "behavior" - ], - "learning_objectives": [ - "Understand psychological principles", - "Learn research methods", - "Explore areas of psychology", - "Apply psychological concepts" - ], - "created_at": "2025-12-05 12:35:49.632821", - "updated_at": "2025-12-05 12:35:49.632821" - }, - { - "id": "01KBQSB5W0V47C74FHBMXE8PER", - "course_code": "PSY050", - "title": "Cognitive Psychology", - "description": "Study of mental processes including perception, memory, thinking, and problem-solving.", - "credits": 3, - "difficulty_level": "intermediate", - "format": "in_person", - "department": "Psychology", - "major": "Psychology", - "prerequisites": [ - { - "course_code": "PSY015", - "course_title": "Prerequisite Course 15", - "minimum_grade": "B-", - "can_be_concurrent": true - }, - { - "course_code": "PSY003", - "course_title": "Prerequisite Course 3", - "minimum_grade": "C", - "can_be_concurrent": false - } - ], - "schedule": { - "days": [ - "monday", - "wednesday", - "friday" - ], - "start_time": "15:00:00", - "end_time": "15:50:00", - "location": "Technology Center 867" - }, - "semester": "fall", - "year": 2024, - "instructor": "Jaime Huang", - "max_enrollment": 99, - "current_enrollment": 19, - "tags": [ - "cognitive psychology", - "memory", - "perception" - ], - "learning_objectives": [ - "Understand cognitive processes", - "Study memory systems", - "Analyze problem-solving", - "Explore perception mechanisms" - ], - "created_at": "2025-12-05 12:35:49.632868", - "updated_at": "2025-12-05 12:35:49.632868" - } - ] -} \ No newline at end of file diff --git a/notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb b/notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb deleted file mode 100644 index 2e01f2a..0000000 --- a/notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb +++ /dev/null @@ -1,3940 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a19be531208b364b", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# 🧠 Working and Long-Term Memory\n", - "\n", - "**⏱️ Estimated Time:** 45-60 minutes\n", - "\n", - "## 🎯 Learning Objectives\n", - "\n", - "By the end of this notebook, you will:\n", - "\n", - "1. **Understand** why memory is essential for context engineering\n", - "2. **Implement** working memory for conversation continuity\n", - "3. **Use** long-term memory for persistent user knowledge\n", - "4. **Integrate** memory with your Section 2 RAG system\n", - "5. **Build** a complete memory-enhanced course advisor\n", - "\n", - "---\n", - "\n", - "## 🔗 Recap\n", - "\n", - "### **Section 1: The Four Context Types**\n", - "\n", - "Recall the four context types from Section 1:\n", - "\n", - "1. **System Context** (Static) - Role, instructions, guidelines\n", - "2. **User Context** (Dynamic, User-Specific) - Profile, preferences, goals\n", - "3. **Conversation Context** (Dynamic, Session-Specific) - **← Memory enables this!**\n", - "4. **Retrieved Context** (Dynamic, Query-Specific) - RAG results\n", - "\n", - "### **Section 2: Stateless RAG**\n", - "\n", - "Your Section 2 RAG system was **stateless**:\n", - "\n", - "```python\n", - "async def rag_query(query, student_profile):\n", - " # 1. Search courses (Retrieved Context)\n", - " courses = await course_manager.search_courses(query)\n", - "\n", - " # 2. Assemble context (System + User + Retrieved)\n", - " context = assemble_context(system_prompt, student_profile, courses)\n", - "\n", - " # 3. Generate response\n", - " response = llm.invoke(context)\n", - "\n", - " # ❌ No conversation history stored\n", - " # ❌ Each query is independent\n", - " # ❌ Can't reference previous messages\n", - "```\n", - "\n", - "**The Problem:** Every query starts from scratch. No conversation continuity.\n", - "\n", - "---\n", - "\n", - "## 🚨 Why Agents Need Memory: The Grounding Problem\n", - "\n", - "Before diving into implementation, let's understand the fundamental problem that memory solves.\n", - "\n", - "**Grounding** means understanding what users are referring to. Natural conversation is full of references:\n", - "\n", - "### **Without Memory:**\n", - "\n", - "```\n", - "User: \"Tell me about CS401\"\n", - "Agent: \"CS401 is Machine Learning. It covers supervised learning...\"\n", - "\n", - "User: \"What are its prerequisites?\"\n", - "Agent: ❌ \"What does 'it' refer to? Please specify which course.\"\n", - "\n", - "User: \"The course we just discussed!\"\n", - "Agent: ❌ \"I don't have access to previous messages. Which course?\"\n", - "```\n", - "\n", - "**This is a terrible user experience.**\n", - "\n", - "### Types of References That Need Grounding\n", - "\n", - "**Pronouns:**\n", - "- \"it\", \"that course\", \"those\", \"this one\"\n", - "- \"he\", \"she\", \"they\" (referring to people)\n", - "\n", - "**Descriptions:**\n", - "- \"the easy one\", \"the online course\"\n", - "- \"my advisor\", \"that professor\"\n", - "\n", - "**Implicit context:**\n", - "- \"Can I take it?\" → Take what?\n", - "- \"When does it start?\" → What starts?\n", - "\n", - "**Temporal references:**\n", - "- \"you mentioned\", \"earlier\", \"last time\"\n", - "\n", - "### **With Memory:**\n", - "\n", - "```\n", - "User: \"Tell me about CS401\"\n", - "Agent: \"CS401 is Machine Learning. It covers...\"\n", - "[Stores: User asked about CS401]\n", - "\n", - "User: \"What are its prerequisites?\"\n", - "Agent: [Checks memory: \"its\" = CS401]\n", - "Agent: ✅ \"CS401 requires CS201 and MATH301\"\n", - "\n", - "User: \"Can I take it?\"\n", - "Agent: [Checks memory: \"it\" = CS401, checks student transcript]\n", - "Agent: ✅ \"You've completed CS201 but still need MATH301\"\n", - "```\n", - "\n", - "**Now the conversation flows naturally!**\n", - "\n", - "---\n", - "\n", - "## 🧠 Two Types of Memory\n", - "\n", - "### **1. Working Memory (Session-Scoped)**\n", - "\n", - " - **What:** Conversation messages from the current session\n", - " - **Purpose:** Reference resolution, conversation continuity\n", - " - **Lifetime:** Persists for the session\n", - " - **Storage:** Conversation remains accessible when you return to the same session\n", - "\n", - "**Example:**\n", - "```\n", - "Session: session_123\n", - "Messages:\n", - " 1. User: \"Tell me about CS401\"\n", - " 2. Agent: \"CS401 is Machine Learning...\"\n", - " 3. User: \"What are its prerequisites?\"\n", - " 4. Agent: \"CS401 requires CS201 and MATH301\"\n", - "```\n", - "\n", - "**Key Point:** Just like ChatGPT or Claude, when you return to a conversation, the working memory is still there. The conversation doesn't disappear!\n", - "\n", - "### **2. Long-term Memory (Cross-Session)**\n", - "\n", - " - **What:** Persistent knowledge (user preferences, domain facts, business rules)\n", - " - **Purpose:** Personalization AND consistent application behavior across sessions\n", - " - **Lifetime:** Permanent (until explicitly deleted)\n", - " - **Scope:** Can be user-specific OR application-wide\n", - "\n", - "**Examples:**\n", - "\n", - "**User-Scoped (Personalization):**\n", - "```\n", - "User: student_sarah\n", - " - \"Prefers online courses over in-person\"\n", - " - \"Major: Computer Science, focus on AI/ML\"\n", - " - \"Goal: Graduate Spring 2026\"\n", - " - \"Completed: CS101, CS201, MATH301\"\n", - "```\n", - "\n", - "**Application-Scoped (Domain Knowledge):**\n", - "```\n", - "Domain: course_requirements\n", - " - \"CS401 requires CS201 as prerequisite\"\n", - " - \"Maximum course load is 18 credits per semester\"\n", - " - \"Registration opens 2 weeks before semester start\"\n", - " - \"Lab courses require campus attendance\"\n", - "```\n", - "\n", - "### **Comparison: Working vs. Long-term Memory**\n", - "\n", - "| Working Memory | Long-term Memory |\n", - "|----------------|------------------|\n", - "| **Session-scoped** | **User-scoped OR Application-scoped** |\n", - "| Current conversation | Important facts, rules, knowledge |\n", - "| Persists for session | Persists across sessions |\n", - "| Full message history | Extracted knowledge (user + domain) |\n", - "| Loaded/saved each turn | Searched when needed |\n", - "| **Challenge:** Context window limits | **Challenge:** Storage growth |\n", - "\n", - "---\n", - "\n", - "## 📦 Setup and Environment\n", - "\n", - "Let's set up our environment with the necessary dependencies and connections. We'll build on Section 2's RAG foundation and add memory capabilities.\n", - "\n", - "### ⚠️ Prerequisites\n", - "\n", - "**Before running this notebook, make sure you have:**\n", - "\n", - "1. **Docker Desktop running** - Required for Redis and Agent Memory Server\n", - "\n", - "2. **Environment variables** - Create a `.env` file in the project root directory:\n", - " ```bash\n", - " # Copy the example file (if it exists)\n", - " cd ../..\n", - " # Or create .env manually with:\n", - " # OPENAI_API_KEY=your_actual_openai_api_key_here\n", - " # REDIS_URL=redis://localhost:6379\n", - " # AGENT_MEMORY_URL=http://localhost:8088\n", - " ```\n", - "\n", - "3. **Start services** - Make sure Redis and Agent Memory Server are running:\n", - " ```bash\n", - " # Start Redis and Agent Memory Server using docker-compose\n", - " cd ../..\n", - " docker-compose up -d\n", - " ```\n", - "\n", - "**Note:** Using docker-compose will:\n", - "- ✅ Start Redis on port 6379\n", - "- ✅ Start Agent Memory Server on port 8088\n", - "- ✅ Configure networking between services\n", - "- ✅ Persist data in Docker volumes\n", - "\n", - "If the Memory Server is not available, the notebook will skip memory-related demos but will still run.\n" - ] - }, - { - "cell_type": "markdown", - "id": "c8736deb126c3f16", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "56268deee3282f75", - "metadata": {}, - "source": [ - "### Automated Setup Check\n", - "\n", - "Let's run the setup script to ensure all services are running properly.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "3df05c4a01f7d55e", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:38.656600Z", - "iopub.status.busy": "2025-12-09T19:44:38.656440Z", - "iopub.status.idle": "2025-12-09T19:44:38.730872Z", - "shell.execute_reply": "2025-12-09T19:44:38.730371Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Checking if required services are running...\n", - "\n", - "✅ Redis is running\n", - "✅ Agent Memory Server is running\n", - "\n", - "If services are not running, start them with:\n", - " cd ../..\n", - " docker-compose up -d\n" - ] - } - ], - "source": [ - "# Check if services are running\n", - "import subprocess\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "print(\"Checking if required services are running...\\n\")\n", - "\n", - "# Check if Redis is running\n", - "try:\n", - " result = subprocess.run(\n", - " [\"docker\", \"ps\", \"--filter\", \"name=redis\", \"--format\", \"{{.Names}}\"],\n", - " capture_output=True,\n", - " text=True,\n", - " timeout=5\n", - " )\n", - " if \"redis\" in result.stdout:\n", - " print(\"✅ Redis is running\")\n", - " else:\n", - " print(\"⚠️ Redis is not running. Start it with: docker-compose up -d\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not check Redis status: {e}\")\n", - "\n", - "# Check if Agent Memory Server is running\n", - "try:\n", - " result = subprocess.run(\n", - " [\"docker\", \"ps\", \"--filter\", \"name=agent-memory\", \"--format\", \"{{.Names}}\"],\n", - " capture_output=True,\n", - " text=True,\n", - " timeout=5\n", - " )\n", - " if \"agent-memory\" in result.stdout or \"memory\" in result.stdout:\n", - " print(\"✅ Agent Memory Server is running\")\n", - " else:\n", - " print(\"⚠️ Agent Memory Server is not running. Start it with: docker-compose up -d\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not check Agent Memory Server status: {e}\")\n", - "\n", - "print(\"\\nIf services are not running, start them with:\")\n", - "print(\" cd ../..\")\n", - "print(\" docker-compose up -d\")" - ] - }, - { - "cell_type": "markdown", - "id": "5911ec87de846a67", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "1b7a2c9167d8c5b9", - "metadata": {}, - "source": [ - "### Install Dependencies\n", - "\n", - "If you haven't already installed the reference-agent package, uncomment and run the following:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "ccc5f86042f5c1b9", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:38.732774Z", - "iopub.status.busy": "2025-12-09T19:44:38.732639Z", - "iopub.status.idle": "2025-12-09T19:44:38.734808Z", - "shell.execute_reply": "2025-12-09T19:44:38.734254Z" - } - }, - "outputs": [], - "source": [ - "# Uncomment to install the project package\n", - "# %pip install -q -e ../..\n", - "\n", - "# Uncomment to install agent-memory-client\n", - "# %pip install -q agent-memory-client" - ] - }, - { - "cell_type": "markdown", - "id": "517cc7d3a970f91d", - "metadata": {}, - "source": [ - "### Load Environment Variables\n", - "\n", - "We'll load environment variables from the `.env` file in the `reference-agent` directory.\n", - "\n", - "**Required variables:**\n", - "- `OPENAI_API_KEY` - Your OpenAI API key\n", - "- `REDIS_URL` - Redis connection URL (default: redis://localhost:6379)\n", - "- `AGENT_MEMORY_URL` - Agent Memory Server URL (default: http://localhost:8088)\n", - "\n", - "If you haven't created the `.env` file yet, copy `.env.example` and add your OpenAI API key.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "c712b48760cc932c", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:38.736225Z", - "iopub.status.busy": "2025-12-09T19:44:38.736119Z", - "iopub.status.idle": "2025-12-09T19:44:38.743556Z", - "shell.execute_reply": "2025-12-09T19:44:38.742961Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment variables loaded\n", - " REDIS_URL: redis://localhost:6379\n", - " AGENT_MEMORY_URL: http://localhost:8088\n" - ] - } - ], - "source": [ - "import os\n", - "from pathlib import Path\n", - "\n", - "from dotenv import load_dotenv\n", - "\n", - "# Load environment variables from project root directory\n", - "env_path = Path(\"../../.env\")\n", - "load_dotenv(dotenv_path=env_path)\n", - "\n", - "# Verify required environment variables\n", - "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n", - "REDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379\")\n", - "AGENT_MEMORY_URL = os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8088\")\n", - "\n", - "if not OPENAI_API_KEY:\n", - " print(\n", - " f\"\"\"❌ OPENAI_API_KEY not found!\n", - "\n", - " Please create a .env file at: {env_path.absolute()}\n", - "\n", - " With the following content:\n", - " OPENAI_API_KEY=your_openai_api_key\n", - " REDIS_URL=redis://localhost:6379\n", - " AGENT_MEMORY_URL=http://localhost:8088\n", - " \"\"\"\n", - " )\n", - "else:\n", - " print(\"✅ Environment variables loaded\")\n", - " print(f\" REDIS_URL: {REDIS_URL}\")\n", - " print(f\" AGENT_MEMORY_URL: {AGENT_MEMORY_URL}\")" - ] - }, - { - "cell_type": "markdown", - "id": "c92aa2f60384e30d", - "metadata": {}, - "source": [ - "### Import Core Libraries\n", - "\n", - "We'll import standard Python libraries and async support for our memory operations.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "60eefefd58081b7e", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:38.744824Z", - "iopub.status.busy": "2025-12-09T19:44:38.744743Z", - "iopub.status.idle": "2025-12-09T19:44:38.746686Z", - "shell.execute_reply": "2025-12-09T19:44:38.746294Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Core libraries imported\n" - ] - } - ], - "source": [ - "import asyncio\n", - "from datetime import datetime\n", - "from typing import Any, Dict, List, Optional\n", - "\n", - "print(\"✅ Core libraries imported\")" - ] - }, - { - "cell_type": "markdown", - "id": "2718bb5d2ac0595c", - "metadata": {}, - "source": [ - "### Import Section 2 Components\n", - "\n", - "We're building on Section 2's RAG foundation, so we'll reuse the same components:\n", - "- `redis_config` - Redis connection and configuration\n", - "- `CourseManager` - Course search and management\n", - "- `StudentProfile` and other models - Data structures\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a5172a46aa07a1cb", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:38.747718Z", - "iopub.status.busy": "2025-12-09T19:44:38.747645Z", - "iopub.status.idle": "2025-12-09T19:44:40.945713Z", - "shell.execute_reply": "2025-12-09T19:44:40.945216Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Section 2 components imported\n", - " CourseManager: Available\n", - " Redis Config: Available\n", - " Models: Course, StudentProfile, etc.\n" - ] - } - ], - "source": [ - "from redis_context_course.course_manager import CourseManager\n", - "from redis_context_course.models import (\n", - " Course,\n", - " CourseFormat,\n", - " DifficultyLevel,\n", - " Semester,\n", - " StudentProfile,\n", - ")\n", - "\n", - "# Import Section 2 components\n", - "from redis_context_course.redis_config import redis_config\n", - "\n", - "print(\"✅ Section 2 components imported\")\n", - "print(f\" CourseManager: Available\")\n", - "print(f\" Redis Config: Available\")\n", - "print(f\" Models: Course, StudentProfile, etc.\")" - ] - }, - { - "cell_type": "markdown", - "id": "9ccfa42b7a0cdf94", - "metadata": {}, - "source": [ - "### Import LangChain Components\n", - "\n", - "We'll use LangChain for LLM interaction and message handling.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "430df8f6e59d12b1", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:40.946955Z", - "iopub.status.busy": "2025-12-09T19:44:40.946820Z", - "iopub.status.idle": "2025-12-09T19:44:40.948774Z", - "shell.execute_reply": "2025-12-09T19:44:40.948445Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ LangChain components imported\n", - " ChatOpenAI: Available\n", - " Message types: HumanMessage, SystemMessage, AIMessage\n" - ] - } - ], - "source": [ - "from langchain_core.messages import AIMessage, HumanMessage, SystemMessage\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "print(\"✅ LangChain components imported\")\n", - "print(f\" ChatOpenAI: Available\")\n", - "print(f\" Message types: HumanMessage, SystemMessage, AIMessage\")" - ] - }, - { - "cell_type": "markdown", - "id": "42862eec4ae3b753", - "metadata": {}, - "source": [ - "### Import Agent Memory Server Client\n", - "\n", - "The Agent Memory Server provides production-ready memory management. If it's not available, we'll note that and continue with limited functionality.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "aeb02858f71bebff", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:40.949871Z", - "iopub.status.busy": "2025-12-09T19:44:40.949793Z", - "iopub.status.idle": "2025-12-09T19:44:40.951895Z", - "shell.execute_reply": "2025-12-09T19:44:40.951509Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Agent Memory Server client available\n", - " MemoryAPIClient: Ready\n", - " Memory models: WorkingMemory, MemoryMessage, ClientMemoryRecord\n" - ] - } - ], - "source": [ - "# Import Agent Memory Server client\n", - "try:\n", - " from agent_memory_client import MemoryAPIClient, MemoryClientConfig\n", - " from agent_memory_client.models import (\n", - " ClientMemoryRecord,\n", - " MemoryMessage,\n", - " WorkingMemory,\n", - " )\n", - "\n", - " MEMORY_SERVER_AVAILABLE = True\n", - " print(\"✅ Agent Memory Server client available\")\n", - " print(\" MemoryAPIClient: Ready\")\n", - " print(\" Memory models: WorkingMemory, MemoryMessage, ClientMemoryRecord\")\n", - "except ImportError:\n", - " MEMORY_SERVER_AVAILABLE = False\n", - " print(\"⚠️ Agent Memory Server not available\")\n", - " print(\" Install with: pip install agent-memory-client\")\n", - " print(\" Start server: See reference-agent/README.md\")\n", - " print(\" Note: Some demos will be skipped\")" - ] - }, - { - "cell_type": "markdown", - "id": "98b94c4f6cd2ed12", - "metadata": {}, - "source": [ - "### What We Just Did\n", - "\n", - "We've successfully set up our environment with all the necessary components:\n", - "\n", - "**Imported:**\n", - "- ✅ Section 2 RAG components (`CourseManager`, `redis_config`, models)\n", - "- ✅ LangChain for LLM interaction\n", - "- ✅ Agent Memory Server client (if available)\n", - "\n", - "**Why This Matters:**\n", - "- Building on Section 2's foundation (not starting from scratch)\n", - "- Agent Memory Server provides scalable, persistent memory\n", - "- Same Redis University domain for consistency\n", - "\n", - "---\n", - "\n", - "## 🔧 Initialize Components\n", - "\n", - "Now let's initialize the components we'll use throughout this notebook.\n" - ] - }, - { - "cell_type": "markdown", - "id": "d6490ff7de0df7c4", - "metadata": {}, - "source": [ - "### Initialize Course Manager\n", - "\n", - "The `CourseManager` handles course search and retrieval, just like in Section 2.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "5e2d3b080e16bd3d", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:40.952934Z", - "iopub.status.busy": "2025-12-09T19:44:40.952867Z", - "iopub.status.idle": "2025-12-09T19:44:41.125356Z", - "shell.execute_reply": "2025-12-09T19:44:41.124985Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:40 redisvl.index.index INFO Index already exists, not overwriting.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Course Manager initialized\n", - " Ready to search and retrieve courses\n" - ] - } - ], - "source": [ - "# Initialize Course Manager\n", - "course_manager = CourseManager()\n", - "\n", - "print(\"✅ Course Manager initialized\")\n", - "print(\" Ready to search and retrieve courses\")" - ] - }, - { - "cell_type": "markdown", - "id": "b0de7fcb447d889d", - "metadata": {}, - "source": [ - "### Initialize LLM\n", - "\n", - "We'll use GPT-4o with temperature=0.0 for consistent, deterministic responses.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "5321f905c99e4d7c", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.126453Z", - "iopub.status.busy": "2025-12-09T19:44:41.126375Z", - "iopub.status.idle": "2025-12-09T19:44:41.134331Z", - "shell.execute_reply": "2025-12-09T19:44:41.133784Z" - } - }, - "outputs": [], - "source": [ - "# Initialize LLM\n", - "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0.0)" - ] - }, - { - "cell_type": "markdown", - "id": "cf422c27fa939aba", - "metadata": {}, - "source": [ - "### Initialize Memory Client\n", - "\n", - "If the Agent Memory Server is available, we'll initialize the memory client. This client handles both working memory (conversation history) and long-term memory (persistent facts).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "e0ae5b78a69a7813", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.135401Z", - "iopub.status.busy": "2025-12-09T19:44:41.135334Z", - "iopub.status.idle": "2025-12-09T19:44:41.140201Z", - "shell.execute_reply": "2025-12-09T19:44:41.139868Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Memory Client initialized\n", - " Base URL: http://localhost:8088\n", - " Namespace: redis_university\n", - " Ready for working memory and long-term memory operations\n" - ] - } - ], - "source": [ - "# Initialize Memory Client\n", - "if MEMORY_SERVER_AVAILABLE:\n", - " config = MemoryClientConfig(\n", - " base_url=AGENT_MEMORY_URL, default_namespace=\"redis_university\"\n", - " )\n", - " memory_client = MemoryAPIClient(config=config)\n", - " print(\"✅ Memory Client initialized\")\n", - " print(f\" Base URL: {config.base_url}\")\n", - " print(f\" Namespace: {config.default_namespace}\")\n", - " print(\" Ready for working memory and long-term memory operations\")\n", - "else:\n", - " memory_client = None\n", - " print(\"⚠️ Memory Server not available\")\n", - " print(\" Running with limited functionality\")\n", - " print(\" Some demos will be skipped\")" - ] - }, - { - "cell_type": "markdown", - "id": "f22962c20e837fe5", - "metadata": {}, - "source": [ - "### Create Sample Student Profile\n", - "\n", - "We'll create a sample student profile to use throughout our demos. This follows the same pattern from Section 2.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "79ba51694f18ea25", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.141262Z", - "iopub.status.busy": "2025-12-09T19:44:41.141194Z", - "iopub.status.idle": "2025-12-09T19:44:41.143346Z", - "shell.execute_reply": "2025-12-09T19:44:41.143046Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Student profile created\n", - " Name: Sarah Chen\n", - " Major: Computer Science\n", - " Year: 2\n", - " Interests: machine learning, data science, algorithms\n", - " Completed: CS101, CS201\n", - " Preferred Format: online\n" - ] - } - ], - "source": [ - "# Create sample student profile\n", - "sarah = StudentProfile(\n", - " name=\"Sarah Chen\",\n", - " email=\"sarah.chen@university.edu\",\n", - " major=\"Computer Science\",\n", - " year=2,\n", - " interests=[\"machine learning\", \"data science\", \"algorithms\"],\n", - " completed_courses=[\"CS101\", \"CS201\"],\n", - " current_courses=[\"MATH301\"],\n", - " preferred_format=CourseFormat.ONLINE,\n", - " preferred_difficulty=DifficultyLevel.INTERMEDIATE,\n", - ")\n", - "\n", - "print(\"✅ Student profile created\")\n", - "print(f\" Name: {sarah.name}\")\n", - "print(f\" Major: {sarah.major}\")\n", - "print(f\" Year: {sarah.year}\")\n", - "print(f\" Interests: {', '.join(sarah.interests)}\")\n", - "print(f\" Completed: {', '.join(sarah.completed_courses)}\")\n", - "print(f\" Preferred Format: {sarah.preferred_format.value}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "a2876f73d8cc1a72", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.144647Z", - "iopub.status.busy": "2025-12-09T19:44:41.144579Z", - "iopub.status.idle": "2025-12-09T19:44:41.146538Z", - "shell.execute_reply": "2025-12-09T19:44:41.146193Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🎯 INITIALIZATION SUMMARY\n", - "\n", - "✅ Course Manager: Ready\n", - "✅ LLM (GPT-4o): Ready\n", - "✅ Memory Client: Ready\n", - "✅ Student Profile: Sarah Chen\n" - ] - } - ], - "source": [ - "print(\"🎯 INITIALIZATION SUMMARY\")\n", - "print(f\"\\n✅ Course Manager: Ready\")\n", - "print(f\"✅ LLM (GPT-4o): Ready\")\n", - "print(\n", - " f\"{'✅' if MEMORY_SERVER_AVAILABLE else '⚠️ '} Memory Client: {'Ready' if MEMORY_SERVER_AVAILABLE else 'Not Available'}\"\n", - ")\n", - "print(f\"✅ Student Profile: {sarah.name}\")" - ] - }, - { - "cell_type": "markdown", - "id": "814b81fa017798d6", - "metadata": {}, - "source": [ - "### Initialization Done\n", - "📋 What We're Building On:\n", - "- Section 2's RAG foundation (CourseManager, redis_config)\n", - "- Same StudentProfile model\n", - "- Same Redis configuration\n", - "\n", - "✨ What We're Adding:\n", - "- Memory Client for conversation history\n", - "- Working Memory for session context\n", - "- Long-term Memory for persistent knowledge\n" - ] - }, - { - "cell_type": "markdown", - "id": "ddb232f3d2509406", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 📚 Part 1: Working Memory Fundamentals\n", - "\n", - "### **What is Working Memory?**\n", - "\n", - "Working memory stores **conversation messages** for the current session. It enables:\n", - "\n", - "- ✅ **Reference resolution** - \"it\", \"that course\", \"the one you mentioned\"\n", - "- ✅ **Context continuity** - Each message builds on previous messages\n", - "- ✅ **Natural conversations** - Users don't repeat themselves\n", - "\n", - "### **How It Works:**\n", - "\n", - "```\n", - "Turn 1: Load working memory (empty) → Process query → Save messages\n", - "Turn 2: Load working memory (1 exchange) → Process query → Save messages\n", - "Turn 3: Load working memory (2 exchanges) → Process query → Save messages\n", - "```\n", - "\n", - "Each turn has access to all previous messages in the session.\n", - "\n", - "---\n", - "\n", - "## 🧪 Hands-On: Working Memory in Action\n", - "\n", - "Let's simulate a multi-turn conversation with working memory. We'll break this down step-by-step to see how working memory enables natural conversation flow.\n" - ] - }, - { - "cell_type": "markdown", - "id": "98c4c3dacf1beaff", - "metadata": {}, - "source": [ - "### Setup: Create Session and Student IDs\n", - "\n", - "Now that we have our components initialized, let's create session and student identifiers for our working memory demo.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "8d44da725da024c7", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.147723Z", - "iopub.status.busy": "2025-12-09T19:44:41.147656Z", - "iopub.status.idle": "2025-12-09T19:44:41.149406Z", - "shell.execute_reply": "2025-12-09T19:44:41.149119Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🎯 Working Memory Demo Setup" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " Student ID: sarah.chen\n", - " Session ID: session_sarah.chen_demo\n", - " Ready to demonstrate multi-turn conversation\n" - ] - } - ], - "source": [ - "# Setup for working memory demo\n", - "student_id = sarah.email.split(\"@\")[0] # \"sarah.chen\"\n", - "session_id = f\"session_{student_id}_demo\"\n", - "\n", - "print(\"🎯 Working Memory Demo Setup\")\n", - "print(f\" Student ID: {student_id}\")\n", - "print(f\" Session ID: {session_id}\")\n", - "print(\" Ready to demonstrate multi-turn conversation\")" - ] - }, - { - "cell_type": "markdown", - "id": "193929957ec58e3e", - "metadata": {}, - "source": [ - "### Turn 1: Initial Query\n", - "\n", - "Let's start with a simple query about a course. This is the first turn, so working memory will be empty.\n", - "\n", - "We'll break this down into clear steps:\n", - "1. We will use Memory Server\n", - "2. Load working memory (will be empty on first turn)\n", - "3. Search for the course\n", - "4. Generate a response\n", - "5. Save the conversation to working memory\n" - ] - }, - { - "cell_type": "markdown", - "id": "ab3990d104a25fa1", - "metadata": {}, - "source": [ - "#### Step 1: Set up the user query\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "fc21436e9dcf0dae", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.150577Z", - "iopub.status.busy": "2025-12-09T19:44:41.150507Z", - "iopub.status.idle": "2025-12-09T19:44:41.152326Z", - "shell.execute_reply": "2025-12-09T19:44:41.151943Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "📍 TURN 1: User asks about a course\n", - "================================================================================\n", - "\n", - "👤 User: Tell me about Data Structures and Algorithms\n" - ] - } - ], - "source": [ - "# Check if Memory Server is available\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"📍 TURN 1: User asks about a course\")\n", - "print(\"=\" * 80)\n", - "\n", - "# Define the user's query\n", - "turn1_query = \"Tell me about Data Structures and Algorithms\"\n", - "print(f\"\\n👤 User: {turn1_query}\")" - ] - }, - { - "cell_type": "markdown", - "id": "a12b09b27ce726a2", - "metadata": {}, - "source": [ - "#### Step 2: Load working memory\n", - "\n", - "On the first turn, working memory will be empty since this is a new session.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "aefbddd80e873727", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.153311Z", - "iopub.status.busy": "2025-12-09T19:44:41.153241Z", - "iopub.status.idle": "2025-12-09T19:44:41.179125Z", - "shell.execute_reply": "2025-12-09T19:44:41.178727Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:41 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/session_sarah.chen_demo?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Working Memory Status:\n", - " Messages in memory: 20\n", - " Status: Has history\n" - ] - } - ], - "source": [ - "# Load working memory (empty for first turn)\n", - "_, turn1_working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=student_id, model_name=\"gpt-4o\"\n", - ")\n", - "\n", - "print(f\"📊 Working Memory Status:\")\n", - "print(f\" Messages in memory: {len(turn1_working_memory.messages)}\")\n", - "print(\n", - " f\" Status: {'Empty (first turn)' if len(turn1_working_memory.messages) == 0 else 'Has history'}\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "632be78f65633470", - "metadata": {}, - "source": [ - "#### Step 3: Search for the course\n", - "\n", - "Use the course manager to search for courses matching the query.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "b3c3f15020256def", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:41.180196Z", - "iopub.status.busy": "2025-12-09T19:44:41.180113Z", - "iopub.status.idle": "2025-12-09T19:44:42.114697Z", - "shell.execute_reply": "2025-12-09T19:44:42.113660Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🔍 Searching for courses...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:42 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Found 1 course(s)\n", - " - CS009: Data Structures and Algorithms\n" - ] - } - ], - "source": [ - "print(f\"\\n🔍 Searching for courses...\")\n", - "turn1_courses = await course_manager.search_courses(turn1_query, limit=1)\n", - "\n", - "if turn1_courses:\n", - " print(f\" Found {len(turn1_courses)} course(s)\")\n", - "\n", - " # print the course details\n", - " for course in turn1_courses:\n", - " print(f\" - {course.course_code}: {course.title}\")" - ] - }, - { - "cell_type": "markdown", - "id": "4e0da4579584d55f", - "metadata": {}, - "source": [ - "#### Step 4: Generate response using LLM\n", - "\n", - "Use the LLM to generate a natural response based on the retrieved course information.\n", - "\n", - "This follows the **RAG pattern**: Retrieve (done in Step 3) → Augment (add to context) → Generate (use LLM).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "183b9954750e3342", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:42.117003Z", - "iopub.status.busy": "2025-12-09T19:44:42.116839Z", - "iopub.status.idle": "2025-12-09T19:44:42.119984Z", - "shell.execute_reply": "2025-12-09T19:44:42.119451Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Course context: Course Information:\n", - "- Code: CS009\n", - "- Title: Data Structures and Algorithms\n", - "- Description: Study of fundamental data structures and algorithms. Arrays, linked lists, trees, graphs, sorting, and searching.\n", - "- Prerequisites: CS001, CS001\n", - "- Credits: 4\n", - "\n" - ] - } - ], - "source": [ - "course = turn1_courses[0]\n", - "\n", - "course_context = f\"\"\"Course Information:\n", - "- Code: {course.course_code}\n", - "- Title: {course.title}\n", - "- Description: {course.description}\n", - "- Prerequisites: {', '.join([p.course_code for p in course.prerequisites]) if course.prerequisites else 'None'}\n", - "- Credits: {course.credits}\n", - "\"\"\"\n", - "\n", - "print(f\" Course context: {course_context}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "83732656aa9bea58", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:42.122001Z", - "iopub.status.busy": "2025-12-09T19:44:42.121829Z", - "iopub.status.idle": "2025-12-09T19:44:44.933860Z", - "shell.execute_reply": "2025-12-09T19:44:44.933229Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "💭 Generating response using LLM...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:44 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: The course \"Data Structures and Algorithms\" (CS009) is a comprehensive study of fundamental data structures and algorithms. It covers essential topics such as arrays, linked lists, trees, graphs, sorting, and searching. This course is designed to provide a solid foundation in understanding how data can be organized and manipulated efficiently, which is crucial for solving complex computational problems.\n", - "\n", - "To enroll in this course, you must have completed the prerequisite course CS001. The course is worth 4 credits, indicating a significant time commitment and depth of study. This course is essential for anyone looking to deepen their understanding of computer science and improve their problem-solving skills in programming.\n" - ] - } - ], - "source": [ - "# Build messages for LLM\n", - "turn1_messages = [\n", - " SystemMessage(\n", - " content=\"You are a helpful course advisor. Answer questions about courses based on the provided information.\"\n", - " ),\n", - " HumanMessage(content=f\"{course_context}\\n\\nUser question: {turn1_query}\"),\n", - "]\n", - "\n", - "# Generate response using LLM\n", - "print(f\"\\n💭 Generating response using LLM...\")\n", - "turn1_response = llm.invoke(turn1_messages).content\n", - "\n", - "print(f\"\\n🤖 Agent: {turn1_response}\")" - ] - }, - { - "cell_type": "markdown", - "id": "866b65c69382e61c", - "metadata": {}, - "source": [ - "#### Step 5: Save to working memory\n", - "\n", - "Add both the user query and assistant response to working memory for future turns.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "dc3e623850cc0420", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:44.936054Z", - "iopub.status.busy": "2025-12-09T19:44:44.935868Z", - "iopub.status.idle": "2025-12-09T19:44:44.953714Z", - "shell.execute_reply": "2025-12-09T19:44:44.953105Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:44 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/session_sarah.chen_demo?user_id=sarah.chen&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "✅ Saved to working memory\n", - " Messages now in memory: 22\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Add messages to working memory\n", - " turn1_working_memory.messages.extend(\n", - " [\n", - " MemoryMessage(role=\"user\", content=turn1_query),\n", - " MemoryMessage(role=\"assistant\", content=turn1_response),\n", - " ]\n", - " )\n", - "\n", - " # Save to Memory Server\n", - " await memory_client.put_working_memory(\n", - " session_id=session_id,\n", - " memory=turn1_working_memory,\n", - " user_id=student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " print(f\"\\n✅ Saved to working memory\")\n", - " print(f\" Messages now in memory: {len(turn1_working_memory.messages)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "cc81aac22b5dee20", - "metadata": {}, - "source": [ - "### What Just Happened in Turn 1?\n", - "\n", - "**Initial State:**\n", - "- Working memory was empty (first turn)\n", - "- No conversation history available\n", - "\n", - "**Actions (RAG Pattern):**\n", - "1. **Retrieve:** Searched for Data Structures and Algorithms in the course database\n", - "2. **Augment:** Added course information to LLM context\n", - "3. **Generate:** LLM created a natural language response\n", - "4. **Save:** Stored conversation in working memory\n", - "\n", - "**Result:**\n", - "- Working memory now contains 2 messages (1 user, 1 assistant)\n", - "- This history will be available for the next turn\n", - "\n", - "**Key Insight:** Even the first turn uses the LLM to generate natural responses based on retrieved information.\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "dcb4b2dd6bc900eb", - "metadata": {}, - "source": [ - "### Turn 2: Follow-up with Pronoun Reference\n", - "\n", - "Now let's ask a follow-up question using \"its\" - a pronoun that requires context from Turn 1.\n", - "\n", - "We'll break this down into steps:\n", - "1. Set up the query with pronoun reference\n", - "2. Load working memory (now contains Turn 1)\n", - "3. Build context with conversation history\n", - "4. Generate response using LLM\n", - "5. Save to working memory\n" - ] - }, - { - "cell_type": "markdown", - "id": "f514e2a3477f589a", - "metadata": {}, - "source": [ - "#### Step 1: Set up the query\n" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "33bdfccd3e1dd8ef", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:44.956006Z", - "iopub.status.busy": "2025-12-09T19:44:44.955862Z", - "iopub.status.idle": "2025-12-09T19:44:44.958819Z", - "shell.execute_reply": "2025-12-09T19:44:44.958173Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "================================================================================\n", - "📍 TURN 2: User uses pronoun reference ('its')\n", - "================================================================================\n", - "\n", - "👤 User: What are its prerequisites?\n", - " Note: 'its' refers to Data Structures and Algorithms from Turn 1\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"📍 TURN 2: User uses pronoun reference ('its')\")\n", - " print(\"=\" * 80)\n", - "\n", - " turn2_query = \"What are its prerequisites?\"\n", - " print(f\"\\n👤 User: {turn2_query}\")\n", - " print(f\" Note: 'its' refers to Data Structures and Algorithms from Turn 1\")" - ] - }, - { - "cell_type": "markdown", - "id": "251400e6c872266e", - "metadata": {}, - "source": [ - "#### Step 2: Load working memory\n", - "\n", - "This time, working memory will contain the conversation from Turn 1.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "f829cbd34e3e664b", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:44.960956Z", - "iopub.status.busy": "2025-12-09T19:44:44.960812Z", - "iopub.status.idle": "2025-12-09T19:44:44.972235Z", - "shell.execute_reply": "2025-12-09T19:44:44.971655Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:44 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/session_sarah.chen_demo?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "📊 Working Memory Status:\n", - " Messages in memory: 22\n", - " Contains: Turn 1 conversation\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Load working memory (now has 1 exchange from Turn 1)\n", - " _, turn2_working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " print(f\"\\n📊 Working Memory Status:\")\n", - " print(f\" Messages in memory: {len(turn2_working_memory.messages)}\")\n", - " print(f\" Contains: Turn 1 conversation\")" - ] - }, - { - "cell_type": "markdown", - "id": "efd1b46d58f3b20d", - "metadata": {}, - "source": [ - "#### Step 3: Build context with conversation history\n", - "\n", - "To resolve the pronoun \"its\", we need to include the conversation history in the LLM context.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "35b9ded0ac51de86", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:44.973788Z", - "iopub.status.busy": "2025-12-09T19:44:44.973666Z", - "iopub.status.idle": "2025-12-09T19:44:44.976737Z", - "shell.execute_reply": "2025-12-09T19:44:44.976111Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🔧 Building context with conversation history...\n", - " Total messages in context: 24\n", - " Includes: System prompt + Turn 1 history + current query\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " print(f\"\\n🔧 Building context with conversation history...\")\n", - "\n", - " # Start with system message\n", - " turn2_messages = [\n", - " SystemMessage(\n", - " content=\"You are a helpful course advisor. Use conversation history to resolve references like 'it', 'that course', etc.\"\n", - " )\n", - " ]\n", - "\n", - " # Add conversation history from working memory\n", - " for msg in turn2_working_memory.messages:\n", - " if msg.role == \"user\":\n", - " turn2_messages.append(HumanMessage(content=msg.content))\n", - " elif msg.role == \"assistant\":\n", - " turn2_messages.append(AIMessage(content=msg.content))\n", - "\n", - " # Add current query\n", - " turn2_messages.append(HumanMessage(content=turn2_query))\n", - "\n", - " print(f\" Total messages in context: {len(turn2_messages)}\")\n", - " print(f\" Includes: System prompt + Turn 1 history + current query\")" - ] - }, - { - "cell_type": "markdown", - "id": "680baddab86f534e", - "metadata": {}, - "source": [ - "#### Step 4: Generate response using LLM\n", - "\n", - "The LLM can now resolve \"its\" by looking at the conversation history.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "30ea9d9182b2beeb", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:44.978290Z", - "iopub.status.busy": "2025-12-09T19:44:44.978183Z", - "iopub.status.idle": "2025-12-09T19:44:47.775950Z", - "shell.execute_reply": "2025-12-09T19:44:47.774761Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "💭 LLM resolving 'its' using conversation history...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:47 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: The prerequisite for the \"Data Structures and Algorithms\" course (CS009) is CS001. This prerequisite ensures that students have a foundational understanding of computer science principles and basic programming skills, which are essential for tackling the more advanced topics covered in data structures and algorithms.\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " print(f\"\\n💭 LLM resolving 'its' using conversation history...\")\n", - " turn2_response = llm.invoke(turn2_messages).content\n", - "\n", - " print(f\"\\n🤖 Agent: {turn2_response}\")" - ] - }, - { - "cell_type": "markdown", - "id": "3dd00ff09f527aff", - "metadata": {}, - "source": [ - "#### Step 5: Save to working memory\n", - "\n", - "Add this turn's conversation to working memory for future turns.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "ec2c0ec81187f379", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:47.779215Z", - "iopub.status.busy": "2025-12-09T19:44:47.778926Z", - "iopub.status.idle": "2025-12-09T19:44:47.800587Z", - "shell.execute_reply": "2025-12-09T19:44:47.799031Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:47 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/session_sarah.chen_demo?user_id=sarah.chen&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "✅ Saved to working memory\n", - " Messages now in memory: 24\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Add messages to working memory\n", - " turn2_working_memory.messages.extend(\n", - " [\n", - " MemoryMessage(role=\"user\", content=turn2_query),\n", - " MemoryMessage(role=\"assistant\", content=turn2_response),\n", - " ]\n", - " )\n", - "\n", - " # Save to Memory Server\n", - " await memory_client.put_working_memory(\n", - " session_id=session_id,\n", - " memory=turn2_working_memory,\n", - " user_id=student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " print(f\"\\n✅ Saved to working memory\")\n", - " print(f\" Messages now in memory: {len(turn2_working_memory.messages)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "8f4dc82b0b179c3a", - "metadata": {}, - "source": [ - "### What Just Happened in Turn 2?\n", - "\n", - "**Initial State:**\n", - "- Working memory contained Turn 1 conversation (2 messages)\n", - "- User asked about \"its prerequisites\" - pronoun reference\n", - "\n", - "**Actions:**\n", - "1. Loaded working memory with Turn 1 history\n", - "2. Built context including conversation history\n", - "3. LLM resolved \"its\" → Data Structures and Algorithms (from Turn 1)\n", - "4. Generated response about Data Structures and Algorithms's prerequisites\n", - "5. Saved updated conversation to working memory\n", - "\n", - "**Result:**\n", - "- Working memory now contains 4 messages (2 exchanges)\n", - "- LLM successfully resolved pronoun reference using conversation history\n", - "- Natural conversation flow maintained\n", - "\n", - "**Key Insight:** Without working memory, the LLM wouldn't know what \"its\" refers to!\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "1fe8d7ec9cc0cd09", - "metadata": {}, - "source": [ - "### Turn 3: Another Follow-up\n", - "\n", - "Let's ask one more follow-up question to demonstrate continued conversation continuity.\n" - ] - }, - { - "cell_type": "markdown", - "id": "3d2e559273936233", - "metadata": {}, - "source": [ - "#### Step 1: Set up the query\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "bc4bc7899cdb4a22", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:47.803205Z", - "iopub.status.busy": "2025-12-09T19:44:47.802997Z", - "iopub.status.idle": "2025-12-09T19:44:47.806116Z", - "shell.execute_reply": "2025-12-09T19:44:47.805517Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "================================================================================\n", - "📍 TURN 3: User asks another follow-up\n", - "================================================================================\n", - "\n", - "👤 User: Can I take it next semester?\n", - " Note: 'it' refers to Data Structures and Algorithms from Turn 1\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"📍 TURN 3: User asks another follow-up\")\n", - " print(\"=\" * 80)\n", - "\n", - " turn3_query = \"Can I take it next semester?\"\n", - " print(f\"\\n👤 User: {turn3_query}\")\n", - " print(f\" Note: 'it' refers to Data Structures and Algorithms from Turn 1\")" - ] - }, - { - "cell_type": "markdown", - "id": "d822bee53d5f72aa", - "metadata": {}, - "source": [ - "#### Step 2: Load working memory with full conversation history\n" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "6ef1b5784db41cf0", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:47.808340Z", - "iopub.status.busy": "2025-12-09T19:44:47.808189Z", - "iopub.status.idle": "2025-12-09T19:44:47.820879Z", - "shell.execute_reply": "2025-12-09T19:44:47.820426Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:47 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/session_sarah.chen_demo?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "📊 Working Memory Status:\n", - " Messages in memory: 24\n", - " Contains: Turns 1 and 2\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Load working memory (now has 2 exchanges)\n", - " _, turn3_working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " print(f\"\\n📊 Working Memory Status:\")\n", - " print(f\" Messages in memory: {len(turn3_working_memory.messages)}\")\n", - " print(f\" Contains: Turns 1 and 2\")" - ] - }, - { - "cell_type": "markdown", - "id": "5108d55a0822552", - "metadata": {}, - "source": [ - "#### Step 3: Build context and generate response\n" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "6385c7befbd151c2", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:47.822818Z", - "iopub.status.busy": "2025-12-09T19:44:47.822690Z", - "iopub.status.idle": "2025-12-09T19:44:50.945372Z", - "shell.execute_reply": "2025-12-09T19:44:50.944594Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Total messages in context: 26\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:50 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: Yes, you can take the \"Data Structures and Algorithms\" course (CS009) next semester. It's important to ensure that you have completed the prerequisite course, CS001, before enrolling. If you meet the prerequisite requirement, you should be able to register for the course when enrollment opens for the next semester. Be sure to check with your academic advisor or the course catalog for specific enrollment dates and any additional requirements.\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Build context with full conversation history\n", - " turn3_messages = [\n", - " SystemMessage(\n", - " content=\"You are a helpful course advisor. Use conversation history to resolve references.\"\n", - " )\n", - " ]\n", - "\n", - " for msg in turn3_working_memory.messages:\n", - " if msg.role == \"user\":\n", - " turn3_messages.append(HumanMessage(content=msg.content))\n", - " elif msg.role == \"assistant\":\n", - " turn3_messages.append(AIMessage(content=msg.content))\n", - "\n", - " turn3_messages.append(HumanMessage(content=turn3_query))\n", - "\n", - " print(f\" Total messages in context: {len(turn3_messages)}\")\n", - "\n", - " # Generate response\n", - " turn3_response = llm.invoke(turn3_messages).content\n", - "\n", - " print(f\"\\n🤖 Agent: {turn3_response}\")" - ] - }, - { - "cell_type": "markdown", - "id": "ac080d85ee7ab8aa", - "metadata": {}, - "source": [ - "\n", - "\n", - "✅ DEMO COMPLETE: Working memory enabled natural conversation flow!\n", - "\n", - "---\n", - "### Working Memory Demo Summary\n", - "\n", - "Let's review what we just demonstrated across three conversation turns.\n", - "\n", - "## 🎯 Working Memory Demo Summary\n", - "### 📊 What Happened:\n", - "**Turn 1:** 'Tell me about Data Structures and Algorithms'\n", - "- Working memory: empty (first turn)\n", - "- Stored query and response\n", - "\n", - "**Turn 2:** 'What are its prerequisites?'\n", - "- Working memory: 1 exchange (Turn 1)\n", - "- LLM resolved 'its' → Data Structures and Algorithms using history\n", - "- Generated accurate response\n", - "\n", - "**Turn 3:** 'Can I take it next semester?'\n", - "- Working memory: 2 exchanges (Turns 1-2)\n", - "- LLM resolved 'it' → Data Structures and Algorithms using history\n", - "- Maintained conversation continuity\n", - "\n", - "#### ✅ Key Benefits:\n", - "- Natural conversation flow\n", - "- Pronoun reference resolution\n", - "- No need to repeat context\n", - "- Seamless user experience\n", - "\n", - "#### ❌ Without Working Memory:\n", - "- 'What are its prerequisites?' → 'What is its?' Or \"General information without data from the LLM's training\"\n", - "- Each query is isolated\n", - "- User must repeat context every time\n", - "\n", - "### Key Insight: Conversation Context Type\n", - "\n", - "Working memory provides the **Conversation Context** - the third context type from Section 1:\n", - "\n", - "1. **System Context** - Role and instructions (static)\n", - "2. **User Context** - Profile and preferences (dynamic, user-specific)\n", - "3. **Conversation Context** - Working memory (dynamic, session-specific) ← **We just demonstrated this!**\n", - "4. **Retrieved Context** - RAG results (dynamic, query-specific)\n", - "\n", - "Without working memory, we only had 3 context types. Now we have all 4!\n" - ] - }, - { - "cell_type": "markdown", - "id": "f45ac6fbfacb1a8c", - "metadata": {}, - "source": [ - "---\n", - "# 📚 Part 2: Long-term Memory for Context Engineering\n", - "\n", - "## What is Long-term Memory?\n", - "\n", - "Long-term memory enables AI agents to store **persistent knowledge** across sessions—including user preferences, domain facts, business rules, and system configuration. This is crucial for context engineering because it allows agents to:\n", - "\n", - "- **Personalize** interactions by remembering user-specific preferences and history\n", - "- **Apply domain knowledge** consistently (prerequisites, policies, regulations)\n", - "- **Maintain organizational context** (business rules, schedules, procedures)\n", - "- **Search efficiently** using semantic vector search across all knowledge types\n", - "\n", - "Long-term memory is a flexible storage mechanism: user-scoped memories enable personalization (\"Student prefers online courses\"), while application-scoped memories provide consistent behavior for everyone (\"CS401 requires CS201\", \"Registration opens 2 weeks before semester\").\n", - "\n", - "### How It Works\n", - "\n", - "```\n", - "Session 1: User shares preferences → Store in long-term memory\n", - "Session 2: User asks for recommendations → Search memory → Personalized response\n", - "Session 3: User updates preferences → Update memory accordingly\n", - "```\n", - "\n", - "---\n", - "\n", - "## Three Types of Long-term Memory\n", - "\n", - "The Agent Memory Server supports three distinct memory types, each optimized for different kinds of information:\n", - "\n", - "### 1. Semantic Memory - Facts and Knowledge\n", - "\n", - "**Purpose:** Store timeless facts, preferences, and knowledge independent of when they were learned. Can be user-scoped (personalization) or application-scoped (domain knowledge).\n", - "\n", - "**User-Scoped Examples:**\n", - "- \"Student's major is Computer Science\"\n", - "- \"Student prefers online courses\"\n", - "- \"Student wants to graduate in Spring 2026\"\n", - "- \"Student is interested in machine learning\"\n", - "\n", - "**Application-Scoped Examples:**\n", - "- \"CS401 requires CS201 and MATH301 as prerequisites\"\n", - "- \"Online courses have asynchronous discussion forums\"\n", - "- \"Academic advisors are available Monday-Friday 9am-5pm\"\n", - "- \"Maximum file upload size for assignments is 50MB\"\n", - "\n", - "**When to use:** Information that remains true regardless of time context, whether user-specific or universally applicable.\n", - "\n", - "---\n", - "\n", - "### 2. Episodic Memory - Events and Experiences\n", - "\n", - "**Purpose:** Store time-bound events and experiences where sequence matters.\n", - "\n", - "**Examples:**\n", - "- \"Student enrolled in CS101 on 2024-09-15\"\n", - "- \"Student completed CS101 with grade A on 2024-12-10\"\n", - "- \"Student asked about machine learning courses on 2024-09-20\"\n", - "\n", - "**When to use:** Timeline-based information where timing or sequence is important.\n", - "\n", - "---\n", - "\n", - "### 3. Message Memory - Context-Rich Conversations\n", - "\n", - "**Purpose:** Store full conversation snippets where complete context is crucial.\n", - "\n", - "**Examples:**\n", - "- Detailed career planning discussion with nuanced advice\n", - "- Professor's specific guidance about research opportunities\n", - "- Student's explanation of personal learning challenges\n", - "\n", - "**When to use:** When summary would lose important nuance, tone, or exact wording.\n", - "\n", - "**⚠️ Use sparingly** - Message memories are token-expensive!\n", - "\n", - "---\n", - "\n", - "## 🎯 Choosing the Right Memory Type\n", - "\n", - "### Decision Framework\n", - "\n", - "**Ask yourself these questions:**\n", - "\n", - "1. **Can you extract a simple fact?** → Use **Semantic**\n", - "2. **Does timing matter?** → Use **Episodic**\n", - "3. **Is full context crucial?** → Use **Message** (rarely)\n", - "\n", - "**Default strategy: Prefer Semantic** - they're compact, searchable, and efficient.\n", - "\n", - "---\n", - "\n", - "### Quick Reference Table\n", - "\n", - "| Information Type | Memory Type | Example |\n", - "|-----------------|-------------|----------|\n", - "| Preference | Semantic | \"Prefers morning classes\" |\n", - "| Fact | Semantic | \"Major is Computer Science\" |\n", - "| Goal | Semantic | \"Wants to graduate in 2026\" |\n", - "| Event | Episodic | \"Enrolled in CS401 on 2024-09-15\" |\n", - "| Timeline | Episodic | \"Completed CS101, then CS201\" |\n", - "| Complex discussion | Message | [Full career planning conversation] |\n", - "| Nuanced advice | Message | [Professor's detailed guidance] |\n", - "\n", - "---\n", - "\n", - "## Examples: Right vs. Wrong Choices\n", - "\n", - "### Scenario 1: Student States Preference\n", - "\n", - "**User says:** \"I prefer online courses because I work during the day.\"\n", - "\n", - "❌ **Wrong - Message memory (too verbose):**\n", - "```python\n", - "memory = \"Student said: 'I prefer online courses because I work during the day.'\"\n", - "```\n", - "\n", - "✅ **Right - Semantic memories (extracted facts):**\n", - "```python\n", - "memory1 = \"Student prefers online courses\"\n", - "memory2 = \"Student works during the day\"\n", - "```\n", - "\n", - "**Why:** Simple facts don't need verbatim storage.\n", - "\n", - "---\n", - "\n", - "### Scenario 2: Course Completion\n", - "\n", - "**User says:** \"I just finished CS101 last week!\"\n", - "\n", - "❌ **Wrong - Semantic (loses temporal context):**\n", - "```python\n", - "memory = \"Student completed CS101\"\n", - "```\n", - "\n", - "✅ **Right - Episodic (preserves timeline):**\n", - "```python\n", - "memory = \"Student completed CS101 on 2024-10-20\"\n", - "```\n", - "\n", - "**Why:** Timeline matters for prerequisites and future planning.\n", - "\n", - "---\n", - "\n", - "### Scenario 3: Complex Career Advice\n", - "\n", - "**Context:** 20-message discussion about career path including nuanced advice about research vs. industry, application timing, and specific companies to target.\n", - "\n", - "❌ **Wrong - Semantic (loses too much context):**\n", - "```python\n", - "memory = \"Student discussed career planning\"\n", - "```\n", - "\n", - "✅ **Right - Message memory (preserves full context):**\n", - "```python\n", - "memory = [Full conversation thread with all nuance]\n", - "```\n", - "\n", - "**Why:** Details and context are critical; summary would be inadequate.\n", - "\n", - "---\n", - "\n", - "## Key Takeaways\n", - "\n", - "- **Most memories should be semantic** - efficient and searchable\n", - "- **Use episodic when sequence matters** - track progress and timeline\n", - "- **Use message rarely** - only when context cannot be summarized\n", - "- **Effective memory selection improves personalization** and reduces token usage\n", - "\n", - "---\n", - "\n", - "## 🧪 Hands-On: Long-term Memory in Action\n", - "\n", - "Let's put these concepts into practice with code examples..." - ] - }, - { - "cell_type": "markdown", - "id": "2c0e9f58388e9a5a", - "metadata": {}, - "source": [ - "### Setup: Student ID for Long-term Memory\n", - "\n", - "Long-term memories are user-scoped, so we need a student ID.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "546a97b8d4edcce4", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:50.947216Z", - "iopub.status.busy": "2025-12-09T19:44:50.947088Z", - "iopub.status.idle": "2025-12-09T19:44:50.949800Z", - "shell.execute_reply": "2025-12-09T19:44:50.949211Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🎯 Long-term Memory Demo Setup\n", - " Student ID: sarah_chen\n", - " Ready to store and search persistent memories\n" - ] - } - ], - "source": [ - "# Setup for long-term memory demo\n", - "lt_student_id = \"sarah_chen\"\n", - "\n", - "print(\"🎯 Long-term Memory Demo Setup\")\n", - "print(f\" Student ID: {lt_student_id}\")\n", - "print(\" Ready to store and search persistent memories\")" - ] - }, - { - "cell_type": "markdown", - "id": "1064a537054755e4", - "metadata": {}, - "source": [ - "### Step 1: Store Semantic Memories (Facts)\n", - "\n", - "Semantic memories are timeless facts about the student. Let's store several facts about Sarah's preferences and academic status.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "f085eec1e55223e2", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:50.951269Z", - "iopub.status.busy": "2025-12-09T19:44:50.951154Z", - "iopub.status.idle": "2025-12-09T19:44:50.959928Z", - "shell.execute_reply": "2025-12-09T19:44:50.959307Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "📍 STEP 1: Storing Semantic Memories (Facts)\n", - "================================================================================\n", - "\n", - "📝 Storing 6 semantic memories...\n", - "14:44:50 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student is currently taking Linear Algebra\n", - "\n", - "✅ Stored 6 semantic memories\n", - " Memory type: semantic (timeless facts)\n", - " Topics: preferences, academic_info\n" - ] - } - ], - "source": [ - "print(\"=\" * 80)\n", - "print(\"📍 STEP 1: Storing Semantic Memories (Facts)\")\n", - "print(\"=\" * 80)\n", - "\n", - "# Define semantic memories (timeless facts)\n", - "semantic_memories = [\n", - " \"Student prefers online courses over in-person classes\",\n", - " \"Student's major is Computer Science with focus on AI/ML\",\n", - " \"Student wants to graduate in Spring 2026\",\n", - " \"Student prefers morning classes, no classes on Fridays\",\n", - " \"Student has completed Introduction to Programming and Data Structures\",\n", - " \"Student is currently taking Linear Algebra\",\n", - "]\n", - "print(f\"\\n📝 Storing {len(semantic_memories)} semantic memories...\")\n", - "\n", - "# Store each semantic memory\n", - "for memory_text in semantic_memories:\n", - " memory_record = ClientMemoryRecord(\n", - " text=memory_text,\n", - " user_id=lt_student_id,\n", - " memory_type=\"semantic\",\n", - " topics=[\"preferences\", \"academic_info\"],\n", - " )\n", - "await memory_client.create_long_term_memory([memory_record])\n", - "print(f\" ✅ {memory_text}\")\n", - "\n", - "print(f\"\\n✅ Stored {len(semantic_memories)} semantic memories\")\n", - "print(\" Memory type: semantic (timeless facts)\")\n", - "print(\" Topics: preferences, academic_info\")" - ] - }, - { - "cell_type": "markdown", - "id": "533e63cbfc1cb44f", - "metadata": {}, - "source": [ - "### What We Just Did: Semantic Memories\n", - "\n", - "**Stored 6 semantic memories:**\n", - "- Student preferences (online courses, morning classes)\n", - "- Academic information (major, graduation date)\n", - "- Course history (completed, current)\n", - "\n", - "**Why semantic?**\n", - "- These are timeless facts\n", - "- No specific date/time context needed\n", - "- Compact and efficient\n", - "\n", - "**How they're stored:**\n", - "- Vector-indexed for semantic search\n", - "- Tagged with topics for organization\n", - "- Automatically deduplicated\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "ec4e3f434ed5da5f", - "metadata": {}, - "source": [ - "### Step 2: Store Episodic Memories (Events)\n", - "\n", - "Episodic memories are time-bound events. Let's store some events from Sarah's academic timeline.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "b6b01e52eef818ad", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:50.962355Z", - "iopub.status.busy": "2025-12-09T19:44:50.962105Z", - "iopub.status.idle": "2025-12-09T19:44:50.975556Z", - "shell.execute_reply": "2025-12-09T19:44:50.974773Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "================================================================================\n", - "📍 STEP 2: Storing Episodic Memories (Events)\n", - "================================================================================\n", - "\n", - "📝 Storing 3 episodic memories...\n", - "14:44:50 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student enrolled in Introduction to Programming on 2024-09-01\n", - "14:44:50 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student completed Introduction to Programming with grade A on 2024-12-15\n", - "14:44:50 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student asked about machine learning courses on 2024-09-20\n", - "\n", - "✅ Stored 3 episodic memories\n", - " Memory type: episodic (time-bound events)\n", - " Topics: enrollment, courses\n" - ] - } - ], - "source": [ - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"📍 STEP 2: Storing Episodic Memories (Events)\")\n", - "print(\"=\" * 80)\n", - "\n", - "# Define episodic memories (time-bound events)\n", - "episodic_memories = [\n", - " \"Student enrolled in Introduction to Programming on 2024-09-01\",\n", - " \"Student completed Introduction to Programming with grade A on 2024-12-15\",\n", - " \"Student asked about machine learning courses on 2024-09-20\",\n", - "]\n", - "\n", - "print(f\"\\n📝 Storing {len(episodic_memories)} episodic memories...\")\n", - "\n", - "# Store each episodic memory\n", - "for memory_text in episodic_memories:\n", - " memory_record = ClientMemoryRecord(\n", - " text=memory_text,\n", - " user_id=lt_student_id,\n", - " memory_type=\"episodic\",\n", - " topics=[\"enrollment\", \"courses\"],\n", - " )\n", - " await memory_client.create_long_term_memory([memory_record])\n", - " print(f\" ✅ {memory_text}\")\n", - "\n", - "print(f\"\\n✅ Stored {len(episodic_memories)} episodic memories\")\n", - "print(\" Memory type: episodic (time-bound events)\")\n", - "print(\" Topics: enrollment, courses\")" - ] - }, - { - "cell_type": "markdown", - "id": "76ea4f9c84d09a7a", - "metadata": {}, - "source": [ - "### What We Just Did: Episodic Memories\n", - "\n", - "**Stored 3 episodic memories:**\n", - "- Enrollment event (Introduction to Programming on 2024-09-01)\n", - "- Completion event (Introduction to Programming with grade A on 2024-12-15)\n", - "- Interaction event (asked about ML courses on 2024-09-20)\n", - "\n", - "**Why episodic?**\n", - "- These are time-bound events\n", - "- Timing and sequence matter\n", - "- Captures academic timeline\n", - "\n", - "**Difference from semantic:**\n", - "- Semantic: \"Student has completed Introduction to Programming\" (timeless fact)\n", - "- Episodic: \"Student completed Introduction to Programming with grade A on 2024-12-15\" (specific event)\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "83186a67c7e672a", - "metadata": {}, - "source": [ - "### Step 3: Search Long-term Memory\n", - "\n", - "Now let's search our long-term memories using natural language queries. The system will use semantic search to find relevant memories.\n" - ] - }, - { - "cell_type": "markdown", - "id": "fb2b0dada127fa7d", - "metadata": {}, - "source": [ - "#### Query 1: What does the student prefer?\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "2c3238ee46c77879", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:50.977757Z", - "iopub.status.busy": "2025-12-09T19:44:50.977595Z", - "iopub.status.idle": "2025-12-09T19:44:51.165000Z", - "shell.execute_reply": "2025-12-09T19:44:51.164101Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "================================================================================\n", - "📍 STEP 3: Searching Long-term Memory\n", - "================================================================================\n", - "\n", - "🔍 Query: 'What does the student prefer?'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:51 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 📚 Found 3 relevant memories:\n", - " 1. The student prefers online courses over in-person classes.\n", - " 2. Student prefers morning classes\n", - " 3. Student prefers morning classes, no classes on Fridays\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"📍 STEP 3: Searching Long-term Memory\")\n", - " print(\"=\" * 80)\n", - "\n", - " search_query_1 = \"What does the student prefer?\"\n", - " print(f\"\\n🔍 Query: '{search_query_1}'\")\n", - "\n", - " search_results_1 = await memory_client.search_long_term_memory(\n", - " text=search_query_1, user_id=UserId(eq=lt_student_id), limit=3\n", - " )\n", - "\n", - " if search_results_1.memories:\n", - " print(f\" 📚 Found {len(search_results_1.memories)} relevant memories:\")\n", - " for i, memory in enumerate(search_results_1.memories[:3], 1):\n", - " print(f\" {i}. {memory.text}\")\n", - " else:\n", - " print(\" ⚠️ No memories found\")" - ] - }, - { - "cell_type": "markdown", - "id": "7325c38bbad26d5d", - "metadata": {}, - "source": [ - "#### Query 2: What courses has the student completed?\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "15bc0d7b3702d072", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:51.167163Z", - "iopub.status.busy": "2025-12-09T19:44:51.166998Z", - "iopub.status.idle": "2025-12-09T19:44:51.865931Z", - "shell.execute_reply": "2025-12-09T19:44:51.865224Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🔍 Query: 'What courses has the student completed?'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:51 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 📚 Found 5 relevant memories:\n", - " 1. Student has completed Introduction to Programming and Data Structures\n", - " 2. Student completed Introduction to Programming with grade A on 2024-12-15\n", - " 3. Student's major is Computer Science\n", - " 4. Student is currently taking Linear Algebra\n", - " 5. Student asked about machine learning courses on 2024-09-20\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " search_query_2 = \"What courses has the student completed?\"\n", - " print(f\"\\n🔍 Query: '{search_query_2}'\")\n", - "\n", - " search_results_2 = await memory_client.search_long_term_memory(\n", - " text=search_query_2, user_id=UserId(eq=lt_student_id), limit=5\n", - " )\n", - "\n", - " if search_results_2.memories:\n", - " print(f\" 📚 Found {len(search_results_2.memories)} relevant memories:\")\n", - " for i, memory in enumerate(search_results_2.memories[:5], 1):\n", - " print(f\" {i}. {memory.text}\")\n", - " else:\n", - " print(\" ⚠️ No memories found\")" - ] - }, - { - "cell_type": "markdown", - "id": "385fae19b2652477", - "metadata": {}, - "source": [ - "#### Query 3: What is the student's major?\n" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "d77f0e7fd8b40b82", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:51.867979Z", - "iopub.status.busy": "2025-12-09T19:44:51.867810Z", - "iopub.status.idle": "2025-12-09T19:44:52.545610Z", - "shell.execute_reply": "2025-12-09T19:44:52.544568Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🔍 Query: 'What is the student's major?'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:52 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 📚 Found 3 relevant memories:\n", - " 1. Student's major is Computer Science\n", - " 2. Student's major is Computer Science with focus on AI/ML\n", - " 3. Student wants to graduate in Spring 2026\n", - "\n", - "================================================================================\n", - "✅ DEMO COMPLETE: Long-term memory enables persistent knowledge!\n", - "================================================================================\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " search_query_3 = \"What is the student's major?\"\n", - " print(f\"\\n🔍 Query: '{search_query_3}'\")\n", - "\n", - " search_results_3 = await memory_client.search_long_term_memory(\n", - " text=search_query_3, user_id=UserId(eq=lt_student_id), limit=3\n", - " )\n", - "\n", - " if search_results_3.memories:\n", - " print(f\" 📚 Found {len(search_results_3.memories)} relevant memories:\")\n", - " for i, memory in enumerate(search_results_3.memories[:3], 1):\n", - " print(f\" {i}. {memory.text}\")\n", - " else:\n", - " print(\" ⚠️ No memories found\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"✅ DEMO COMPLETE: Long-term memory enables persistent knowledge!\")\n", - " print(\"=\" * 80)\n", - "else:\n", - " print(\"⚠️ Memory Server not available. Skipping demo.\")" - ] - }, - { - "cell_type": "markdown", - "id": "df79f16661490755", - "metadata": {}, - "source": [ - "### Long-term Memory Demo Summary\n", - "\n", - "Let's review what we demonstrated with long-term memory.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "a54dd4fd398bfb94", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:52.549004Z", - "iopub.status.busy": "2025-12-09T19:44:52.548728Z", - "iopub.status.idle": "2025-12-09T19:44:52.553399Z", - "shell.execute_reply": "2025-12-09T19:44:52.552573Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🎯 LONG-TERM MEMORY DEMO SUMMARY\n", - "================================================================================\n", - "\n", - "📊 What We Did:\n", - " Step 1: Stored 6 semantic memories (facts)\n", - " → Student preferences, major, graduation date\n", - " → Tagged with topics: preferences, academic_info\n", - "\n", - " Step 2: Stored 3 episodic memories (events)\n", - " → Enrollment, completion, interaction events\n", - " → Tagged with topics: enrollment, courses\n", - "\n", - " Step 3: Searched long-term memory\n", - " → Used natural language queries\n", - " → Semantic search found relevant memories\n", - " → No exact keyword matching needed\n", - "\n", - "✅ Key Benefits:\n", - " • Persistent knowledge across sessions\n", - " • Semantic search (not keyword matching)\n", - " • Automatic deduplication\n", - " • Topic-based organization\n", - "\n", - "💡 Key Insight:\n", - " Long-term memory enables personalization and knowledge\n", - " accumulation across sessions. It's the foundation for\n", - " building agents that remember and learn from users.\n", - "================================================================================\n" - ] - } - ], - "source": [ - "print(\"=\" * 80)\n", - "print(\"🎯 LONG-TERM MEMORY DEMO SUMMARY\")\n", - "print(\"=\" * 80)\n", - "print(\"\\n📊 What We Did:\")\n", - "print(\" Step 1: Stored 6 semantic memories (facts)\")\n", - "print(\" → Student preferences, major, graduation date\")\n", - "print(\" → Tagged with topics: preferences, academic_info\")\n", - "print(\"\\n Step 2: Stored 3 episodic memories (events)\")\n", - "print(\" → Enrollment, completion, interaction events\")\n", - "print(\" → Tagged with topics: enrollment, courses\")\n", - "print(\"\\n Step 3: Searched long-term memory\")\n", - "print(\" → Used natural language queries\")\n", - "print(\" → Semantic search found relevant memories\")\n", - "print(\" → No exact keyword matching needed\")\n", - "print(\"\\n✅ Key Benefits:\")\n", - "print(\" • Persistent knowledge across sessions\")\n", - "print(\" • Semantic search (not keyword matching)\")\n", - "print(\" • Automatic deduplication\")\n", - "print(\" • Topic-based organization\")\n", - "print(\"\\n💡 Key Insight:\")\n", - "print(\" Long-term memory enables personalization and knowledge\")\n", - "print(\" accumulation across sessions. It's the foundation for\")\n", - "print(\" building agents that remember and learn from users.\")\n", - "print(\"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "93e71eba49c4186c", - "metadata": {}, - "source": [ - "### Key Insight: User Context Type\n", - "\n", - "Long-term memory provides part of the **User Context** - the second context type from Section 1:\n", - "\n", - "1. **System Context** - Role and instructions (static)\n", - "2. **User Context** - Profile + long-term memories (dynamic, user-specific) ← **Long-term memories contribute here!**\n", - "3. **Conversation Context** - Working memory (dynamic, session-specific)\n", - "4. **Retrieved Context** - RAG results (dynamic, query-specific)\n", - "\n", - "Long-term memories enhance User Context by adding persistent knowledge about the user's preferences, history, and goals.\n", - "\n", - "---\n", - "\n", - "## 🏷️ Advanced: Topics and Filtering\n", - "\n", - "Topics help organize and filter memories. Let's explore how to use them effectively.\n" - ] - }, - { - "cell_type": "markdown", - "id": "3257eef2f0a46b70", - "metadata": {}, - "source": [ - "### Step 1: Store memories with topics\n" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "a5195f3f351cb42c", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:52.555485Z", - "iopub.status.busy": "2025-12-09T19:44:52.555319Z", - "iopub.status.idle": "2025-12-09T19:44:52.570445Z", - "shell.execute_reply": "2025-12-09T19:44:52.569879Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🏷️ TOPICS AND FILTERING DEMO\n", - "================================================================================\n", - "\n", - "📍 Storing Memories with Topics\n", - "--------------------------------------------------------------------------------\n", - "14:44:52 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student prefers online courses\n", - " Topics: preferences, course_format\n", - "14:44:52 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student's major is Computer Science\n", - " Topics: academic_info, major\n", - "14:44:52 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student wants to graduate in Spring 2026\n", - " Topics: goals, graduation\n", - "14:44:52 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Student prefers morning classes\n", - " Topics: preferences, schedule\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " topics_student_id = \"sarah_chen\"\n", - "\n", - " print(\"=\" * 80)\n", - " print(\"🏷️ TOPICS AND FILTERING DEMO\")\n", - " print(\"=\" * 80)\n", - "\n", - " print(\"\\n📍 Storing Memories with Topics\")\n", - " print(\"-\" * 80)\n", - "\n", - " # Define memories with their topics\n", - " memories_with_topics = [\n", - " (\"Student prefers online courses\", [\"preferences\", \"course_format\"]),\n", - " (\"Student's major is Computer Science\", [\"academic_info\", \"major\"]),\n", - " (\"Student wants to graduate in Spring 2026\", [\"goals\", \"graduation\"]),\n", - " (\"Student prefers morning classes\", [\"preferences\", \"schedule\"]),\n", - " ]\n", - "\n", - " # Store each memory\n", - " for memory_text, topics in memories_with_topics:\n", - " memory_record = ClientMemoryRecord(\n", - " text=memory_text,\n", - " user_id=topics_student_id,\n", - " memory_type=\"semantic\",\n", - " topics=topics,\n", - " )\n", - " await memory_client.create_long_term_memory([memory_record])\n", - " print(f\" ✅ {memory_text}\")\n", - " print(f\" Topics: {', '.join(topics)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "1795b81a16b4d63b", - "metadata": {}, - "source": [ - "### Step 2: Filter memories by type\n" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "fe9d3d303cb2f8fb", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:52.572064Z", - "iopub.status.busy": "2025-12-09T19:44:52.571937Z", - "iopub.status.idle": "2025-12-09T19:44:53.153947Z", - "shell.execute_reply": "2025-12-09T19:44:53.153181Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "📍 Filtering by Memory Type: Semantic\n", - "--------------------------------------------------------------------------------\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:53 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Found 9 semantic memories:\n", - " 1. The student prefers online courses over in-person classes.\n", - " Topics: preferences, course_format, academic_info\n", - " 2. Student is currently taking Linear Algebra\n", - " Topics: preferences, academic_info\n", - " 3. Student's major is Computer Science\n", - " Topics: academic_info, major\n", - " 4. Student prefers morning classes\n", - " Topics: preferences, schedule\n", - " 5. Student is interested in machine learning and AI\n", - " Topics: interests, AI\n", - "\n", - "================================================================================\n", - "✅ Topics enable organized, filterable memory management!\n", - "================================================================================\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " print(\"\\n📍 Filtering by Memory Type: Semantic\")\n", - " print(\"-\" * 80)\n", - "\n", - " from agent_memory_client.filters import MemoryType, UserId\n", - "\n", - " # Search for all semantic memories\n", - " results = await memory_client.search_long_term_memory(\n", - " text=\"\", # Empty query returns all\n", - " user_id=UserId(eq=topics_student_id),\n", - " memory_type=MemoryType(eq=\"semantic\"),\n", - " limit=10,\n", - " )\n", - "\n", - " print(f\" Found {len(results.memories)} semantic memories:\")\n", - " for i, memory in enumerate(results.memories[:5], 1):\n", - " topics_str = \", \".join(memory.topics) if memory.topics else \"none\"\n", - " print(f\" {i}. {memory.text}\")\n", - " print(f\" Topics: {topics_str}\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"✅ Topics enable organized, filterable memory management!\")\n", - " print(\"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "b01d75fff675a3c0", - "metadata": {}, - "source": [ - "### 🎯 Why Topics Matter\n", - "\n", - "**Organization:**\n", - "- Group related memories together\n", - "- Easy to find memories by category\n", - "\n", - "**Filtering:**\n", - "- Search within specific topics\n", - "- Filter by memory type (semantic, episodic, message)\n", - "\n", - "**Best Practices:**\n", - "- Use consistent topic names\n", - "- Keep topics broad enough to be useful\n", - "- Common topics: `preferences`, `academic_info`, `goals`, `schedule`, `courses`\n", - "\n", - "---\n", - "\n", - "## 🔄 Cross-Session Memory Persistence\n", - "\n", - "Let's verify that memories persist across sessions.\n" - ] - }, - { - "cell_type": "markdown", - "id": "aa1f3d6a0081ec90", - "metadata": {}, - "source": [ - "### Step 1: Session 1 - Store memories\n" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "e6a79bf4d4bad524", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:53.156508Z", - "iopub.status.busy": "2025-12-09T19:44:53.156303Z", - "iopub.status.idle": "2025-12-09T19:44:53.163159Z", - "shell.execute_reply": "2025-12-09T19:44:53.162383Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🔄 CROSS-SESSION MEMORY PERSISTENCE DEMO\n", - "================================================================================\n", - "\n", - "📍 SESSION 1: Storing Memories\n", - "--------------------------------------------------------------------------------\n", - "14:44:53 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Stored: Student is interested in machine learning and AI\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " cross_session_student_id = \"sarah_chen\"\n", - "\n", - " print(\"=\" * 80)\n", - " print(\"🔄 CROSS-SESSION MEMORY PERSISTENCE DEMO\")\n", - " print(\"=\" * 80)\n", - "\n", - " print(\"\\n📍 SESSION 1: Storing Memories\")\n", - " print(\"-\" * 80)\n", - "\n", - " memory_record = ClientMemoryRecord(\n", - " text=\"Student is interested in machine learning and AI\",\n", - " user_id=cross_session_student_id,\n", - " memory_type=\"semantic\",\n", - " topics=[\"interests\", \"AI\"],\n", - " )\n", - " await memory_client.create_long_term_memory([memory_record])\n", - " print(\" ✅ Stored: Student is interested in machine learning and AI\")" - ] - }, - { - "cell_type": "markdown", - "id": "4566b9b23eb6f60a", - "metadata": {}, - "source": [ - "### Step 2: Session 2 - Create new client and retrieve memories\n", - "\n", - "Simulate a new session by creating a new memory client.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "327c07072ee9f573", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:53.165003Z", - "iopub.status.busy": "2025-12-09T19:44:53.164861Z", - "iopub.status.idle": "2025-12-09T19:44:53.358771Z", - "shell.execute_reply": "2025-12-09T19:44:53.358026Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "📍 SESSION 2: New Session, Same Student\n", - "--------------------------------------------------------------------------------\n", - " 🔄 New session started for the same student\n", - "\n", - " 🔍 Searching: 'What are the student's interests?'\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:53 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " ✅ Memories accessible from new session:\n", - " 1. Student is interested in machine learning and AI\n", - " 2. Student's major is Computer Science\n", - " 3. Student's major is Computer Science with focus on AI/ML\n", - "\n", - "================================================================================\n", - "✅ Long-term memories persist across sessions!\n", - "================================================================================\n" - ] - } - ], - "source": [ - "# Search for memories from the new session\n", - "from agent_memory_client.filters import UserId\n", - "\n", - "if MEMORY_SERVER_AVAILABLE:\n", - " print(\"\\n📍 SESSION 2: New Session, Same Student\")\n", - " print(\"-\" * 80)\n", - "\n", - " # Create a new memory client (simulating a new session)\n", - " new_session_config = MemoryClientConfig(\n", - " base_url=os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8000\"),\n", - " default_namespace=\"redis_university\",\n", - " )\n", - " new_session_client = MemoryAPIClient(config=new_session_config)\n", - "\n", - " print(\" 🔄 New session started for the same student\")\n", - "\n", - " print(\"\\n 🔍 Searching: 'What are the student's interests?'\")\n", - " cross_session_results = await new_session_client.search_long_term_memory(\n", - " text=\"What are the student's interests?\",\n", - " user_id=UserId(eq=cross_session_student_id),\n", - " limit=3,\n", - " )\n", - "\n", - " if cross_session_results.memories:\n", - " print(f\"\\n ✅ Memories accessible from new session:\")\n", - " for i, memory in enumerate(cross_session_results.memories[:3], 1):\n", - " print(f\" {i}. {memory.text}\")\n", - " else:\n", - " print(\" ⚠️ No memories found\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"✅ Long-term memories persist across sessions!\")\n", - " print(\"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "973cb3f4b2576f9a", - "metadata": {}, - "source": [ - "### 🎯 Cross-Session Persistence\n", - "\n", - "**What We Demonstrated:**\n", - "- **Session 1:** Stored memories about student interests\n", - "- **Session 2:** Created new client (simulating new session)\n", - "- **Result:** Memories from Session 1 are accessible in Session 2\n", - "\n", - "**Why This Matters:**\n", - "- Users don't have to repeat themselves\n", - "- Personalization works across days, weeks, months\n", - "- Knowledge accumulates over time\n", - "\n", - "**Contrast with Working Memory:**\n", - "- Working memory: Session-scoped (persists within the session, like ChatGPT conversations)\n", - "- Long-term memory: User-scoped (persists across all sessions indefinitely)\n", - "\n", - "---\n", - "\n", - "## 🔗 What's Next: Memory-Enhanced RAG and Agents\n", - "\n", - "You've learned the fundamentals of memory architecture! Now it's time to put it all together.\n", - "\n", - "### **Next Notebook: `02_combining_memory_with_retrieved_context.ipynb`**\n", - "\n", - "In the next notebook, you'll:\n", - "\n", - "1. **Build** a complete memory-enhanced RAG system\n", - " - Integrate working memory + long-term memory + RAG\n", - " - Combine all four context types\n", - " - Show clear before/after comparisons\n", - "\n", - "2. **Convert** to LangGraph agent (Part 2, separate notebook)\n", - " - Add state management\n", - " - Improve control flow\n", - " - Prepare for Section 4 (tools and advanced capabilities)\n", - "\n", - "**Why Continue?**\n", - "- See memory in action with real conversations\n", - "- Learn how to build production-ready agents\n", - "- Prepare for Section 4 (adding tools like enrollment, scheduling)\n", - "\n", - "**📚 Continue to:** `02_combining_memory_with_retrieved_context.ipynb`\n", - "\n", - "## ⏰ Memory Lifecycle & Persistence\n", - "\n", - "Understanding how working memory and long-term memory persist is crucial for building reliable systems.\n", - "\n", - "### **Working Memory Persistence**\n", - "\n", - "**How it works:** Just like ChatGPT or Claude conversations\n", - "\n", - "**What this means:**\n", - "- When you return to a conversation, the working memory is still there\n", - "- The conversation doesn't disappear when you close the tab\n", - "- Full conversation history remains accessible within the session\n", - "- **Backend optimization:** TTL for storage management (not user-facing)\n", - "\n", - "**User Experience:**\n", - "\n", - "```\n", - "Day 1, 10:00 AM - User starts conversation\n", - "Day 1, 10:25 AM - User closes browser\n", - " ↓\n", - "[User returns later]\n", - " ↓\n", - "Day 1, 3:00 PM - User reopens conversation\n", - " → Working memory still there ✅\n", - " → Conversation continues naturally ✅\n", - "```\n", - "\n", - "**The Real Challenge: Context Window Limits**\n", - "\n", - "Working memory doesn't \"expire\" - but it can grow too large:\n", - "- LLMs have context window limits (e.g., 128K tokens for GPT-4)\n", - "- Long conversations eventually exceed these limits\n", - "- **Solution:** Compression strategies (covered in Notebook 03)\n", - "\n", - "### **Long-term Memory Persistence**\n", - "\n", - "**Lifetime:** Indefinite (until manually deleted)\n", - "\n", - "**What this means:**\n", - "- Long-term memories never expire automatically\n", - "- Accessible across all sessions, forever\n", - "- Must be explicitly deleted if no longer needed\n", - "\n", - "### **Why This Design?**\n", - "\n", - "**Working Memory (Session-Persistent):**\n", - "- Stores full conversation history for the session\n", - "- Persists when you return to the conversation (like ChatGPT)\n", - "- **Challenge:** Can grow too large for context window\n", - "- **Solution:** Compression strategies (Notebook 03)\n", - "\n", - "**Long-term Memory (Cross-Session Persistent):**\n", - "- Important facts extracted from conversations\n", - "- User preferences don't expire\n", - "- Knowledge accumulates over time\n", - "- Enables true personalization across sessions\n", - "\n", - "### **Important Implications**\n", - "\n", - "**1. Automatic Extraction to Long-term Memory**\n", - "\n", - "Important facts from conversations are automatically extracted to long-term memory.\n", - "\n", - "**Good news:** Agent Memory Server does this automatically in the background!\n", - "\n", - "**2. Long-term Memories are Permanent**\n", - "\n", - "Once stored, long-term memories persist indefinitely. Be thoughtful about what you store.\n", - "\n", - "**3. Cross-Session Behavior**\n", - "\n", - "```\n", - "Session 1 (Day 1):\n", - "- User: \"I'm interested in machine learning\"\n", - "- Working memory: Stores full conversation\n", - "- Long-term memory: Extracts \"Student interested in machine learning\"\n", - "\n", - "[User starts a NEW session on Day 3]\n", - "\n", - "Session 2 (Day 3):\n", - "- Working memory: NEW session, starts empty ✅\n", - "- Long-term memory: Still has \"Student interested in machine learning\" ✅\n", - "- Agent retrieves long-term memory for personalization ✅\n", - "- Agent makes relevant recommendations ✅\n", - "```\n", - "\n", - "**Key Distinction:**\n", - "- **Same session:** Working memory persists (like returning to a ChatGPT conversation)\n", - "- **New session:** Working memory starts fresh, but long-term memories are available\n", - "\n", - "### **Practical Multi-Day Conversation Example**\n" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "4f59dd2bae29f763", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:44:53.361364Z", - "iopub.status.busy": "2025-12-09T19:44:53.361170Z", - "iopub.status.idle": "2025-12-09T19:44:53.690517Z", - "shell.execute_reply": "2025-12-09T19:44:53.689500Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "⏰ MULTI-DAY CONVERSATION SIMULATION\n", - "================================================================================\n", - "\n", - "📅 DAY 1: Initial Conversation\n", - "--------------------------------------------------------------------------------\n", - "\n", - "Text: Student is preparing for a career in AI research\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:53 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/ \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ✅ Stored in long-term memory: Career goal (AI research)\n", - " 💬 Working memory: Active for session_day1\n", - " 📝 Note: If user returns to THIS session, working memory persists\n", - "\n", - "📅 DAY 3: NEW Conversation (different session)\n", - "--------------------------------------------------------------------------------\n", - " 🆕 Working memory: NEW session, starts empty\n", - " ✅ Long-term memory: Still available across all sessions\n", - "\n", - "Text: What are the student's career goals?\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:44:53 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " 🔍 Retrieved from long-term memory:\n", - " • Student wants to graduate in Spring 2026\n", - " • Student's major is Computer Science\n", - " • Student's major is Computer Science with focus on AI/ML\n", - "\n", - " ✅ Agent can still personalize recommendations!\n", - "\n", - "================================================================================\n", - "✅ Long-term memories persist across sessions, working memory is session-scoped\n", - "================================================================================\n" - ] - } - ], - "source": [ - "# Multi-Day Conversation Simulation\n", - "from agent_memory_client.filters import UserId\n", - "\n", - "\n", - "async def multi_day_simulation():\n", - " \"\"\"Simulate conversations across multiple days\"\"\"\n", - "\n", - " student_id = \"sarah_chen\"\n", - "\n", - " print(\"=\" * 80)\n", - " print(\"⏰ MULTI-DAY CONVERSATION SIMULATION\")\n", - " print(\"=\" * 80)\n", - "\n", - " # Day 1: Initial conversation\n", - " print(\"\\n📅 DAY 1: Initial Conversation\")\n", - " print(\"-\" * 80)\n", - "\n", - " session_1 = f\"session_{student_id}_day1\"\n", - " text = \"Student is preparing for a career in AI research\"\n", - " print(f\"\\nText: {text}\\n\")\n", - " # Store a fact in long-term memory\n", - " memory_record = ClientMemoryRecord(\n", - " text=text,\n", - " user_id=student_id,\n", - " memory_type=\"semantic\",\n", - " topics=[\"career\", \"goals\"],\n", - " )\n", - " await memory_client.create_long_term_memory([memory_record])\n", - " print(\" ✅ Stored in long-term memory: Career goal (AI research)\")\n", - "\n", - " # Simulate working memory (would normally be conversation)\n", - " print(\" 💬 Working memory: Active for session_day1\")\n", - " print(\" 📝 Note: If user returns to THIS session, working memory persists\")\n", - "\n", - " # Day 3: NEW conversation (different session)\n", - " print(\"\\n📅 DAY 3: NEW Conversation (different session)\")\n", - " print(\"-\" * 80)\n", - "\n", - " session_2 = f\"session_{student_id}_day3\"\n", - "\n", - " print(\" 🆕 Working memory: NEW session, starts empty\")\n", - " print(\" ✅ Long-term memory: Still available across all sessions\")\n", - " text2 = \"What are the student's career goals?\"\n", - " print(f\"\\nText: {text2}\\n\")\n", - "\n", - " # Search long-term memory\n", - " results = await memory_client.search_long_term_memory(\n", - " text=text2, user_id=UserId(eq=student_id), limit=3\n", - " )\n", - "\n", - " if results.memories:\n", - " print(\"\\n 🔍 Retrieved from long-term memory:\")\n", - " for memory in results.memories[:3]:\n", - " print(f\" • {memory.text}\")\n", - " print(\"\\n ✅ Agent can still personalize recommendations!\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\n", - " \"✅ Long-term memories persist across sessions, working memory is session-scoped\"\n", - " )\n", - " print(\"=\" * 80)\n", - "\n", - "\n", - "# Run the simulation\n", - "await multi_day_simulation()" - ] - }, - { - "cell_type": "markdown", - "id": "5313340c15849727", - "metadata": {}, - "source": [ - "### 🎯 Memory Lifecycle Best Practices\n", - "\n", - "**1. Trust Automatic Extraction**\n", - "- Agent Memory Server automatically extracts important facts\n", - "- Don't manually store everything in long-term memory\n", - "- Let the system decide what's important\n", - "\n", - "**2. Use Appropriate Memory Types**\n", - "- Working memory: Current conversation only\n", - "- Long-term memory: Facts that should persist\n", - "\n", - "**3. Monitor Memory Growth**\n", - "- Long-term memories accumulate over time\n", - "- Implement cleanup for outdated information\n", - "- Consider archiving old memories\n", - "\n", - "**4. Understand Session Management**\n", - "- Working memory persists within a session\n", - "- New sessions start with empty working memory\n", - "- Important facts should be in long-term memory for cross-session access\n", - "- Consider providing ways to resume or load previous session context\n", - "\n", - "**5. Plan for Context Window Limits**\n", - "- Working memory doesn't expire, but can grow too large\n", - "- LLMs have context window limits (e.g., 128K tokens)\n", - "- Use compression strategies when conversations get long (covered in Notebook 03)\n", - "- Monitor token usage in long conversations\n", - "\n", - "**6. Test Cross-Session Behavior**\n", - "- Verify long-term memories are accessible across sessions\n", - "- Test both same-session returns and new-session starts\n", - "- Ensure personalization works in both scenarios\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "5f1c090ec7126ac4", - "metadata": {}, - "source": [ - "## 🧠 Memory Extraction Strategies\n", - "\n", - "The Agent Memory Server automatically extracts important information from conversations and stores it in long-term memory. Understanding **how** this extraction works helps you choose the right strategy for your use case.\n" - ] - }, - { - "cell_type": "markdown", - "id": "dab736ee516b94e", - "metadata": {}, - "source": [ - "### How Memory Extraction Works\n", - "\n", - "**Key Distinction:**\n", - "- **Working Memory:** Stores raw conversation messages (user/assistant exchanges)\n", - "- **Long-term Memory:** Stores extracted facts, summaries, or preferences\n", - "\n", - "**The Question:** When promoting information from working memory to long-term memory, should we extract:\n", - "- Individual discrete facts? (\"User prefers online courses\")\n", - "- A summary of the conversation? (\"User discussed course preferences...\")\n", - "- User preferences specifically? (\"User prefers email notifications\")\n", - "- Custom domain-specific information?\n", - "\n", - "This is where **memory extraction strategies** come in.\n" - ] - }, - { - "cell_type": "markdown", - "id": "2dee3b159eb86d90", - "metadata": {}, - "source": [ - "### Available Strategies\n", - "\n", - "The Agent Memory Server supports four memory extraction strategies that determine how memories are created:\n", - "\n", - "#### **1. Discrete Strategy (Default)** ✅\n", - "\n", - "**Purpose:** Extract individual facts and preferences from conversations\n", - "\n", - "**Best For:** General-purpose memory extraction, factual information, user preferences\n", - "\n", - "**Example Input (Conversation):**\n", - "```\n", - "User: \"I'm a Computer Science major interested in machine learning. I prefer online courses.\"\n", - "```\n", - "\n", - "**Example Output (Long-term Memories):**\n", - "```json\n", - "[\n", - " {\n", - " \"type\": \"semantic\",\n", - " \"text\": \"User's major is Computer Science\",\n", - " \"topics\": [\"education\", \"major\"],\n", - " \"entities\": [\"Computer Science\"]\n", - " },\n", - " {\n", - " \"type\": \"semantic\",\n", - " \"text\": \"User interested in machine learning\",\n", - " \"topics\": [\"interests\", \"technology\"],\n", - " \"entities\": [\"machine learning\"]\n", - " },\n", - " {\n", - " \"type\": \"semantic\",\n", - " \"text\": \"User prefers online courses\",\n", - " \"topics\": [\"preferences\", \"learning\"],\n", - " \"entities\": [\"online courses\"]\n", - " }\n", - "]\n", - "```\n", - "\n", - "**When to Use:**\n", - "- ✅ Most agent interactions (default choice)\n", - "- ✅ When you want searchable individual facts\n", - "- ✅ When facts should be independently retrievable\n", - "- ✅ Building knowledge graphs or fact databases\n", - "\n", - "---\n", - "\n", - "#### **2. Summary Strategy**\n", - "\n", - "**Purpose:** Create concise summaries of entire conversations instead of extracting discrete facts\n", - "\n", - "**Best For:** Long conversations, meeting notes, comprehensive context preservation\n", - "\n", - "**Example Input (Same Conversation):**\n", - "```\n", - "User: \"I'm a Computer Science major interested in machine learning. I prefer online courses.\"\n", - "```\n", - "\n", - "**Example Output (Long-term Memory):**\n", - "```json\n", - "{\n", - " \"type\": \"semantic\",\n", - " \"text\": \"User is a Computer Science major with interest in machine learning, preferring online course formats for their studies.\",\n", - " \"topics\": [\"education\", \"preferences\", \"technology\"],\n", - " \"entities\": [\"Computer Science\", \"machine learning\", \"online courses\"]\n", - "}\n", - "```\n", - "\n", - "**When to Use:**\n", - "- ✅ Long consultations or advising sessions\n", - "- ✅ Meeting notes or session summaries\n", - "- ✅ When context of entire conversation matters\n", - "- ✅ Reducing storage while preserving conversational context\n", - "\n", - "---\n", - "\n", - "#### **3. Preferences Strategy**\n", - "\n", - "**Purpose:** Focus specifically on extracting user preferences and personal characteristics\n", - "\n", - "**Best For:** Personalization systems, user profile building, preference learning\n", - "\n", - "**Example Output:**\n", - "```json\n", - "{\n", - " \"type\": \"semantic\",\n", - " \"text\": \"User prefers online courses over in-person instruction\",\n", - " \"topics\": [\"preferences\", \"learning_style\"],\n", - " \"entities\": [\"online courses\", \"in-person\"]\n", - "}\n", - "```\n", - "\n", - "**When to Use:**\n", - "- ✅ User onboarding flows\n", - "- ✅ Building user profiles\n", - "- ✅ Personalization-focused applications\n", - "- ✅ Preference learning systems\n", - "\n", - "---\n", - "\n", - "#### **4. Custom Strategy**\n", - "\n", - "**Purpose:** Use domain-specific extraction prompts for specialized needs\n", - "\n", - "**Best For:** Domain-specific extraction (technical, legal, medical), specialized workflows\n", - "\n", - "**Security Note:** ⚠️ Custom prompts require validation to prevent prompt injection attacks. See the [Security Guide](https://redis.github.io/agent-memory-server/security/) for details.\n", - "\n", - "**When to Use:**\n", - "- ✅ Specialized domains (legal, medical, technical)\n", - "- ✅ Custom extraction logic needed\n", - "- ✅ Domain-specific memory structures\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "e71ffa2ee69019f5", - "metadata": {}, - "source": [ - "### Strategy Comparison\n", - "\n", - "| Strategy | Output Type | Use Case | Example |\n", - "|----------|------------|----------|---------|\n", - "| **Discrete** | Individual facts | General agents | \"User's major is Computer Science\" |\n", - "| **Summary** | Conversation summary | Long sessions | \"User discussed CS major, interested in ML courses...\" |\n", - "| **Preferences** | User preferences | Personalization | \"User prefers online courses over in-person\" |\n", - "| **Custom** | Domain-specific | Specialized domains | Custom extraction logic |\n" - ] - }, - { - "cell_type": "markdown", - "id": "679ca666a553fb37", - "metadata": {}, - "source": [ - "### Default Behavior in This Course\n", - "\n", - "**In this course, we use the Discrete Strategy (default)** because:\n", - "\n", - "✅ **Works well for course advising conversations**\n", - "- Students ask specific questions\n", - "- Facts are independently useful\n", - "- Each fact can be searched separately\n", - "\n", - "✅ **Creates searchable individual facts**\n", - "- \"User's major is Computer Science\"\n", - "- \"User completed RU101\"\n", - "- \"User interested in machine learning\"\n", - "\n", - "✅ **Balances detail with storage efficiency**\n", - "- Not too granular (every sentence)\n", - "- Not too broad (entire conversations)\n", - "- Just right for Q&A interactions\n", - "\n", - "✅ **No configuration required**\n", - "- Default behavior\n", - "- Works out of the box\n", - "- Production-ready\n" - ] - }, - { - "cell_type": "markdown", - "id": "3e1695a490a2165f", - "metadata": {}, - "source": [ - "### When Would You Use Different Strategies?\n", - "\n", - "**Scenario 1: Long Academic Advising Session (Summary Strategy)**\n", - "\n", - "```\n", - "Student has 30-minute conversation discussing:\n", - "- Academic goals and graduation timeline\n", - "- Career aspirations and internship plans\n", - "- Course preferences and learning style\n", - "- Schedule constraints and work commitments\n", - "- Extracurricular interests\n", - "```\n", - "\n", - "**Discrete Strategy:** Extracts 20+ individual facts\n", - "- \"User wants to graduate Spring 2026\"\n", - "- \"User interested in tech startup internship\"\n", - "- \"User prefers online courses\"\n", - "- ... (17 more facts)\n", - "\n", - "**Summary Strategy:** Creates 1-2 comprehensive summaries\n", - "- \"Student discussed academic planning for Spring 2026 graduation, expressing strong interest in ML/AI courses and tech startup internships. Prefers online format due to part-time work commitments. Interested in vector databases and modern AI applications.\"\n", - "\n", - "**Trade-off:**\n", - "- Discrete: More searchable, more storage\n", - "- Summary: Less storage, preserves context\n", - "\n", - "---\n", - "\n", - "**Scenario 2: User Onboarding (Preferences Strategy)**\n", - "\n", - "```\n", - "New student onboarding flow:\n", - "- Communication preferences\n", - "- Learning style preferences\n", - "- Schedule preferences\n", - "- Notification preferences\n", - "```\n", - "\n", - "**Preferences Strategy:** Focuses on extracting preferences\n", - "- \"User prefers email over SMS notifications\"\n", - "- \"User prefers morning study sessions\"\n", - "- \"User prefers video content over text\"\n", - "\n", - "**Why Preferences Strategy:**\n", - "- Optimized for preference extraction\n", - "- Builds user profile efficiently\n", - "- Personalization-focused\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "2b6964aab793ef5a", - "metadata": {}, - "source": [ - "### How Strategies Work Behind the Scenes\n", - "\n", - "**Discrete Strategy (Default):**\n", - "```\n", - "Conversation Messages\n", - " ↓\n", - "[Background Worker]\n", - " ↓\n", - "Extract individual facts using LLM\n", - " ↓\n", - "Store each fact as separate long-term memory\n", - " ↓\n", - "Vector index for semantic search\n", - "```\n", - "\n", - "**Summary Strategy:**\n", - "```\n", - "Conversation Messages\n", - " ↓\n", - "[Background Worker]\n", - " ↓\n", - "Summarize conversation using LLM\n", - " ↓\n", - "Store summary as long-term memory\n", - " ↓\n", - "Vector index for semantic search\n", - "```\n", - "\n", - "**📚 Learn More:** See the [Memory Extraction Strategies Guide](https://redis.github.io/agent-memory-server/memory-extraction-strategies/) for detailed examples and hands-on demos in Notebook 2.\n", - "\n", - "---\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "d904c018fda2fbc0", - "metadata": {}, - "source": [ - "### 🎯 Memory Lifecycle Best Practices\n", - "\n", - "**1. Trust Automatic Extraction**\n", - "- Agent Memory Server automatically extracts important facts\n", - "- Don't manually store everything in long-term memory\n", - "- Let the system decide what's important\n", - "\n", - "**2. Use Appropriate Memory Types**\n", - "- Working memory: Current conversation only\n", - "- Long-term memory: Facts that should persist\n", - "\n", - "**3. Monitor Memory Growth**\n", - "- Long-term memories accumulate over time\n", - "- Implement cleanup for outdated information\n", - "- Consider archiving old memories\n", - "\n", - "**4. Understand Session Management**\n", - "- Working memory persists within a session (like ChatGPT conversations)\n", - "- New sessions start with empty working memory\n", - "- Important facts should be in long-term memory for cross-session access\n", - "- Consider providing ways to resume or load previous session context\n", - "\n", - "**5. Plan for Context Window Limits**\n", - "- Working memory doesn't expire, but can grow too large\n", - "- LLMs have context window limits (e.g., 128K tokens)\n", - "- Use compression strategies when conversations get long (covered in Notebook 03)\n", - "- Monitor token usage in long conversations\n", - "\n", - "**6. Test Cross-Session Behavior**\n", - "- Verify long-term memories are accessible across sessions\n", - "- Test both same-session returns and new-session starts\n", - "- Ensure personalization works in both scenarios\n", - "\n", - "---\n", - "\n", - "## 🎓 Key Takeaways\n", - "\n", - "### **1. Memory Solves the Grounding Problem**\n", - "\n", - "Without memory, agents can't resolve references:\n", - "- ❌ \"What are **its** prerequisites?\" → Agent doesn't know what \"its\" refers to\n", - "- ✅ With working memory → Agent resolves \"its\" from conversation history\n", - "\n", - "### **2. Two Types of Memory Serve Different Purposes**\n", - "\n", - "**Working Memory (Session-Scoped):**\n", - "- Conversation messages from current session\n", - "- Enables reference resolution and conversation continuity\n", - "- Persists within the session (like ChatGPT conversations)\n", - "- Challenge: Can grow too large for context window limits\n", - "\n", - "**Long-term Memory (Cross-Session):**\n", - "- Persistent knowledge: user preferences, domain facts, business rules\n", - "- Enables personalization AND consistent application behavior\n", - "- Can be user-scoped (personalization) or application-scoped (domain knowledge)\n", - "- Searchable via semantic vector search\n", - "\n", - "### **3. Memory Completes the Four Context Types**\n", - "\n", - "From Section 1, we learned about four context types. Memory enables two of them:\n", - "\n", - "1. **System Context** (Static) - ✅ Section 2\n", - "2. **User Context** (Dynamic, User-Specific) - ✅ Section 2 + Long-term Memory\n", - "3. **Conversation Context** (Dynamic, Session-Specific) - ✨ **Working Memory**\n", - "4. **Retrieved Context** (Dynamic, Query-Specific) - ✅ Section 2 RAG\n", - "\n", - "### **4. Memory + RAG = Complete Context Engineering**\n", - "\n", - "The integration pattern:\n", - "```\n", - "1. Load working memory (conversation history)\n", - "2. Search long-term memory (user facts)\n", - "3. RAG search (relevant documents)\n", - "4. Assemble all context types\n", - "5. Generate response\n", - "6. Save working memory (updated conversation)\n", - "```\n", - "\n", - "This gives us **stateful, personalized, context-aware conversations**.\n", - "\n", - "### **5. Agent Memory Server is Production-Ready**\n", - "\n", - "Why use Agent Memory Server instead of simple in-memory storage:\n", - "- ✅ **Scalable** - Redis-backed, handles thousands of users\n", - "- ✅ **Automatic** - Extracts important facts to long-term storage\n", - "- ✅ **Semantic search** - Vector-indexed memory retrieval\n", - "- ✅ **Deduplication** - Prevents redundant memories\n", - "- ✅ **Session management** - Efficient storage and retrieval of conversation history\n", - "\n", - "### **6. LangChain is Sufficient for Memory + RAG**\n", - "\n", - "We didn't need LangGraph for this section because:\n", - "- Simple linear flow (load → search → generate → save)\n", - "- No conditional branching or complex state management\n", - "- No tool calling required\n", - "\n", - "**LangGraph becomes necessary in Section 4** when we add tools and multi-step workflows.\n", - "\n", - "### **7. Memory Management Best Practices**\n", - "\n", - "**Choose the Right Memory Type:**\n", - "- **Semantic** for facts and preferences (most common)\n", - "- **Episodic** for time-bound events and timeline\n", - "- **Message** for context-rich conversations (use sparingly)\n", - "\n", - "**Understand Memory Lifecycle:**\n", - "- **Working memory:** Session-scoped, persists within session\n", - "- **Long-term memory:** Indefinite persistence, user-scoped, cross-session\n", - "- **Automatic extraction:** Trust the system to extract important facts\n", - "- **Context window limits:** Working memory can grow too large (use compression strategies)\n", - "\n", - "**Benefits of Proper Memory Management:**\n", - "- ✅ **Natural conversations** - Users don't repeat themselves\n", - "- ✅ **Cross-session personalization** - Knowledge persists over time\n", - "- ✅ **Efficient storage** - Automatic deduplication prevents bloat\n", - "- ✅ **Semantic search** - Find relevant memories without exact keywords\n", - "- ✅ **Scalable** - Redis-backed, production-ready architecture\n", - "\n", - "**Key Principle:** Memory transforms stateless RAG into stateful, personalized, context-aware conversations.\n", - "\n", - "---\n", - "\n", - "## 💪 Practice Exercises\n", - "\n", - "### **Exercise 1: Cross-Session Personalization**\n", - "\n", - "Modify the `memory_enhanced_rag_query` function to:\n", - "1. Store user preferences in long-term memory when mentioned\n", - "2. Use those preferences in future sessions\n", - "3. Test with two different sessions for the same student\n", - "\n", - "**Hint:** Look for phrases like \"I prefer...\", \"I like...\", \"I want...\" and store them as semantic memories.\n", - "\n", - "### **Exercise 2: Memory-Aware Filtering**\n", - "\n", - "Enhance the RAG search to use long-term memories as filters:\n", - "1. Search long-term memory for preferences (format, difficulty, schedule)\n", - "2. Apply those preferences as filters to `course_manager.search_courses()`\n", - "3. Compare results with and without memory-aware filtering\n", - "\n", - "**Hint:** Use the `filters` parameter in `course_manager.search_courses()`.\n", - "\n", - "### **Exercise 3: Conversation Summarization**\n", - "\n", - "Implement a function that summarizes long conversations:\n", - "1. When working memory exceeds 10 messages, summarize the conversation\n", - "2. Store the summary in long-term memory\n", - "3. Clear old messages from working memory (keep only recent 4)\n", - "4. Test that reference resolution still works with summarized history\n", - "\n", - "**Hint:** Use the LLM to generate summaries, then store as semantic memories.\n", - "\n", - "### **Exercise 4: Multi-User Memory Management**\n", - "\n", - "Create a simple CLI that:\n", - "1. Supports multiple students (different user IDs)\n", - "2. Maintains separate working memory per session\n", - "3. Maintains separate long-term memory per user\n", - "4. Demonstrates cross-session continuity for each user\n", - "\n", - "**Hint:** Use different `session_id` and `user_id` for each student.\n", - "\n", - "### **Exercise 5: Memory Search Quality**\n", - "\n", - "Experiment with long-term memory search:\n", - "1. Store 20+ diverse memories for a student\n", - "2. Try different search queries\n", - "3. Analyze which memories are retrieved\n", - "4. Adjust memory text to improve search relevance\n", - "\n", - "**Hint:** More specific memory text leads to better semantic search results.\n", - "\n", - "---\n", - "\n", - "## 📝 Summary\n", - "\n", - "### **What You Learned:**\n", - "\n", - "1. **The Grounding Problem** - Why agents need memory to resolve references\n", - "2. **Working Memory** - Session-scoped conversation history for continuity\n", - "3. **Long-term Memory** - Cross-session persistent knowledge for personalization\n", - "4. **Memory Integration** - Combining memory with Section 2's RAG system\n", - "5. **Complete Context Engineering** - All four context types working together\n", - "6. **Production Architecture** - Using Agent Memory Server for scalable memory\n", - "\n", - "### **What You Built:**\n", - "\n", - "- ✅ Working memory demo (multi-turn conversations)\n", - "- ✅ Long-term memory demo (persistent knowledge)\n", - "- ✅ Complete memory-enhanced RAG system\n", - "- ✅ Integration of all four context types\n", - "\n", - "### **Key Functions:**\n", - "\n", - "- `memory_enhanced_rag_query()` - Complete memory + RAG pipeline\n", - "- `working_memory_demo()` - Demonstrates conversation continuity\n", - "- `longterm_memory_demo()` - Demonstrates persistent knowledge\n", - "- `complete_demo()` - End-to-end multi-turn conversation\n", - "\n", - "### **Architecture Pattern:**\n", - "\n", - "```\n", - "User Query\n", - " ↓\n", - "Load Working Memory (conversation history)\n", - " ↓\n", - "Search Long-term Memory (user facts)\n", - " ↓\n", - "RAG Search (relevant courses)\n", - " ↓\n", - "Assemble Context (System + User + Conversation + Retrieved)\n", - " ↓\n", - "Generate Response\n", - " ↓\n", - "Save Working Memory (updated conversation)\n", - "```\n", - "\n", - "### **From Section 2 to Section 3:**\n", - "\n", - "**Section 2 (Stateless RAG):**\n", - "- ❌ No conversation history\n", - "- ❌ Each query independent\n", - "- ❌ Can't resolve references\n", - "- ✅ Retrieves relevant documents\n", - "\n", - "**Section 3 (Memory-Enhanced RAG):**\n", - "- ✅ Conversation history (working memory)\n", - "- ✅ Multi-turn conversations\n", - "- ✅ Reference resolution\n", - "- ✅ Persistent user knowledge (long-term memory)\n", - "- ✅ Personalization across sessions\n", - "\n", - "### **Next Steps:**\n", - "\n", - "**Section 4** will add **tools** and **agentic workflows** using **LangGraph**, completing your journey from context engineering fundamentals to production-ready AI agents.\n", - "\n", - "---\n", - "\n", - "## 🎉 Congratulations!\n", - "\n", - "You've successfully built a **memory-enhanced RAG system** that:\n", - "- Remembers conversations (working memory)\n", - "- Accumulates knowledge (long-term memory)\n", - "- Resolves references naturally\n", - "- Personalizes responses\n", - "- Integrates all four context types\n", - "\n", - "**You're now ready for Section 4: Tools & Agentic Workflows!** 🚀\n", - "\n", - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "- [Agent Memory Server Documentation](https://github.com/redis/agent-memory-server) - Production-ready memory management\n", - "- [Agent Memory Client](https://pypi.org/project/agent-memory-client/) - Python client for Agent Memory Server\n", - "- [RedisVL Documentation](https://redisvl.com/) - Redis Vector Library\n", - "- [LangChain Guide](https://python.langchain.com/docs/modules/memory/) - Langchain\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "95d2ac5376e38a1", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-3-memory-systems/02_combining_memory_with_retrieved_context.ipynb b/notebooks/section-3-memory-systems/02_combining_memory_with_retrieved_context.ipynb deleted file mode 100644 index 5fb6004..0000000 --- a/notebooks/section-3-memory-systems/02_combining_memory_with_retrieved_context.ipynb +++ /dev/null @@ -1,3064 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "9e21de5ad28ededc", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# 🔗 Combining Memory with Retrieved Context\n", - "\n", - "**⏱️ Estimated Time:** 60-75 minutes\n", - "\n", - "## 🎯 Learning Objectives\n", - "\n", - "By the end of this notebook, you will:\n", - "\n", - "1. **Build** a memory-enhanced RAG system that combines all four context types\n", - "2. **Demonstrate** the benefits of memory for natural conversations\n", - "3. **Convert** a simple RAG system into a LangGraph agent\n", - "4. **Prepare** for Section 4 (adding tools and advanced agent capabilities)\n", - "\n", - "---\n", - "\n", - "## 🔗 Bridge from Previous Notebooks\n", - "\n", - "### **What You've Learned:**\n", - "\n", - "**Section 1:** Four Context Types\n", - "- System Context (static instructions)\n", - "- User Context (profile, preferences)\n", - "- Conversation Context (enabled by working memory)\n", - "- Retrieved Context (RAG results)\n", - "\n", - "**Section 2:** RAG Fundamentals\n", - "- Semantic search with vector embeddings\n", - "- Context assembly\n", - "- LLM generation\n", - "\n", - "**Section 3 (Notebook 1):** Memory Fundamentals\n", - "- Working memory for conversation continuity\n", - "- Long-term memory for persistent knowledge\n", - "- Memory types (semantic, episodic, message)\n", - "- Memory lifecycle and persistence\n", - "\n", - "### **What We'll Build:**\n", - "\n", - "**Part 1:** Memory-Enhanced RAG\n", - "- Integrate working memory + long-term memory + RAG\n", - "- Show clear before/after comparisons\n", - "- Demonstrate benefits of memory systems\n", - "\n", - "**Part 2:** LangGraph Agent (Separate Notebook)\n", - "- Convert memory-enhanced RAG to LangGraph agent\n", - "- Add state management and control flow\n", - "- Prepare for Section 4 (tools and advanced capabilities)\n", - "\n", - "---\n", - "\n", - "## 📊 The Complete Picture\n", - "\n", - "### **Memory-Enhanced RAG Flow:**\n", - "\n", - "```\n", - "User Query\n", - " ↓\n", - "1. Load Working Memory (conversation history)\n", - "2. Search Long-term Memory (user preferences, facts)\n", - "3. RAG Search (relevant courses)\n", - "4. Assemble Context (System + User + Conversation + Retrieved)\n", - "5. Generate Response\n", - "6. Save Working Memory (updated conversation)\n", - "```\n", - "\n", - "### **All Four Context Types Working Together:**\n", - "\n", - "| Context Type | Source | Purpose |\n", - "|-------------|--------|---------|\n", - "| **System** | Static prompt | Role, instructions, guidelines |\n", - "| **User** | Profile + Long-term Memory | Personalization, preferences |\n", - "| **Conversation** | Working Memory | Reference resolution, continuity |\n", - "| **Retrieved** | RAG Search | Relevant courses, information |\n", - "\n", - "**💡 Key Insight:** Memory transforms stateless RAG into stateful, personalized conversations.\n", - "\n", - "---\n", - "\n", - "## 📦 Setup and Environment\n", - "\n", - "Let's set up our environment with the necessary dependencies and connections. We'll build on Section 2's RAG foundation and add memory capabilities.\n", - "\n", - "### ⚠️ Prerequisites\n", - "\n", - "**Before running this notebook, make sure you have:**\n", - "\n", - "1. **Docker Desktop running** - Required for Redis and Agent Memory Server\n", - "\n", - "2. **Environment variables** - Create a `.env` file in the project root directory:\n", - " ```bash\n", - " # Copy the example file (if it exists)\n", - " cd ../..\n", - " # Or create .env manually with:\n", - " # OPENAI_API_KEY=your_actual_openai_api_key_here\n", - " # REDIS_URL=redis://localhost:6379\n", - " # AGENT_MEMORY_URL=http://localhost:8088\n", - " ```\n", - "\n", - "3. **Start services** - Make sure Redis and Agent Memory Server are running:\n", - " ```bash\n", - " # Start Redis and Agent Memory Server using docker-compose\n", - " cd ../..\n", - " docker-compose up -d\n", - " ```\n", - "\n", - "**Note:** Using docker-compose will:\n", - "- ✅ Start Redis on port 6379\n", - "- ✅ Start Agent Memory Server on port 8088\n", - "- ✅ Configure networking between services\n", - "- ✅ Persist data in Docker volumes\n", - "\n", - "If the Memory Server is not available, the notebook will skip memory-related demos but will still run.\n" - ] - }, - { - "cell_type": "markdown", - "id": "264e6d5b346b6755", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T14:27:06.541458Z", - "iopub.status.busy": "2025-10-31T14:27:06.541296Z", - "iopub.status.idle": "2025-10-31T14:27:08.268475Z", - "shell.execute_reply": "2025-10-31T14:27:08.268022Z" - } - }, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "dedc66a54eb849c6", - "metadata": {}, - "source": [ - "### Automated Setup Check\n", - "\n", - "Let's run the setup script to ensure all services are running properly.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "1cd141310064ba82", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:04.402755Z", - "iopub.status.busy": "2025-12-09T19:50:04.402499Z", - "iopub.status.idle": "2025-12-09T19:50:04.475817Z", - "shell.execute_reply": "2025-12-09T19:50:04.475143Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Checking if required services are running...\n", - "\n", - "✅ Redis is running\n", - "✅ Agent Memory Server is running\n", - "\n", - "If services are not running, start them with:\n", - " cd ../..\n", - " docker-compose up -d\n" - ] - } - ], - "source": [ - "# Check if services are running\n", - "import subprocess\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "print(\"Checking if required services are running...\\n\")\n", - "\n", - "# Check if Redis is running\n", - "try:\n", - " result = subprocess.run(\n", - " [\"docker\", \"ps\", \"--filter\", \"name=redis\", \"--format\", \"{{.Names}}\"],\n", - " capture_output=True,\n", - " text=True,\n", - " timeout=5\n", - " )\n", - " if \"redis\" in result.stdout:\n", - " print(\"✅ Redis is running\")\n", - " else:\n", - " print(\"⚠️ Redis is not running. Start it with: docker-compose up -d\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not check Redis status: {e}\")\n", - "\n", - "# Check if Agent Memory Server is running\n", - "try:\n", - " result = subprocess.run(\n", - " [\"docker\", \"ps\", \"--filter\", \"name=agent-memory\", \"--format\", \"{{.Names}}\"],\n", - " capture_output=True,\n", - " text=True,\n", - " timeout=5\n", - " )\n", - " if \"agent-memory\" in result.stdout or \"memory\" in result.stdout:\n", - " print(\"✅ Agent Memory Server is running\")\n", - " else:\n", - " print(\"⚠️ Agent Memory Server is not running. Start it with: docker-compose up -d\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not check Agent Memory Server status: {e}\")\n", - "\n", - "print(\"\\nIf services are not running, start them with:\")\n", - "print(\" cd ../..\")\n", - "print(\" docker-compose up -d\")" - ] - }, - { - "cell_type": "markdown", - "id": "d221bf3835cda63e", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "18c01bfe255ff0d", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T14:27:08.387999Z", - "iopub.status.busy": "2025-10-31T14:27:08.387932Z", - "iopub.status.idle": "2025-10-31T14:27:19.029786Z", - "shell.execute_reply": "2025-10-31T14:27:19.029077Z" - } - }, - "source": [ - "### Install Dependencies\n", - "\n", - "If you haven't already installed the reference-agent package, uncomment and run the following:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "3bb296c50e53337f", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:04.477507Z", - "iopub.status.busy": "2025-12-09T19:50:04.477377Z", - "iopub.status.idle": "2025-12-09T19:50:04.479381Z", - "shell.execute_reply": "2025-12-09T19:50:04.478866Z" - } - }, - "outputs": [], - "source": [ - "# Uncomment to install the project package\n", - "# %pip install -q -e ../..\n", - "\n", - "# Uncomment to install agent-memory-client\n", - "# %pip install -q agent-memory-client" - ] - }, - { - "cell_type": "markdown", - "id": "5577d8576496593a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T14:27:19.031485Z", - "iopub.status.busy": "2025-10-31T14:27:19.031347Z", - "iopub.status.idle": "2025-10-31T14:27:19.324283Z", - "shell.execute_reply": "2025-10-31T14:27:19.323806Z" - } - }, - "source": [ - "### Load Environment Variables\n", - "\n", - "We'll load environment variables from the `.env` file in the `reference-agent` directory.\n", - "\n", - "**Required variables:**\n", - "- `OPENAI_API_KEY` - Your OpenAI API key\n", - "- `REDIS_URL` - Redis connection URL (default: redis://localhost:6379)\n", - "- `AGENT_MEMORY_URL` - Agent Memory Server URL (default: http://localhost:8088)\n", - "\n", - "If you haven't created the `.env` file yet, copy `.env.example` and add your OpenAI API key.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "7f541ee37bd9e94b", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:04.480719Z", - "iopub.status.busy": "2025-12-09T19:50:04.480602Z", - "iopub.status.idle": "2025-12-09T19:50:04.487904Z", - "shell.execute_reply": "2025-12-09T19:50:04.487591Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment variables loaded\n", - " REDIS_URL: redis://localhost:6379\n", - " AGENT_MEMORY_URL: http://localhost:8088\n" - ] - } - ], - "source": [ - "import os\n", - "from pathlib import Path\n", - "\n", - "from dotenv import load_dotenv\n", - "\n", - "# Load environment variables from project root directory\n", - "env_path = Path(\"../../.env\")\n", - "load_dotenv(dotenv_path=env_path)\n", - "\n", - "# Verify required environment variables\n", - "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n", - "REDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379\")\n", - "AGENT_MEMORY_URL = os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8088\")\n", - "\n", - "if not OPENAI_API_KEY:\n", - " print(\n", - " f\"\"\"❌ OPENAI_API_KEY not found!\n", - "\n", - " Please create a .env file at: {env_path.absolute()}\n", - "\n", - " With the following content:\n", - " OPENAI_API_KEY=your_openai_api_key\n", - " REDIS_URL=redis://localhost:6379\n", - " AGENT_MEMORY_URL=http://localhost:8088\n", - " \"\"\"\n", - " )\n", - "else:\n", - " print(\"✅ Environment variables loaded\")\n", - " print(f\" REDIS_URL: {REDIS_URL}\")\n", - " print(f\" AGENT_MEMORY_URL: {AGENT_MEMORY_URL}\")" - ] - }, - { - "cell_type": "markdown", - "id": "ff97c53e10f44716", - "metadata": {}, - "source": [ - "### Import Core Libraries\n", - "\n", - "We'll import standard Python libraries and async support for our memory operations.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "1a4fabcf00d1fdda", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:04.489326Z", - "iopub.status.busy": "2025-12-09T19:50:04.489236Z", - "iopub.status.idle": "2025-12-09T19:50:04.491172Z", - "shell.execute_reply": "2025-12-09T19:50:04.490785Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Core libraries imported\n" - ] - } - ], - "source": [ - "import asyncio\n", - "import sys\n", - "from datetime import datetime\n", - "from typing import Any, Dict, List, Optional\n", - "\n", - "print(\"✅ Core libraries imported\")" - ] - }, - { - "cell_type": "markdown", - "id": "d8b6cc99aac5193e", - "metadata": {}, - "source": [ - "### Import Section 2 Components\n", - "\n", - "We're building on Section 2's RAG foundation, so we'll reuse the same components:\n", - "- `redis_config` - Redis connection and configuration\n", - "- `CourseManager` - Course search and management\n", - "- `StudentProfile` and other models - Data structures\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "87f84446a6969a31", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:04.492339Z", - "iopub.status.busy": "2025-12-09T19:50:04.492273Z", - "iopub.status.idle": "2025-12-09T19:50:06.742020Z", - "shell.execute_reply": "2025-12-09T19:50:06.741516Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Section 2 components imported\n", - " CourseManager: Available\n", - " Redis Config: Available\n", - " Models: Course, StudentProfile, etc.\n" - ] - } - ], - "source": [ - "from redis_context_course.course_manager import CourseManager\n", - "from redis_context_course.models import (\n", - " Course,\n", - " CourseFormat,\n", - " DifficultyLevel,\n", - " Semester,\n", - " StudentProfile,\n", - ")\n", - "\n", - "# Import Section 2 components\n", - "from redis_context_course.redis_config import redis_config\n", - "\n", - "print(\"✅ Section 2 components imported\")\n", - "print(f\" CourseManager: Available\")\n", - "print(f\" Redis Config: Available\")\n", - "print(f\" Models: Course, StudentProfile, etc.\")" - ] - }, - { - "cell_type": "markdown", - "id": "8c9c424c857e0b63", - "metadata": {}, - "source": [ - "### Import LangChain Components\n", - "\n", - "We'll use LangChain for LLM interaction and message handling.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "17f591bf327805dd", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.743378Z", - "iopub.status.busy": "2025-12-09T19:50:06.743251Z", - "iopub.status.idle": "2025-12-09T19:50:06.745163Z", - "shell.execute_reply": "2025-12-09T19:50:06.744810Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ LangChain components imported\n", - " ChatOpenAI: Available\n", - " Message types: HumanMessage, SystemMessage, AIMessage\n" - ] - } - ], - "source": [ - "from langchain_core.messages import AIMessage, HumanMessage, SystemMessage\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "print(\"✅ LangChain components imported\")\n", - "print(f\" ChatOpenAI: Available\")\n", - "print(f\" Message types: HumanMessage, SystemMessage, AIMessage\")" - ] - }, - { - "cell_type": "markdown", - "id": "b8a129328fb75fc3", - "metadata": {}, - "source": [ - "### Import Agent Memory Server Client\n", - "\n", - "The Agent Memory Server provides production-ready memory management. If it's not available, we'll note that and continue with limited functionality.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "8e19c1f57084b6b1", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.746369Z", - "iopub.status.busy": "2025-12-09T19:50:06.746303Z", - "iopub.status.idle": "2025-12-09T19:50:06.748344Z", - "shell.execute_reply": "2025-12-09T19:50:06.747934Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Agent Memory Server client available\n", - " MemoryAPIClient: Ready\n", - " Memory models: WorkingMemory, MemoryMessage, ClientMemoryRecord\n" - ] - } - ], - "source": [ - "# Import Agent Memory Server client\n", - "try:\n", - " from agent_memory_client import MemoryAPIClient, MemoryClientConfig\n", - " from agent_memory_client.models import (\n", - " ClientMemoryRecord,\n", - " MemoryMessage,\n", - " WorkingMemory,\n", - " )\n", - "\n", - " MEMORY_SERVER_AVAILABLE = True\n", - " print(\"✅ Agent Memory Server client available\")\n", - " print(\" MemoryAPIClient: Ready\")\n", - " print(\" Memory models: WorkingMemory, MemoryMessage, ClientMemoryRecord\")\n", - "except ImportError:\n", - " MEMORY_SERVER_AVAILABLE = False\n", - " print(\"⚠️ Agent Memory Server not available\")\n", - " print(\" Install with: pip install agent-memory-client\")\n", - " print(\" Start server: See reference-agent/README.md\")\n", - " print(\" Note: Some demos will be skipped\")" - ] - }, - { - "cell_type": "markdown", - "id": "773c7b6a987f3977", - "metadata": {}, - "source": [ - "### Environment Summary\n", - "\n", - "Let's verify everything is set up correctly.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "193e3a1353afb7b0", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.749457Z", - "iopub.status.busy": "2025-12-09T19:50:06.749394Z", - "iopub.status.idle": "2025-12-09T19:50:06.751665Z", - "shell.execute_reply": "2025-12-09T19:50:06.751276Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🔧 ENVIRONMENT SETUP SUMMARY\n", - "================================================================================\n", - "\n", - "✅ Core Libraries: Imported\n", - "✅ Section 2 Components: Imported\n", - "✅ LangChain: Imported\n", - "✅ Agent Memory Server: Available\n", - "\n", - "📋 Configuration:\n", - " OPENAI_API_KEY: ✓ Set\n", - " REDIS_URL: redis://localhost:6379\n", - " AGENT_MEMORY_URL: http://localhost:8088\n", - "================================================================================\n" - ] - } - ], - "source": [ - "print(\"=\" * 80)\n", - "print(\"🔧 ENVIRONMENT SETUP SUMMARY\")\n", - "print(\"=\" * 80)\n", - "print(f\"\\n✅ Core Libraries: Imported\")\n", - "print(f\"✅ Section 2 Components: Imported\")\n", - "print(f\"✅ LangChain: Imported\")\n", - "print(\n", - " f\"{'✅' if MEMORY_SERVER_AVAILABLE else '⚠️ '} Agent Memory Server: {'Available' if MEMORY_SERVER_AVAILABLE else 'Not Available'}\"\n", - ")\n", - "print(f\"\\n📋 Configuration:\")\n", - "print(f\" OPENAI_API_KEY: {'✓ Set' if OPENAI_API_KEY else '✗ Not set'}\")\n", - "print(f\" REDIS_URL: {REDIS_URL}\")\n", - "print(f\" AGENT_MEMORY_URL: {AGENT_MEMORY_URL}\")\n", - "print(\"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "83febaebad1682ec", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🔧 Initialize Components\n", - "\n", - "Now let's initialize the components we'll use throughout this notebook.\n" - ] - }, - { - "cell_type": "markdown", - "id": "3fbbea50ae1ff08b", - "metadata": {}, - "source": [ - "### Initialize Course Manager\n", - "\n", - "The `CourseManager` handles course search and retrieval, just like in Section 2.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "236f04d3923aa764", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.752698Z", - "iopub.status.busy": "2025-12-09T19:50:06.752633Z", - "iopub.status.idle": "2025-12-09T19:50:06.881851Z", - "shell.execute_reply": "2025-12-09T19:50:06.881351Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:06 redisvl.index.index INFO Index already exists, not overwriting.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Course Manager initialized\n", - " Ready to search and retrieve courses\n" - ] - } - ], - "source": [ - "# Initialize Course Manager\n", - "course_manager = CourseManager()\n", - "\n", - "print(\"✅ Course Manager initialized\")\n", - "print(\" Ready to search and retrieve courses\")" - ] - }, - { - "cell_type": "markdown", - "id": "61c5f50d1886133e", - "metadata": {}, - "source": [ - "### Initialize LLM\n", - "\n", - "We'll use GPT-4o with temperature=0.0 for consistent, deterministic responses.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "bad8a7d2061efec7", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.882989Z", - "iopub.status.busy": "2025-12-09T19:50:06.882912Z", - "iopub.status.idle": "2025-12-09T19:50:06.891460Z", - "shell.execute_reply": "2025-12-09T19:50:06.891010Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ LLM initialized\n", - " Model: gpt-4o\n", - " Temperature: 0.0 (deterministic)\n" - ] - } - ], - "source": [ - "# Initialize LLM\n", - "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0.0)\n", - "\n", - "print(\"✅ LLM initialized\")\n", - "print(\" Model: gpt-4o\")\n", - "print(\" Temperature: 0.0 (deterministic)\")" - ] - }, - { - "cell_type": "markdown", - "id": "2e60063cef6b46a8", - "metadata": {}, - "source": [ - "### Initialize Memory Client\n", - "\n", - "If the Agent Memory Server is available, we'll initialize the memory client. This client handles both working memory (conversation history) and long-term memory (persistent facts).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "514603f5fdcf043a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.892594Z", - "iopub.status.busy": "2025-12-09T19:50:06.892513Z", - "iopub.status.idle": "2025-12-09T19:50:06.897579Z", - "shell.execute_reply": "2025-12-09T19:50:06.897146Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Memory Client initialized\n", - " Base URL: http://localhost:8088\n", - " Namespace: redis_university\n", - " Ready for working memory and long-term memory operations\n" - ] - } - ], - "source": [ - "# Initialize Memory Client\n", - "if MEMORY_SERVER_AVAILABLE:\n", - " config = MemoryClientConfig(\n", - " base_url=AGENT_MEMORY_URL, default_namespace=\"redis_university\"\n", - " )\n", - " memory_client = MemoryAPIClient(config=config)\n", - " print(\"✅ Memory Client initialized\")\n", - " print(f\" Base URL: {config.base_url}\")\n", - " print(f\" Namespace: {config.default_namespace}\")\n", - " print(\" Ready for working memory and long-term memory operations\")\n", - "else:\n", - " memory_client = None\n", - " print(\"⚠️ Memory Server not available\")\n", - " print(\" Running with limited functionality\")\n", - " print(\" Some demos will be skipped\")" - ] - }, - { - "cell_type": "markdown", - "id": "8bec158470f51831", - "metadata": {}, - "source": [ - "### Create Sample Student Profile\n", - "\n", - "We'll create a sample student profile to use throughout our demos. This follows the same pattern from Section 2.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "907614be8182a320", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.898734Z", - "iopub.status.busy": "2025-12-09T19:50:06.898670Z", - "iopub.status.idle": "2025-12-09T19:50:06.900797Z", - "shell.execute_reply": "2025-12-09T19:50:06.900534Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Student profile created\n", - " Name: Sarah Chen\n", - " Major: Computer Science\n", - " Year: 2\n", - " Interests: machine learning, data science, algorithms\n", - " Completed: Introduction to Programming, Data Structures\n", - " Preferred Format: online\n" - ] - } - ], - "source": [ - "# Create sample student profile\n", - "sarah = StudentProfile(\n", - " name=\"Sarah Chen\",\n", - " email=\"sarah.chen@university.edu\",\n", - " major=\"Computer Science\",\n", - " year=2,\n", - " interests=[\"machine learning\", \"data science\", \"algorithms\"],\n", - " completed_courses=[\"Introduction to Programming\", \"Data Structures\"],\n", - " current_courses=[\"Linear Algebra\"],\n", - " preferred_format=CourseFormat.ONLINE,\n", - " preferred_difficulty=DifficultyLevel.INTERMEDIATE,\n", - ")\n", - "\n", - "print(\"✅ Student profile created\")\n", - "print(f\" Name: {sarah.name}\")\n", - "print(f\" Major: {sarah.major}\")\n", - "print(f\" Year: {sarah.year}\")\n", - "print(f\" Interests: {', '.join(sarah.interests)}\")\n", - "print(f\" Completed: {', '.join(sarah.completed_courses)}\")\n", - "print(f\" Preferred Format: {sarah.preferred_format.value}\")" - ] - }, - { - "cell_type": "markdown", - "id": "9603e9dd9cf82e45", - "metadata": {}, - "source": [ - "### 💡 Key Insight\n", - "\n", - "We're reusing:\n", - "- ✅ **Same `CourseManager`** from Section 2\n", - "- ✅ **Same `StudentProfile`** model\n", - "- ✅ **Same Redis configuration**\n", - "\n", - "We're adding:\n", - "- ✨ **Memory Client** for conversation history\n", - "- ✨ **Working Memory** for session context\n", - "- ✨ **Long-term Memory** for persistent knowledge\n", - "\n", - "---\n", - "\n", - "## 📚 Part 1: Memory-Enhanced RAG\n", - "\n", - "### **Goal:** Build a simple, inline memory-enhanced RAG system that demonstrates the benefits of memory.\n", - "\n", - "### **Approach:**\n", - "- Start with Section 2's stateless RAG\n", - "- Add working memory for conversation continuity\n", - "- Add long-term memory for personalization\n", - "- Show clear before/after comparisons\n", - "\n", - "---\n", - "\n", - "## 🚫 Before: Stateless RAG (Section 2 Approach)\n", - "\n", - "Let's first recall how Section 2's stateless RAG worked, and see its limitations.\n" - ] - }, - { - "cell_type": "markdown", - "id": "abd9aaee3e7f7805", - "metadata": {}, - "source": [ - "### Query 1: Initial query (works fine)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "336f4f8e806ff089", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:06.902076Z", - "iopub.status.busy": "2025-12-09T19:50:06.902008Z", - "iopub.status.idle": "2025-12-09T19:50:10.384005Z", - "shell.execute_reply": "2025-12-09T19:50:10.383365Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🚫 STATELESS RAG DEMO\n", - "================================================================================\n", - "\n", - "👤 User: I'm interested in machine learning courses\n", - "\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:08 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:10 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: Based on your interest in machine learning and your background in computer science, I recommend the \"Machine Learning\" course from the list. This course will introduce you to machine learning algorithms and applications, including supervised and unsupervised learning and neural networks. It is an advanced course, so it will build on your existing knowledge from your completed courses in programming and data structures. Additionally, you might consider taking \"Linear Algebra\" as it is essential for understanding many concepts in data science and machine learning.\n" - ] - } - ], - "source": [ - "print(\"=\" * 80)\n", - "print(\"🚫 STATELESS RAG DEMO\")\n", - "print(\"=\" * 80)\n", - "\n", - "stateless_query_1 = \"I'm interested in machine learning courses\"\n", - "print(f\"\\n👤 User: {stateless_query_1}\\n\\n\")\n", - "\n", - "# Search courses\n", - "stateless_courses_1 = await course_manager.search_courses(stateless_query_1, limit=3)\n", - "\n", - "# Assemble context (System + User + Retrieved only - NO conversation history)\n", - "stateless_system_prompt = \"\"\"You are a Redis University course advisor.\n", - "\n", - "CRITICAL RULES:\n", - "- ONLY discuss and recommend courses from the \"Relevant Courses\" list provided below\n", - "- Do NOT mention, suggest, or make up any courses that are not in the provided list\n", - "- If the available courses don't perfectly match the request, recommend the best options from what IS available\"\"\"\n", - "\n", - "stateless_user_context = f\"\"\"Student: {sarah.name}\n", - "Major: {sarah.major}\n", - "Interests: {', '.join(sarah.interests)}\n", - "Completed: {', '.join(sarah.completed_courses)}\n", - "\"\"\"\n", - "\n", - "stateless_retrieved_context = \"Relevant Courses:\\n\"\n", - "for i, course in enumerate(stateless_courses_1, 1):\n", - " stateless_retrieved_context += f\"\\n{i}. {course.title}\"\n", - " stateless_retrieved_context += f\"\\n Description: {course.description}\"\n", - " stateless_retrieved_context += f\"\\n Difficulty: {course.difficulty_level.value}\"\n", - "\n", - "# Generate response\n", - "stateless_messages_1 = [\n", - " SystemMessage(content=stateless_system_prompt),\n", - " HumanMessage(\n", - " content=f\"{stateless_user_context}\\n\\n{stateless_retrieved_context}\\n\\nQuery: {stateless_query_1}\"\n", - " ),\n", - "]\n", - "\n", - "stateless_response_1 = llm.invoke(stateless_messages_1).content\n", - "print(f\"\\n🤖 Agent: {stateless_response_1}\")\n", - "\n", - "# ❌ No conversation history stored\n", - "# ❌ Next query won't remember this interaction" - ] - }, - { - "cell_type": "markdown", - "id": "b0e5f16248ede0b2", - "metadata": {}, - "source": [ - "### Query 2: Follow-up with pronoun reference (fails)\n", - "\n", - "Now let's try a follow-up that requires conversation history.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "be6391be25ebb1b9", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:10.386327Z", - "iopub.status.busy": "2025-12-09T19:50:10.386187Z", - "iopub.status.idle": "2025-12-09T19:50:13.144480Z", - "shell.execute_reply": "2025-12-09T19:50:13.143391Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "👤 User: What are the prerequisites for the first one?\n", - " Note: 'the first one' refers to the first course from Query 1\n", - "\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:10 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:13 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: The course list provided only includes \"Calculus I\" courses, and they all have the same description and difficulty level. Typically, prerequisites for a Calculus I course might include a solid understanding of pre-calculus topics such as algebra and trigonometry. However, since the list does not specify prerequisites, I recommend checking with the course provider or institution for specific requirements. If Sarah is interested in machine learning, data science, and algorithms, a strong foundation in calculus can be beneficial, so taking Calculus I could be a good step forward.\n", - "\n", - "❌ Agent can't resolve 'the first one' - no conversation history!\n" - ] - } - ], - "source": [ - "stateless_query_2 = \"What are the prerequisites for the first one?\"\n", - "print(f\"👤 User: {stateless_query_2}\")\n", - "print(f\" Note: 'the first one' refers to the first course from Query 1\\n\\n\")\n", - "\n", - "# Search courses (will search for \"prerequisites first one\" - not helpful)\n", - "stateless_courses_2 = await course_manager.search_courses(stateless_query_2, limit=3)\n", - "\n", - "# Assemble context (NO conversation history from Query 1)\n", - "stateless_retrieved_context_2 = \"Relevant Courses:\\n\"\n", - "for i, course in enumerate(stateless_courses_2, 1):\n", - " stateless_retrieved_context_2 += f\"\\n{i}. {course.title}\"\n", - " stateless_retrieved_context_2 += f\"\\n Description: {course.description}\"\n", - " stateless_retrieved_context_2 += f\"\\n Difficulty: {course.difficulty_level.value}\"\n", - "\n", - "# Generate response\n", - "stateless_messages_2 = [\n", - " SystemMessage(content=stateless_system_prompt),\n", - " HumanMessage(\n", - " content=f\"{stateless_user_context}\\n\\n{stateless_retrieved_context_2}\\n\\nQuery: {stateless_query_2}\"\n", - " ),\n", - "]\n", - "\n", - "stateless_response_2 = llm.invoke(stateless_messages_2).content\n", - "print(f\"\\n🤖 Agent: {stateless_response_2}\")\n", - "print(\"\\n❌ Agent can't resolve 'the first one' - no conversation history!\")" - ] - }, - { - "cell_type": "markdown", - "id": "7495edbb86ca8989", - "metadata": {}, - "source": [ - "\n", - "\n", - "### 🎯 What Just Happened?\n", - "\n", - "**Query 1:** \"I'm interested in machine learning courses\"\n", - "- ✅ Works fine - searches and returns ML courses\n", - "\n", - "**Query 2:** \"What are the prerequisites for **the first one**?\"\n", - "- ❌ **Fails** - Agent doesn't know what \"the first one\" refers to\n", - "- ❌ No conversation history stored\n", - "- ❌ Each query is completely independent\n", - "\n", - "**The Problem:** Natural conversation requires context from previous turns.\n", - "\n", - "---\n", - "\n", - "## ✅ After: Memory-Enhanced RAG\n", - "\n", - "Now let's add memory to enable natural conversations.\n", - "\n", - "### **Step 1: Load Working Memory**\n", - "\n", - "Working memory stores conversation history for the current session.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "2306e6cdcf19fcdb", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:13.147123Z", - "iopub.status.busy": "2025-12-09T19:50:13.146657Z", - "iopub.status.idle": "2025-12-09T19:50:13.158324Z", - "shell.execute_reply": "2025-12-09T19:50:13.157990Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:13 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/demo_session_001?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Loaded working memory for session: demo_session_001\n", - " Messages: 8\n" - ] - } - ], - "source": [ - "# Set up session and student identifiers\n", - "session_id = \"demo_session_001\"\n", - "student_id = sarah.email.split(\"@\")[0]\n", - "\n", - "# Load working memory\n", - "if MEMORY_SERVER_AVAILABLE:\n", - " _, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " print(f\"✅ Loaded working memory for session: {session_id}\")\n", - " print(f\" Messages: {len(working_memory.messages)}\")\n", - "else:\n", - " print(\"⚠️ Memory Server not available\")" - ] - }, - { - "cell_type": "markdown", - "id": "eeaeb0a04fb2b00b", - "metadata": {}, - "source": [ - "### 🎯 What We Just Did\n", - "\n", - "**Loaded Working Memory:**\n", - "- Created or retrieved conversation history for this session\n", - "- Session ID: `demo_session_001` (unique per conversation)\n", - "- User ID: `sarah_chen` (from student email)\n", - "\n", - "**Why This Matters:**\n", - "- Working memory persists across turns in the same session\n", - "- Enables reference resolution (\"it\", \"that course\", \"the first one\")\n", - "- Conversation context is maintained\n", - "\n", - "---\n", - "\n", - "### **Step 2: Search Long-term Memory**\n", - "\n", - "Long-term memory stores persistent facts and preferences across sessions.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "a07e0aefe7250bf9", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:13.160010Z", - "iopub.status.busy": "2025-12-09T19:50:13.159740Z", - "iopub.status.idle": "2025-12-09T19:50:13.466908Z", - "shell.execute_reply": "2025-12-09T19:50:13.466054Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:13 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🔍 Query: 'What does the student prefer?'\n", - "📚 Found 5 relevant memories:\n", - " 1. User is interested in machine learning courses.\n", - " 2. User asked about the availability of machine learning courses online, indicating an interest in flexible learning options.\n", - " 3. User has interests in data science and algorithms\n", - " 4. User is interested in machine learning courses.\n", - " 5. Data Structures and Algorithms (CS301) could be a good fit for User\n" - ] - } - ], - "source": [ - "# Search long-term memory\n", - "longterm_query = \"What does the student prefer?\"\n", - "\n", - "if MEMORY_SERVER_AVAILABLE:\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " longterm_results = await memory_client.search_long_term_memory(\n", - " text=longterm_query, user_id=UserId(eq=student_id), limit=5\n", - " )\n", - "\n", - " longterm_memories = (\n", - " [m.text for m in longterm_results.memories] if longterm_results.memories else []\n", - " )\n", - "\n", - " print(f\"🔍 Query: '{longterm_query}'\")\n", - " print(f\"📚 Found {len(longterm_memories)} relevant memories:\")\n", - " for i, memory in enumerate(longterm_memories, 1):\n", - " print(f\" {i}. {memory}\")\n", - "else:\n", - " longterm_memories = []\n", - " print(\"⚠️ Memory Server not available\")" - ] - }, - { - "cell_type": "markdown", - "id": "9fb3cb7ac45a690b", - "metadata": {}, - "source": [ - "### 🎯 What We Just Did\n", - "\n", - "**Searched Long-term Memory:**\n", - "- Used semantic search to find relevant facts\n", - "- Query: \"What does the student prefer?\"\n", - "- Results: Memories about preferences, goals, academic info\n", - "\n", - "**Why This Matters:**\n", - "- Long-term memory enables personalization\n", - "- Facts persist across sessions (days, weeks, months)\n", - "- Semantic search finds relevant memories without exact keyword matching\n", - "\n", - "---\n", - "\n", - "### **Step 3: Assemble All Four Context Types**\n", - "\n", - "Now let's combine everything: System + User + Conversation + Retrieved.\n" - ] - }, - { - "cell_type": "markdown", - "id": "e5dd1140f19fa2e", - "metadata": {}, - "source": [ - "#### 3.1: System Context (static)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "5a97ccafff01934d", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:13.469258Z", - "iopub.status.busy": "2025-12-09T19:50:13.469060Z", - "iopub.status.idle": "2025-12-09T19:50:13.472000Z", - "shell.execute_reply": "2025-12-09T19:50:13.471468Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ System Context created\n", - " Length: 927 chars\n" - ] - } - ], - "source": [ - "# 1. System Context (static)\n", - "context_system_prompt = \"\"\"You are a Redis University course advisor.\n", - "\n", - "Your role:\n", - "- Help students find and enroll in courses from our catalog\n", - "- Provide personalized recommendations based on available courses\n", - "- Answer questions about courses, prerequisites, schedules\n", - "\n", - "CRITICAL RULES - READ CAREFULLY:\n", - "- You can ONLY recommend courses that appear in the \"Relevant Courses\" list below\n", - "- Do NOT suggest courses that are not in the \"Relevant Courses\" list\n", - "- Do NOT say things like \"you might want to consider X course\" if X is not in the list\n", - "- Do NOT mention courses from other platforms or external resources\n", - "- If the available courses don't perfectly match the request, recommend the best options from what IS in the list\n", - "- Use conversation history to resolve references (\"it\", \"that course\", \"the first one\")\n", - "- Use long-term memories to personalize your recommendations\n", - "- Be helpful, supportive, and encouraging while staying within the available courses\"\"\"\n", - "\n", - "print(\"✅ System Context created\")\n", - "print(f\" Length: {len(context_system_prompt)} chars\")" - ] - }, - { - "cell_type": "markdown", - "id": "53c82066a191acc9", - "metadata": {}, - "source": [ - "#### 3.2: User Context (profile + long-term memories)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "f526b51861566d13", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:13.473908Z", - "iopub.status.busy": "2025-12-09T19:50:13.473774Z", - "iopub.status.idle": "2025-12-09T19:50:13.809569Z", - "shell.execute_reply": "2025-12-09T19:50:13.808747Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:13 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ User Context created\n", - " Length: 682 chars\n" - ] - } - ], - "source": [ - "# 2. User Context (profile + long-term memories)\n", - "context_user_context = f\"\"\"Student Profile:\n", - "- Name: {sarah.name}\n", - "- Major: {sarah.major}\n", - "- Year: {sarah.year}\n", - "- Interests: {', '.join(sarah.interests)}\n", - "- Completed: {', '.join(sarah.completed_courses)}\n", - "- Current: {', '.join(sarah.current_courses)}\n", - "- Preferred Format: {sarah.preferred_format.value}\n", - "- Preferred Difficulty: {sarah.preferred_difficulty.value}\"\"\"\n", - "\n", - "# Search long-term memory for this query\n", - "context_query = \"machine learning courses\"\n", - "\n", - "if MEMORY_SERVER_AVAILABLE:\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " context_longterm_results = await memory_client.search_long_term_memory(\n", - " text=context_query, user_id=UserId(eq=student_id), limit=5\n", - " )\n", - " context_longterm_memories = (\n", - " [m.text for m in context_longterm_results.memories]\n", - " if context_longterm_results.memories\n", - " else []\n", - " )\n", - "\n", - " if context_longterm_memories:\n", - " context_user_context += f\"\\n\\nLong-term Memories:\\n\" + \"\\n\".join(\n", - " [f\"- {m}\" for m in context_longterm_memories]\n", - " )\n", - "\n", - "print(\"✅ User Context created\")\n", - "print(f\" Length: {len(context_user_context)} chars\")" - ] - }, - { - "cell_type": "markdown", - "id": "d7d4b7343d483871", - "metadata": {}, - "source": [ - "#### 3.3: Conversation Context (working memory)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "c74eae47e96155df", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:13.811715Z", - "iopub.status.busy": "2025-12-09T19:50:13.811539Z", - "iopub.status.idle": "2025-12-09T19:50:13.820663Z", - "shell.execute_reply": "2025-12-09T19:50:13.820178Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:13 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/demo_session_001?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Conversation Context loaded\n", - " Messages: 8\n" - ] - } - ], - "source": [ - "# 3. Conversation Context (working memory)\n", - "if MEMORY_SERVER_AVAILABLE:\n", - " _, context_working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " context_conversation_messages = []\n", - " for msg in context_working_memory.messages:\n", - " if msg.role == \"user\":\n", - " context_conversation_messages.append(HumanMessage(content=msg.content))\n", - " elif msg.role == \"assistant\":\n", - " context_conversation_messages.append(AIMessage(content=msg.content))\n", - "\n", - " print(\"✅ Conversation Context loaded\")\n", - " print(f\" Messages: {len(context_conversation_messages)}\")\n", - "else:\n", - " context_conversation_messages = []" - ] - }, - { - "cell_type": "markdown", - "id": "ef065750cd38f76b", - "metadata": {}, - "source": [ - "#### 3.4: Retrieved Context (RAG)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "cdd97d65955272e7", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:13.822016Z", - "iopub.status.busy": "2025-12-09T19:50:13.821906Z", - "iopub.status.idle": "2025-12-09T19:50:14.007317Z", - "shell.execute_reply": "2025-12-09T19:50:14.006341Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:13 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Retrieved Context created\n", - " Length: 596 chars\n" - ] - } - ], - "source": [ - "# 4. Retrieved Context (RAG)\n", - "context_courses = await course_manager.search_courses(context_query, limit=3)\n", - "\n", - "context_retrieved_context = \"Relevant Courses:\\n\"\n", - "for i, course in enumerate(context_courses, 1):\n", - " context_retrieved_context += f\"\\n{i}. {course.title}\"\n", - " context_retrieved_context += f\"\\n Description: {course.description}\"\n", - " context_retrieved_context += f\"\\n Difficulty: {course.difficulty_level.value}\"\n", - " context_retrieved_context += f\"\\n Format: {course.format.value}\"\n", - " if course.prerequisites:\n", - " prereq_names = [p.course_title for p in course.prerequisites]\n", - " context_retrieved_context += f\"\\n Prerequisites: {', '.join(prereq_names)}\"\n", - "\n", - "print(\"✅ Retrieved Context created\")\n", - "print(f\" Length: {len(context_retrieved_context)} chars\")" - ] - }, - { - "cell_type": "markdown", - "id": "3b0cc30ca49faa54", - "metadata": {}, - "source": [ - "#### Summary: All Four Context Types\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "1cbf570051f9b121", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:14.010066Z", - "iopub.status.busy": "2025-12-09T19:50:14.009888Z", - "iopub.status.idle": "2025-12-09T19:50:14.012434Z", - "shell.execute_reply": "2025-12-09T19:50:14.011996Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "📊 ASSEMBLED CONTEXT\n", - "================================================================================\n", - "\n", - "1️⃣ System Context: 927 chars\n", - "2️⃣ User Context: 682 chars\n", - "3️⃣ Conversation Context: 8 messages\n", - "4️⃣ Retrieved Context: 596 chars\n" - ] - } - ], - "source": [ - "print(\"=\" * 80)\n", - "print(\"📊 ASSEMBLED CONTEXT\")\n", - "print(\"=\" * 80)\n", - "print(f\"\\n1️⃣ System Context: {len(context_system_prompt)} chars\")\n", - "print(f\"2️⃣ User Context: {len(context_user_context)} chars\")\n", - "print(f\"3️⃣ Conversation Context: {len(context_conversation_messages)} messages\")\n", - "print(f\"4️⃣ Retrieved Context: {len(context_retrieved_context)} chars\")" - ] - }, - { - "cell_type": "markdown", - "id": "26df0d7a4b1c6c60", - "metadata": {}, - "source": [ - "### 🎯 What We Just Did\n", - "\n", - "**Assembled All Four Context Types:**\n", - "\n", - "1. **System Context** - Role, instructions, guidelines (static)\n", - "2. **User Context** - Profile + long-term memories (dynamic, user-specific)\n", - "3. **Conversation Context** - Working memory messages (dynamic, session-specific)\n", - "4. **Retrieved Context** - RAG search results (dynamic, query-specific)\n", - "\n", - "**Why This Matters:**\n", - "- All four context types from Section 1 are now working together\n", - "- System knows WHO the user is (User Context)\n", - "- System knows WHAT was discussed (Conversation Context)\n", - "- System knows WHAT's relevant (Retrieved Context)\n", - "- System knows HOW to behave (System Context)\n", - "\n", - "---\n", - "\n", - "### **Step 4: Generate Response and Save Memory**\n", - "\n", - "Now let's put it all together: generate a response and save the conversation.\n" - ] - }, - { - "cell_type": "markdown", - "id": "b262b0b1942da424", - "metadata": {}, - "source": [ - "#### 4.1: Set up the query\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "24e7abcead19bcc0", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:14.014227Z", - "iopub.status.busy": "2025-12-09T19:50:14.014084Z", - "iopub.status.idle": "2025-12-09T19:50:14.016228Z", - "shell.execute_reply": "2025-12-09T19:50:14.015664Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "👤 User: I'm interested in machine learning courses\n" - ] - } - ], - "source": [ - "test_query = \"I'm interested in machine learning courses\"\n", - "print(f\"👤 User: {test_query}\")" - ] - }, - { - "cell_type": "markdown", - "id": "1125bd64e3023243", - "metadata": {}, - "source": [ - "#### 4.2: Assemble all context types\n", - "\n", - "We'll reuse the context assembly logic from Step 3.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "997ec6e54c450371", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:14.017791Z", - "iopub.status.busy": "2025-12-09T19:50:14.017680Z", - "iopub.status.idle": "2025-12-09T19:50:14.580699Z", - "shell.execute_reply": "2025-12-09T19:50:14.579763Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:14 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/demo_session_001?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:14 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Context assembled\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Load working memory\n", - " _, test_working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " # Build conversation messages\n", - " test_conversation_messages = []\n", - " for msg in test_working_memory.messages:\n", - " if msg.role == \"user\":\n", - " test_conversation_messages.append(HumanMessage(content=msg.content))\n", - " elif msg.role == \"assistant\":\n", - " test_conversation_messages.append(AIMessage(content=msg.content))\n", - "\n", - " # Search for courses\n", - " test_courses = await course_manager.search_courses(test_query, limit=3)\n", - "\n", - " # Build retrieved context\n", - " test_retrieved_context = \"Relevant Courses:\\n\"\n", - " for i, course in enumerate(test_courses, 1):\n", - " test_retrieved_context += f\"\\n{i}. {course.title}\"\n", - " test_retrieved_context += f\"\\n Description: {course.description}\"\n", - " test_retrieved_context += f\"\\n Difficulty: {course.difficulty_level.value}\"\n", - " if course.prerequisites:\n", - " prereq_names = [p.course_title for p in course.prerequisites]\n", - " test_retrieved_context += f\"\\n Prerequisites: {', '.join(prereq_names)}\"\n", - "\n", - " print(\"✅ Context assembled\")" - ] - }, - { - "cell_type": "markdown", - "id": "9d2eed52c74ef1a3", - "metadata": {}, - "source": [ - "#### 4.3: Build messages and generate response\n" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "41033fb0b272936a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:14.583949Z", - "iopub.status.busy": "2025-12-09T19:50:14.583697Z", - "iopub.status.idle": "2025-12-09T19:50:16.995380Z", - "shell.execute_reply": "2025-12-09T19:50:16.994626Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:16 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: Hi Sarah! I see you're interested in machine learning courses. Currently, we have an advanced Machine Learning course available. It covers topics such as supervised and unsupervised learning, as well as neural networks. Given your background in computer science and your current study of Linear Algebra, you might find this course challenging but rewarding.\n", - "\n", - "While it is at an advanced level, your strong foundation in programming and data structures, along with your ongoing study of Linear Algebra, could help you tackle the material. If you're ready to take on the challenge, this course could be a great way to deepen your understanding of machine learning.\n", - "\n", - "Let me know if you have any questions or need more information about the course!\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Build complete message list\n", - " test_messages = [SystemMessage(content=context_system_prompt)]\n", - " test_messages.extend(test_conversation_messages) # Add conversation history\n", - " test_messages.append(\n", - " HumanMessage(\n", - " content=f\"{context_user_context}\\n\\n{test_retrieved_context}\\n\\nQuery: {test_query}\"\n", - " )\n", - " )\n", - "\n", - " # Generate response using LLM\n", - " test_response = llm.invoke(test_messages).content\n", - "\n", - " print(f\"\\n🤖 Agent: {test_response}\")" - ] - }, - { - "cell_type": "markdown", - "id": "120b591cf34b3351", - "metadata": {}, - "source": [ - "#### 4.4: Save to working memory\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "8a7782164d5e152", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:16.997502Z", - "iopub.status.busy": "2025-12-09T19:50:16.997173Z", - "iopub.status.idle": "2025-12-09T19:50:17.012357Z", - "shell.execute_reply": "2025-12-09T19:50:17.011778Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:17 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/demo_session_001?user_id=sarah.chen&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "✅ Conversation saved to working memory\n", - " Total messages: 10\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Add messages to working memory\n", - " test_working_memory.messages.extend(\n", - " [\n", - " MemoryMessage(role=\"user\", content=test_query),\n", - " MemoryMessage(role=\"assistant\", content=test_response),\n", - " ]\n", - " )\n", - "\n", - " # Save to Memory Server\n", - " await memory_client.put_working_memory(\n", - " session_id=session_id,\n", - " memory=test_working_memory,\n", - " user_id=student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " print(f\"\\n✅ Conversation saved to working memory\")\n", - " print(f\" Total messages: {len(test_working_memory.messages)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "ebdcd4af8b39ecbd", - "metadata": {}, - "source": [ - "#### Helper function for the demo\n", - "\n", - "For the complete demo below, we'll use a helper function that combines all these steps.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "56ed86c043eddff6", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:17.014771Z", - "iopub.status.busy": "2025-12-09T19:50:17.014475Z", - "iopub.status.idle": "2025-12-09T19:50:17.019833Z", - "shell.execute_reply": "2025-12-09T19:50:17.019166Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Helper function created for demo\n" - ] - } - ], - "source": [ - "# Helper function for demo (combines all steps above)\n", - "\n", - "\n", - "async def generate_and_save(\n", - " user_query: str, student_profile: StudentProfile, session_id: str, top_k: int = 3\n", - ") -> str:\n", - " \"\"\"Generate response and save to working memory\"\"\"\n", - "\n", - " if not MEMORY_SERVER_AVAILABLE:\n", - " return \"⚠️ Memory Server not available\"\n", - "\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " student_id = student_profile.email.split(\"@\")[0]\n", - "\n", - " # Load working memory\n", - " _, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " # Build conversation messages\n", - " conversation_messages = []\n", - " for msg in working_memory.messages:\n", - " if msg.role == \"user\":\n", - " conversation_messages.append(HumanMessage(content=msg.content))\n", - " elif msg.role == \"assistant\":\n", - " conversation_messages.append(AIMessage(content=msg.content))\n", - "\n", - " # Search courses\n", - " courses = await course_manager.search_courses(user_query, limit=top_k)\n", - "\n", - " # Build retrieved context\n", - " retrieved_context = \"Relevant Courses:\\n\"\n", - " for i, course in enumerate(courses, 1):\n", - " retrieved_context += f\"\\n{i}. {course.title}\"\n", - " retrieved_context += f\"\\n Description: {course.description}\"\n", - " retrieved_context += f\"\\n Difficulty: {course.difficulty_level.value}\"\n", - " if course.prerequisites:\n", - " prereq_names = [p.course_title for p in course.prerequisites]\n", - " retrieved_context += f\"\\n Prerequisites: {', '.join(prereq_names)}\"\n", - "\n", - " # Build messages\n", - " messages = [SystemMessage(content=context_system_prompt)]\n", - " messages.extend(conversation_messages)\n", - " messages.append(\n", - " HumanMessage(\n", - " content=f\"{context_user_context}\\n\\n{retrieved_context}\\n\\nQuery: {user_query}\"\n", - " )\n", - " )\n", - "\n", - " # Generate response\n", - " response = llm.invoke(messages).content\n", - "\n", - " # Save to working memory\n", - " working_memory.messages.extend(\n", - " [\n", - " MemoryMessage(role=\"user\", content=user_query),\n", - " MemoryMessage(role=\"assistant\", content=response),\n", - " ]\n", - " )\n", - " await memory_client.put_working_memory(\n", - " session_id=session_id,\n", - " memory=working_memory,\n", - " user_id=student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " return response\n", - "\n", - "\n", - "print(\"✅ Helper function created for demo\")" - ] - }, - { - "cell_type": "markdown", - "id": "b1d57045c52dd02c", - "metadata": {}, - "source": [ - "### 🎯 What We Just Did\n", - "\n", - "**Generated Response:**\n", - "- Assembled all four context types\n", - "- Built message list with conversation history\n", - "- Generated response using LLM\n", - "- **Saved updated conversation to working memory**\n", - "\n", - "**Why This Matters:**\n", - "- Next query will have access to this conversation\n", - "- Reference resolution will work (\"it\", \"that course\")\n", - "- Conversation continuity is maintained\n", - "\n", - "---\n", - "\n", - "## 🧪 Complete Demo: Memory-Enhanced RAG\n", - "\n", - "Now let's test the complete system with a multi-turn conversation.\n", - "\n", - "We'll break this down into three turns:\n", - "1. Initial query about machine learning courses\n", - "2. Follow-up asking about prerequisites (with pronoun reference)\n", - "3. Another follow-up checking if student meets prerequisites\n" - ] - }, - { - "cell_type": "markdown", - "id": "2ee62ecce47bf926", - "metadata": {}, - "source": [ - "### Turn 1: Initial Query\n", - "\n", - "Let's start with a query about machine learning courses.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "f50093afecca2c8c", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:17.021853Z", - "iopub.status.busy": "2025-12-09T19:50:17.021488Z", - "iopub.status.idle": "2025-12-09T19:50:17.024570Z", - "shell.execute_reply": "2025-12-09T19:50:17.024066Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🧪 MEMORY-ENHANCED RAG DEMO\n", - "================================================================================\n", - "\n", - "👤 Student: Sarah Chen\n", - "📧 Session: complete_demo_session\n", - "\n", - "================================================================================\n", - "📍 TURN 1: Initial Query\n", - "================================================================================\n", - "\n", - "👤 User: I'm interested in machine learning courses\n" - ] - } - ], - "source": [ - "# Set up demo session\n", - "demo_session_id = \"complete_demo_session\"\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"🧪 MEMORY-ENHANCED RAG DEMO\")\n", - "print(\"=\" * 80)\n", - "print(f\"\\n👤 Student: {sarah.name}\")\n", - "print(f\"📧 Session: {demo_session_id}\")\n", - "\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"📍 TURN 1: Initial Query\")\n", - "print(\"=\" * 80)\n", - "\n", - "demo_query_1 = \"I'm interested in machine learning courses\"\n", - "print(f\"\\n👤 User: {demo_query_1}\")" - ] - }, - { - "cell_type": "markdown", - "id": "c5a4ade39bc1104b", - "metadata": {}, - "source": [ - "#### Generate response and save to memory\n" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "1d247655a8b83820", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:17.026116Z", - "iopub.status.busy": "2025-12-09T19:50:17.026018Z", - "iopub.status.idle": "2025-12-09T19:50:18.513655Z", - "shell.execute_reply": "2025-12-09T19:50:18.512590Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:17 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/complete_demo_session?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:17 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:18 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:18 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/complete_demo_session?user_id=sarah.chen&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: Hi Sarah! It's great to see your continued interest in machine learning. While we currently don't have an intermediate-level machine learning course available, I recommend considering the \"Machine Learning\" course we offer. It covers a range of topics including supervised and unsupervised learning, as well as neural networks. However, please note that this course is at an advanced difficulty level.\n", - "\n", - "Since you're currently taking Linear Algebra, which is essential for understanding many machine learning concepts, you might find that it helps prepare you for the advanced course. If you feel ready to take on the challenge, this could be a great opportunity to deepen your knowledge in machine learning. Let me know if you have any questions or need further assistance!\n", - "\n", - "✅ Conversation saved to working memory\n" - ] - } - ], - "source": [ - "demo_response_1 = await generate_and_save(demo_query_1, sarah, demo_session_id)\n", - "\n", - "print(f\"\\n🤖 Agent: {demo_response_1}\")\n", - "print(f\"\\n✅ Conversation saved to working memory\")" - ] - }, - { - "cell_type": "markdown", - "id": "775c4094d7248e1", - "metadata": {}, - "source": [ - "### Turn 2: Follow-up with Pronoun Reference\n", - "\n", - "Now let's ask about \"the first one\" - a reference that requires conversation history.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "27bc4cd9dfab64aa", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:18.516743Z", - "iopub.status.busy": "2025-12-09T19:50:18.516632Z", - "iopub.status.idle": "2025-12-09T19:50:18.518613Z", - "shell.execute_reply": "2025-12-09T19:50:18.518265Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "================================================================================\n", - "📍 TURN 2: Follow-up with Pronoun Reference\n", - "================================================================================\n", - "\n", - "👤 User: What are the prerequisites for the first one?\n", - " Note: 'the first one' refers to the first course mentioned in Turn 1\n" - ] - } - ], - "source": [ - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"📍 TURN 2: Follow-up with Pronoun Reference\")\n", - "print(\"=\" * 80)\n", - "\n", - "demo_query_2 = \"What are the prerequisites for the first one?\"\n", - "print(f\"\\n👤 User: {demo_query_2}\")\n", - "print(f\" Note: 'the first one' refers to the first course mentioned in Turn 1\")" - ] - }, - { - "cell_type": "markdown", - "id": "c12b0d543f855a68", - "metadata": {}, - "source": [ - "#### Load conversation history and generate response\n", - "\n", - "The system will load Turn 1 from working memory to resolve \"the first one\".\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "33f0859c03577c04", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:18.520181Z", - "iopub.status.busy": "2025-12-09T19:50:18.520090Z", - "iopub.status.idle": "2025-12-09T19:50:20.180809Z", - "shell.execute_reply": "2025-12-09T19:50:20.179774Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:18 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/complete_demo_session?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:18 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:20 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:20 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/complete_demo_session?user_id=sarah.chen&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: The first \"Calculus I\" course listed does not have any specified prerequisites, making it accessible for students who have a foundational understanding of mathematics. Given your background in Computer Science and your current study of Linear Algebra, you should be well-prepared to enroll in this intermediate-level course. It will provide you with essential mathematical skills that are beneficial for your interests in machine learning and data science. If you have any more questions or need further assistance, feel free to ask!\n", - "\n", - "✅ Agent resolved 'the first one' using conversation history!\n" - ] - } - ], - "source": [ - "demo_response_2 = await generate_and_save(demo_query_2, sarah, demo_session_id)\n", - "\n", - "print(f\"\\n🤖 Agent: {demo_response_2}\")\n", - "print(\"\\n✅ Agent resolved 'the first one' using conversation history!\")" - ] - }, - { - "cell_type": "markdown", - "id": "4b8c58d592048c0c", - "metadata": {}, - "source": [ - "### Turn 3: Another Follow-up\n", - "\n", - "Let's ask if the student meets the prerequisites mentioned in Turn 2.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "e81a28aff710f634", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:20.183371Z", - "iopub.status.busy": "2025-12-09T19:50:20.183173Z", - "iopub.status.idle": "2025-12-09T19:50:20.186824Z", - "shell.execute_reply": "2025-12-09T19:50:20.186151Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "================================================================================\n", - "📍 TURN 3: Another Follow-up\n", - "================================================================================\n", - "\n", - "👤 User: Do I meet those prerequisites?\n", - " Note: 'those prerequisites' refers to prerequisites from Turn 2\n" - ] - } - ], - "source": [ - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"📍 TURN 3: Another Follow-up\")\n", - "print(\"=\" * 80)\n", - "\n", - "demo_query_3 = \"Do I meet those prerequisites?\"\n", - "print(f\"\\n👤 User: {demo_query_3}\")\n", - "print(f\" Note: 'those prerequisites' refers to prerequisites from Turn 2\")" - ] - }, - { - "cell_type": "markdown", - "id": "e30907ab5fb2c1a", - "metadata": {}, - "source": [ - "#### Load full conversation history and check student profile\n", - "\n", - "The system will:\n", - "1. Load Turns 1-2 from working memory\n", - "2. Resolve \"those prerequisites\"\n", - "3. Check student's completed courses from profile\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "f69f77c1e8619b20", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:20.188732Z", - "iopub.status.busy": "2025-12-09T19:50:20.188577Z", - "iopub.status.idle": "2025-12-09T19:50:23.169823Z", - "shell.execute_reply": "2025-12-09T19:50:23.168796Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:20 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/complete_demo_session?user_id=sarah.chen&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:20 httpx INFO HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:23 httpx INFO HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:23 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/complete_demo_session?user_id=sarah.chen&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🤖 Agent: Based on the information provided, the first \"Calculus I\" course lists prerequisites as Prerequisite Course 3 and Prerequisite Course 6. Unfortunately, without more details on what those specific courses entail, it's difficult to determine if you meet them.\n", - "\n", - "However, the second and third \"Calculus I\" courses do not have any specified prerequisites, making them accessible for students with a foundational understanding of mathematics. Given your background in Computer Science and your current study of Linear Algebra, you should be well-prepared to enroll in one of these intermediate-level Calculus I courses. This will provide you with essential mathematical skills that are beneficial for your interests in machine learning and data science.\n", - "\n", - "If you have any more questions or need further assistance, feel free to ask!\n", - "\n", - "✅ Agent resolved 'those prerequisites' and checked student's transcript!\n", - "\n", - "================================================================================\n", - "✅ DEMO COMPLETE: Memory-enhanced RAG enables natural conversations!\n", - "================================================================================\n" - ] - } - ], - "source": [ - "demo_response_3 = await generate_and_save(demo_query_3, sarah, demo_session_id)\n", - "\n", - "print(f\"\\n🤖 Agent: {demo_response_3}\")\n", - "print(\"\\n✅ Agent resolved 'those prerequisites' and checked student's transcript!\")\n", - "\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"✅ DEMO COMPLETE: Memory-enhanced RAG enables natural conversations!\")\n", - "print(\"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "83059c5567f43c57", - "metadata": {}, - "source": [ - "### 🎯 What Just Happened?\n", - "\n", - "**Turn 1:** \"I'm interested in machine learning courses\"\n", - "- System searches courses\n", - "- Finds ML-related courses\n", - "- Responds with recommendations\n", - "- **Saves conversation to working memory**\n", - "\n", - "**Turn 2:** \"What are the prerequisites for **the first one**?\"\n", - "- System loads working memory (Turn 1)\n", - "- Resolves \"the first one\" → first course mentioned in Turn 1\n", - "- Responds with prerequisites\n", - "- **Saves updated conversation**\n", - "\n", - "**Turn 3:** \"Do I meet **those prerequisites**?\"\n", - "- System loads working memory (Turns 1-2)\n", - "- Resolves \"those prerequisites\" → prerequisites from Turn 2\n", - "- Checks student's completed courses (from profile)\n", - "- Responds with personalized answer\n", - "- **Saves updated conversation**\n", - "\n", - "**💡 Key Insight:** Memory + RAG = **Natural, stateful, personalized conversations**\n", - "\n", - "---\n", - "\n", - "## 📊 Before vs. After Comparison\n", - "\n", - "Let's visualize the difference between stateless and memory-enhanced RAG.\n", - "\n", - "### **Stateless RAG (Section 2):**\n", - "\n", - "```\n", - "Query 1: \"I'm interested in ML courses\"\n", - " → ✅ Works (searches and returns courses)\n", - "\n", - "Query 2: \"What are the prerequisites for the first one?\"\n", - " → ❌ Fails (no conversation history)\n", - " → Agent: \"Which course are you referring to?\"\n", - "```\n", - "\n", - "**Problems:**\n", - "- ❌ No conversation continuity\n", - "- ❌ Can't resolve references\n", - "- ❌ Each query is independent\n", - "- ❌ Poor user experience\n", - "\n", - "### **Memory-Enhanced RAG (This Notebook):**\n", - "\n", - "```\n", - "Query 1: \"I'm interested in ML courses\"\n", - " → ✅ Works (searches and returns courses)\n", - " → Saves to working memory\n", - "\n", - "Query 2: \"What are the prerequisites for the first one?\"\n", - " → ✅ Works (loads conversation history)\n", - " → Resolves \"the first one\" → first course from Query 1\n", - " → Responds with prerequisites\n", - " → Saves updated conversation\n", - "\n", - "Query 3: \"Do I meet those prerequisites?\"\n", - " → ✅ Works (loads conversation history)\n", - " → Resolves \"those prerequisites\" → prerequisites from Query 2\n", - " → Checks student transcript\n", - " → Responds with personalized answer\n", - "```\n", - "\n", - "**Benefits:**\n", - "- ✅ Conversation continuity\n", - "- ✅ Reference resolution\n", - "- ✅ Personalization\n", - "- ✅ Natural user experience\n", - "\n", - "---\n", - "\n", - "## 🎓 Key Takeaways\n", - "\n", - "### **1. Memory Transforms RAG**\n", - "\n", - "**Without Memory (Section 2):**\n", - "- Stateless queries\n", - "- No conversation continuity\n", - "- Limited to 3 context types (System, User, Retrieved)\n", - "\n", - "**With Memory (This Notebook):**\n", - "- Stateful conversations\n", - "- Reference resolution\n", - "- All 4 context types (System, User, Conversation, Retrieved)\n", - "\n", - "### **2. Two Types of Memory Work Together**\n", - "\n", - "**Working Memory:**\n", - "- Session-scoped conversation history\n", - "- Enables reference resolution\n", - "- Persists within the session (like ChatGPT conversations)\n", - "\n", - "**Long-term Memory:**\n", - "- User-scoped persistent facts\n", - "- Enables personalization\n", - "- Persists indefinitely\n", - "\n", - "### **3. Simple, Inline Approach**\n", - "\n", - "**What We Built:**\n", - "- Small, focused functions\n", - "- Inline code (no large classes)\n", - "- Progressive learning\n", - "- Clear demonstrations\n", - "\n", - "**Why This Matters:**\n", - "- Easy to understand\n", - "- Easy to modify\n", - "- Easy to extend\n", - "- Foundation for LangGraph agents (Part 2)\n", - "\n", - "### **4. All Four Context Types**\n", - "\n", - "**System Context:** Role, instructions, guidelines\n", - "**User Context:** Profile + long-term memories\n", - "**Conversation Context:** Working memory\n", - "**Retrieved Context:** RAG results\n", - "\n", - "**Together:** Natural, stateful, personalized conversations\n", - "\n", - "**💡 Research Insight (From Section 1):** Context Rot research demonstrates that context structure and organization affect LLM attention. Memory systems that selectively retrieve and organize context outperform systems that dump all available information. This validates our approach: quality over quantity, semantic similarity, and selective retrieval. ([Context Rot paper](https://research.trychroma.com/context-rot))\n", - "\n", - "---\n", - "\n", - "## 🚀 What's Next?\n", - "\n", - "### **Part 2: Converting to LangGraph Agent (Separate Notebook)**\n", - "\n", - "In the next notebook (`03_langgraph_agent_conversion.ipynb`), we'll:\n", - "\n", - "1. **Convert** memory-enhanced RAG to LangGraph agent\n", - "2. **Add** state management and control flow\n", - "3. **Prepare** for Section 4 (tools and advanced capabilities)\n", - "4. **Build** a foundation for production-ready agents\n", - "\n", - "**Why LangGraph?**\n", - "- Better state management\n", - "- More control over agent flow\n", - "- Easier to add tools (Section 4)\n", - "- Production-ready architecture\n", - "\n", - "### **Section 4: Tools and Advanced Agents**\n", - "\n", - "After completing Part 2, you'll be ready for Section 4.\n", - "\n", - "**💡 What's Next:**\n", - "\n", - "In Section 4, you'll build an agent that can actively decide when to use memory tools, rather than having memory operations hardcoded in your application flow.\n", - "\n", - "---\n", - "\n", - "## 🏋️ Practice Exercises\n", - "\n", - "### **Exercise 1: Add Personalization**\n", - "\n", - "Modify the system to use long-term memories for personalization:\n", - "\n", - "1. Store student preferences in long-term memory\n", - "2. Search long-term memory in `assemble_context()`\n", - "3. Use memories to personalize recommendations\n", - "\n", - "**Hint:** Use `memory_client.create_long_term_memory()` and `memory_client.search_long_term_memory()`\n", - "\n", - "### **Exercise 2: Add Error Handling**\n", - "\n", - "Add error handling for memory operations:\n", - "\n", - "1. Handle case when Memory Server is unavailable\n", - "2. Fallback to stateless RAG\n", - "3. Log warnings appropriately\n", - "\n", - "**Hint:** Check `MEMORY_SERVER_AVAILABLE` flag\n", - "\n", - "### **Exercise 3: Add Conversation Summary**\n", - "\n", - "Add a function to summarize the conversation:\n", - "\n", - "1. Load working memory\n", - "2. Extract key points from conversation\n", - "3. Display summary to user\n", - "\n", - "**Hint:** Use LLM to generate summary from conversation history\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "1850ca00-5255-45e3-ac2a-e332f1a64cea", - "metadata": {}, - "source": [ - "### **Exercise 4: Compare Memory Extraction Strategies** 🆕\n", - "\n", - "In Notebook 1, we learned about memory extraction strategies. Now let's see them in action!\n", - "\n", - "**Goal:** Compare how discrete vs summary strategies extract different types of memories from the same conversation.\n", - "\n", - "**Scenario:** A student has a long advising session discussing their academic goals, course preferences, and career aspirations.\n" - ] - }, - { - "cell_type": "markdown", - "id": "6435601dec8615ec", - "metadata": {}, - "source": [ - "#### **Understanding the Difference**\n", - "\n", - "**Discrete Strategy (Default):**\n", - "- Extracts individual facts: \"User's major is CS\", \"User interested in ML\", \"User wants to graduate Spring 2026\"\n", - "- Each fact is independently searchable\n", - "- Good for: Most conversations, factual Q&A\n", - "\n", - "**Summary Strategy:**\n", - "- Creates conversation summary: \"User discussed academic planning, expressing interest in ML courses for Spring 2026 graduation...\"\n", - "- Preserves conversational context\n", - "- Good for: Long sessions, meeting notes, comprehensive context\n", - "\n", - "**Let's see the difference with real code!**\n" - ] - }, - { - "cell_type": "markdown", - "id": "2cc3e83167dc6e1a", - "metadata": {}, - "source": [ - "#### **Demo: Discrete Strategy (Current Default)**\n" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "97b9702ef4347804", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:23.172201Z", - "iopub.status.busy": "2025-12-09T19:50:23.172011Z", - "iopub.status.idle": "2025-12-09T19:50:25.617465Z", - "shell.execute_reply": "2025-12-09T19:50:25.616362Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🎯 Testing DISCRETE Strategy (Default)\n", - "================================================================================\n", - "Session ID: demo_discrete_584f315e\n", - "Student ID: student_discrete_afd4621f\n", - "\n", - "14:50:23 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/demo_discrete_584f315e?user_id=student_discrete_afd4621f&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 404 Not Found\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:23 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/demo_discrete_584f315e?user_id=student_discrete_afd4621f&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:23 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/demo_discrete_584f315e?user_id=student_discrete_afd4621f&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Conversation stored with DISCRETE strategy\n", - " Messages: 6\n", - "\n", - "⏳ Waiting for automatic memory extraction...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:25 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "📊 DISCRETE Strategy Results:\n", - " Extracted 0 individual memories\n", - "\n", - " ⏳ No memories extracted yet (background processing may take time)\n", - " Note: In production, extraction happens asynchronously\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " import uuid\n", - "\n", - " from agent_memory_client.models import MemoryStrategyConfig\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " # Create a test session with discrete strategy (default)\n", - " discrete_session_id = f\"demo_discrete_{uuid.uuid4().hex[:8]}\"\n", - " discrete_student_id = f\"student_discrete_{uuid.uuid4().hex[:8]}\"\n", - "\n", - " print(\"🎯 Testing DISCRETE Strategy (Default)\")\n", - " print(\"=\" * 80)\n", - " print(f\"Session ID: {discrete_session_id}\")\n", - " print(f\"Student ID: {discrete_student_id}\\n\")\n", - "\n", - " # Simulate a long advising conversation\n", - " advising_conversation = [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Hi! I'm a Computer Science major planning to graduate in Spring 2026. I'm really interested in machine learning and AI.\",\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"Great to meet you! I can help you plan your ML/AI coursework. What's your current experience level with machine learning?\",\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"I've taken intro to Python and data structures. I prefer online courses because I work part-time. I'm hoping to get an internship at a tech startup next summer.\",\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"Perfect! Based on your goals, I'd recommend starting with RU301 (Querying, Indexing, and Full-Text Search) and RU330 (Trading Engine). Both are available online.\",\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"That sounds good. I'm also interested in vector databases since they're used in AI applications. Do you have courses on that?\",\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"Absolutely! RU401 (Running Redis at Scale) covers vector search capabilities. It's a great fit for your AI interests.\",\n", - " },\n", - " ]\n", - "\n", - " # Store conversation in working memory (discrete strategy is default)\n", - " messages = [\n", - " MemoryMessage(role=msg[\"role\"], content=msg[\"content\"])\n", - " for msg in advising_conversation\n", - " ]\n", - "\n", - " # Get or create working memory\n", - " _, discrete_working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=discrete_session_id, user_id=discrete_student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " # Add messages to working memory\n", - " discrete_working_memory.messages.extend(messages)\n", - "\n", - " # Save to Memory Server\n", - " await memory_client.put_working_memory(\n", - " session_id=discrete_session_id,\n", - " memory=discrete_working_memory,\n", - " user_id=discrete_student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " print(\"✅ Conversation stored with DISCRETE strategy\")\n", - " print(f\" Messages: {len(messages)}\")\n", - " print(\"\\n⏳ Waiting for automatic memory extraction...\")\n", - "\n", - " # Wait a moment for background extraction\n", - " import asyncio\n", - "\n", - " await asyncio.sleep(2)\n", - "\n", - " # Search for extracted memories\n", - " discrete_results = await memory_client.search_long_term_memory(\n", - " text=\"student preferences and goals\",\n", - " user_id=UserId(eq=discrete_student_id),\n", - " limit=10,\n", - " )\n", - "\n", - " discrete_memories = discrete_results.memories if discrete_results.memories else []\n", - "\n", - " print(f\"\\n📊 DISCRETE Strategy Results:\")\n", - " print(f\" Extracted {len(discrete_memories)} individual memories\\n\")\n", - "\n", - " if discrete_memories:\n", - " for i, mem in enumerate(discrete_memories[:5], 1):\n", - " print(f\" {i}. {mem.text[:100]}...\")\n", - " else:\n", - " print(\" ⏳ No memories extracted yet (background processing may take time)\")\n", - " print(\" Note: In production, extraction happens asynchronously\")\n", - "else:\n", - " print(\"⚠️ Memory Server not available - skipping demo\")" - ] - }, - { - "cell_type": "markdown", - "id": "36519930b77297f3", - "metadata": {}, - "source": [ - "#### **Demo: Summary Strategy**\n", - "\n", - "Now let's see how the SUMMARY strategy handles the same conversation differently.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "90262aaa860ae39e", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:25.619851Z", - "iopub.status.busy": "2025-12-09T19:50:25.619638Z", - "iopub.status.idle": "2025-12-09T19:50:28.245654Z", - "shell.execute_reply": "2025-12-09T19:50:28.244452Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🎯 Testing SUMMARY Strategy\n", - "================================================================================\n", - "Session ID: demo_summary_2aa10f68\n", - "Student ID: student_summary_9eac115c\n", - "\n", - "14:50:25 httpx INFO HTTP Request: GET http://localhost:8088/v1/working-memory/demo_summary_2aa10f68?user_id=student_summary_9eac115c&namespace=redis_university&model_name=gpt-4o \"HTTP/1.1 404 Not Found\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:25 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/demo_summary_2aa10f68?user_id=student_summary_9eac115c&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:25 httpx INFO HTTP Request: PUT http://localhost:8088/v1/working-memory/demo_summary_2aa10f68?user_id=student_summary_9eac115c&model_name=gpt-4o \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Conversation stored with SUMMARY strategy\n", - " Messages: 6\n", - " Strategy: summary (max_summary_length=500)\n", - "\n", - "⏳ Waiting for automatic memory extraction...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14:50:28 httpx INFO HTTP Request: POST http://localhost:8088/v1/long-term-memory/search?optimize_query=false \"HTTP/1.1 200 OK\"\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "📊 SUMMARY Strategy Results:\n", - " Extracted 0 conversation summaries\n", - "\n", - " ⏳ No summaries extracted yet (background processing may take time)\n", - " Note: In production, extraction happens asynchronously\n" - ] - } - ], - "source": [ - "if MEMORY_SERVER_AVAILABLE:\n", - " # Create a test session with SUMMARY strategy\n", - " summary_session_id = f\"demo_summary_{uuid.uuid4().hex[:8]}\"\n", - " summary_student_id = f\"student_summary_{uuid.uuid4().hex[:8]}\"\n", - "\n", - " print(\"\\n🎯 Testing SUMMARY Strategy\")\n", - " print(\"=\" * 80)\n", - " print(f\"Session ID: {summary_session_id}\")\n", - " print(f\"Student ID: {summary_student_id}\\n\")\n", - "\n", - " # Configure summary strategy\n", - " summary_strategy = MemoryStrategyConfig(\n", - " strategy=\"summary\", config={\"max_summary_length\": 500}\n", - " )\n", - "\n", - " # Store the SAME conversation with summary strategy\n", - " messages = [\n", - " MemoryMessage(role=msg[\"role\"], content=msg[\"content\"])\n", - " for msg in advising_conversation\n", - " ]\n", - "\n", - " # Get or create working memory\n", - " _, summary_working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=summary_session_id, user_id=summary_student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " # Set the long-term memory strategy\n", - " summary_working_memory.long_term_memory_strategy = summary_strategy # ← Key difference!\n", - "\n", - " # Add messages to working memory\n", - " summary_working_memory.messages.extend(messages)\n", - "\n", - " # Save to Memory Server\n", - " await memory_client.put_working_memory(\n", - " session_id=summary_session_id,\n", - " memory=summary_working_memory,\n", - " user_id=summary_student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " print(\"✅ Conversation stored with SUMMARY strategy\")\n", - " print(f\" Messages: {len(messages)}\")\n", - " print(f\" Strategy: summary (max_summary_length=500)\")\n", - " print(\"\\n⏳ Waiting for automatic memory extraction...\")\n", - "\n", - " # Wait for background extraction\n", - " await asyncio.sleep(2)\n", - "\n", - " # Search for extracted memories\n", - " summary_results = await memory_client.search_long_term_memory(\n", - " text=\"student preferences and goals\",\n", - " user_id=UserId(eq=summary_student_id),\n", - " limit=10,\n", - " )\n", - "\n", - " summary_memories = summary_results.memories if summary_results.memories else []\n", - "\n", - " print(f\"\\n📊 SUMMARY Strategy Results:\")\n", - " print(f\" Extracted {len(summary_memories)} conversation summaries\\n\")\n", - "\n", - " if summary_memories:\n", - " for i, mem in enumerate(summary_memories[:3], 1):\n", - " print(f\" {i}. {mem.text}\\n\")\n", - " else:\n", - " print(\" ⏳ No summaries extracted yet (background processing may take time)\")\n", - " print(\" Note: In production, extraction happens asynchronously\")\n", - "else:\n", - " print(\"⚠️ Memory Server not available - skipping demo\")" - ] - }, - { - "cell_type": "markdown", - "id": "ecefdf0ba5d5621b", - "metadata": {}, - "source": [ - "#### **Comparison: When to Use Each Strategy**\n", - "\n", - "**Use DISCRETE Strategy (Default) when:**\n", - "- ✅ You want individual, searchable facts\n", - "- ✅ Facts should be independently retrievable\n", - "- ✅ Building knowledge graphs or fact databases\n", - "- ✅ Most general-purpose agent interactions\n", - "\n", - "**Example:** Course advisor agent (our use case)\n", - "- \"User's major is Computer Science\"\n", - "- \"User interested in machine learning\"\n", - "- \"User prefers online courses\"\n", - "- \"User wants to graduate Spring 2026\"\n", - "\n", - "**Use SUMMARY Strategy when:**\n", - "- ✅ Long conversations need to be preserved as context\n", - "- ✅ Meeting notes or session summaries\n", - "- ✅ Comprehensive context matters more than individual facts\n", - "- ✅ Reducing storage while preserving meaning\n", - "\n", - "**Example:** Academic advising session summary\n", - "- \"Student discussed academic planning for Spring 2026 graduation, expressing strong interest in ML/AI courses. Prefers online format due to part-time work. Seeking tech startup internship. Recommended RU301, RU330, and RU401 based on AI career goals.\"\n", - "\n", - "**Use PREFERENCES Strategy when:**\n", - "- ✅ Building user profiles\n", - "- ✅ Personalization is primary goal\n", - "- ✅ User onboarding flows\n", - "\n", - "**Example:** User profile building\n", - "- \"User prefers email over SMS notifications\"\n", - "- \"User works best in morning hours\"\n", - "- \"User prefers dark mode interfaces\"\n" - ] - }, - { - "cell_type": "markdown", - "id": "2836d12f1ac55727", - "metadata": {}, - "source": [ - "#### **Key Takeaway**\n", - "\n", - "**For this course, we use Discrete Strategy (default)** because:\n", - "1. Course advising benefits from searchable individual facts\n", - "2. Students ask specific questions (\"What are my prerequisites?\")\n", - "3. Facts are independently useful (\"User completed RU101\")\n", - "4. Balances detail with storage efficiency\n", - "\n", - "**In production**, you might use:\n", - "- **Discrete** for most interactions\n", - "- **Summary** for long consultation sessions\n", - "- **Preferences** during onboarding\n", - "- **Custom** for domain-specific needs (legal, medical, technical)\n" - ] - }, - { - "cell_type": "markdown", - "id": "8a2e7ad698521ca8", - "metadata": {}, - "source": [ - "#### **Configuration Reference**\n", - "\n", - "**Discrete Strategy (Default - No Config Needed):**\n", - "```python\n", - "# This is the default - no configuration required\n", - "_, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=user_id, model_name=\"gpt-4o\"\n", - ")\n", - "working_memory.messages.extend(messages)\n", - "await memory_client.put_working_memory(\n", - " session_id=session_id,\n", - " memory=working_memory,\n", - " user_id=user_id,\n", - " model_name=\"gpt-4o\"\n", - ")\n", - "```\n", - "\n", - "**Summary Strategy:**\n", - "```python\n", - "from agent_memory_client.models import MemoryStrategyConfig\n", - "\n", - "summary_strategy = MemoryStrategyConfig(\n", - " strategy=\"summary\",\n", - " config={\"max_summary_length\": 500}\n", - ")\n", - "\n", - "_, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=user_id, model_name=\"gpt-4o\"\n", - ")\n", - "working_memory.long_term_memory_strategy = summary_strategy\n", - "working_memory.messages.extend(messages)\n", - "await memory_client.put_working_memory(\n", - " session_id=session_id,\n", - " memory=working_memory,\n", - " user_id=user_id,\n", - " model_name=\"gpt-4o\"\n", - ")\n", - "```\n", - "\n", - "**Preferences Strategy:**\n", - "```python\n", - "preferences_strategy = MemoryStrategyConfig(\n", - " strategy=\"preferences\",\n", - " config={}\n", - ")\n", - "\n", - "_, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=session_id, user_id=user_id, model_name=\"gpt-4o\"\n", - ")\n", - "working_memory.long_term_memory_strategy = preferences_strategy\n", - "working_memory.messages.extend(messages)\n", - "await memory_client.put_working_memory(\n", - " session_id=session_id,\n", - " memory=working_memory,\n", - " user_id=user_id,\n", - " model_name=\"gpt-4o\"\n", - ")\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "id": "ffd903461d805026", - "metadata": {}, - "source": [ - "#### **📚 Learn More**\n", - "\n", - "For complete documentation and advanced configuration:\n", - "- [Memory Extraction Strategies Documentation](https://redis.github.io/agent-memory-server/memory-extraction-strategies/)\n", - "- [Working Memory Configuration](https://redis.github.io/agent-memory-server/working-memory/)\n", - "- [Long-term Memory Best Practices](https://redis.github.io/agent-memory-server/long-term-memory/)\n", - "\n", - "**Next:** In Section 4, we'll see how agents use these strategies in production workflows.\n", - "\n", - "\n", - "\n", - "---\n", - "\n", - "## 📝 Summary\n", - "\n", - "### **What You Learned:**\n", - "\n", - "1. ✅ **Built** memory-enhanced RAG system\n", - "2. ✅ **Integrated** all four context types\n", - "3. ✅ **Demonstrated** benefits of memory\n", - "4. ✅ **Prepared** for LangGraph conversion\n", - "\n", - "### **Key Concepts:**\n", - "\n", - "- **Working Memory** - Session-scoped conversation history\n", - "- **Long-term Memory** - User-scoped persistent facts\n", - "- **Context Assembly** - Combining all four context types\n", - "- **Reference Resolution** - Resolving pronouns and references\n", - "- **Stateful Conversations** - Natural, continuous dialogue\n", - "\n", - "### **Next Steps:**\n", - "\n", - "1. Complete practice exercises\n", - "2. Experiment with different queries\n", - "3. Move to Part 2 (LangGraph agent conversion)\n", - "4. Prepare for Section 4 (tools and advanced agents)\n", - "\n", - "**🎉 Congratulations!** You've built a complete memory-enhanced RAG system!\n", - "\n", - "---\n", - "\n", - "## 🔗 Resources\n", - "\n", - "- **Section 1:** Four Context Types\n", - "- **Section 2:** RAG Fundamentals\n", - "- **Section 3 (Notebook 1):** Memory Fundamentals\n", - "- **Section 3 (Notebook 3):** LangGraph Agent Conversion (Next)\n", - "- **Section 4:** Tools and Advanced Agents\n", - "\n", - "**Agent Memory Server:**\n", - "- GitHub: `reference-agent/`\n", - "- Documentation: See README.md\n", - "- API Client: `agent-memory-client`\n", - "\n", - "**LangChain:**\n", - "- Documentation: https://python.langchain.com/\n", - "- LangGraph: https://langchain-ai.github.io/langgraph/\n", - "\n", - "---\n", - "\n", - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "**Redis University - Context Engineering Course**\n", - "\n", - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "- [Agent Memory Server Documentation](https://github.com/redis/agent-memory-server) - Production-ready memory management\n", - "- [Agent Memory Client](https://pypi.org/project/agent-memory-client/) - Python client for Agent Memory Server\n", - "- [RedisVL Documentation](https://redisvl.com/) - Redis Vector Library\n", - "- [Retrieval-Augmented Generation Paper](https://arxiv.org/abs/2005.11401) - Original RAG research\n", - "- [LangChain RAG Tutorial](https://python.langchain.com/docs/use_cases/question_answering/) - Building RAG systems\n", - "- [LangGraph Tutorials](https://langchain-ai.github.io/langgraph/tutorials/) - Building agents with LangGraph\n", - "- [Agent Architectures](https://python.langchain.com/docs/modules/agents/) - Different agent patterns\n", - "- [ReAct: Synergizing Reasoning and Acting](https://arxiv.org/abs/2210.03629) - Reasoning + acting in LLMs\n", - "- [Anthropic's Guide to Building Effective Agents](https://www.anthropic.com/research/building-effective-agents) - Agent design patterns\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6bd68f27c65d3b21", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb b/notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb deleted file mode 100644 index 69ea9aa..0000000 --- a/notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb +++ /dev/null @@ -1,4137 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "3d06c497fe3df20b", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# 🧠 Managing Long Conversations with Compression Strategies\n", - "\n", - "**⏱️ Estimated Time:** 50-60 minutes\n", - "\n", - "## 🎯 Learning Objectives\n", - "\n", - "By the end of this notebook, you will:\n", - "\n", - "1. **Understand** why long conversations need management (token limits, performance, user experience)\n", - "2. **Implement** conversation summarization to preserve key information\n", - "3. **Build** context compression strategies (truncation, priority-based, summarization)\n", - "4. **Configure** automatic memory management with Agent Memory Server\n", - "5. **Decide** when to apply each technique based on conversation characteristics\n", - "\n", - "---\n", - "\n", - "## 🔗 Where We Are\n", - "\n", - "### **Your Journey So Far:**\n", - "\n", - "**Section 3, Notebook 1:** Memory Fundamentals\n", - "- ✅ Working memory for conversation continuity\n", - "- ✅ Long-term memory for persistent knowledge\n", - "- ✅ The grounding problem and reference resolution\n", - "- ✅ Memory types (semantic, episodic, message)\n", - "\n", - "**Section 3, Notebook 2:** Memory-Enhanced RAG\n", - "- ✅ Integrated all four context types\n", - "- ✅ Built complete memory-enhanced RAG system\n", - "- ✅ Demonstrated benefits of stateful conversations\n", - "\n", - "**Your memory system works!** It can:\n", - "- Remember conversation history across turns\n", - "- Store and retrieve long-term facts\n", - "- Resolve references (\"it\", \"that course\")\n", - "- Provide personalized recommendations\n", - "\n", - "### **But... What About Long Conversations?**\n", - "\n", - "**Questions we can't answer yet:**\n", - "- ❓ What happens when conversations get really long?\n", - "- ❓ How do we handle token limits?\n", - "- ❓ Can we preserve important context while reducing tokens?\n", - "- ❓ When should we summarize vs. truncate vs. keep everything?\n", - "- ❓ What are the resource implications of long conversations?\n", - "\n", - "---\n", - "\n", - "## 🚨 The Long Conversation Problem\n", - "\n", - "Before diving into solutions, let's understand the fundamental problem.\n", - "\n", - "**🔬 Connection to Section 1:** Remember the Context Rot research? It showed that LLM performance degrades non-uniformly as context length increases. This notebook teaches you practical strategies to address that problem.\n", - "\n", - "### **The Problem: Unbounded Growth**\n", - "\n", - "Every conversation turn adds messages to working memory:\n", - "\n", - "```\n", - "Turn 1: System (500) + Messages (200) = 700 tokens ✅\n", - "Turn 5: System (500) + Messages (1,000) = 1,500 tokens ✅\n", - "Turn 20: System (500) + Messages (4,000) = 4,500 tokens ✅\n", - "Turn 50: System (500) + Messages (10,000) = 10,500 tokens ⚠️\n", - "Turn 100: System (500) + Messages (20,000) = 20,500 tokens ⚠️\n", - "Turn 200: System (500) + Messages (40,000) = 40,500 tokens ❌\n", - "```\n", - "\n", - "**Without management, conversations grow unbounded!**\n", - "\n", - "### **Why This Matters**\n", - "\n", - "**1. Token Limits (Hard Constraint)**\n", - "- GPT-4o: 128K tokens (~96,000 words)\n", - "- GPT-3.5: 16K tokens (~12,000 words)\n", - "- Eventually, you'll hit the limit and conversations fail\n", - "\n", - "**2. Performance (Quality Constraint)**\n", - "- More tokens = longer processing time\n", - "- Context Rot: LLMs struggle with very long contexts (recall from Section 1: performance degrades non-uniformly as context grows)\n", - "- Important information gets \"lost in the middle\"\n", - "\n", - "**3. User Experience**\n", - "- Slow responses frustrate users\n", - "- Failed conversations due to token limits are unacceptable\n", - "- Degraded quality impacts user satisfaction\n", - "\n", - "**4. Resource Usage (Including Cost)**\n", - "- Input tokens consume API resources (e.g. $0.0025 / 1K tokens for GPT-4o)\n", - "- A 50-turn conversation = ~10,000 tokens = $0.025 per query\n", - "- Over 1,000 conversations = $25 just for conversation history\n", - "- At scale, resource efficiency becomes important\n", - "\n", - "### **The Solution: Memory Management**\n", - "\n", - "We need strategies to:\n", - "- ✅ Keep conversations within token budgets\n", - "- ✅ Preserve important information\n", - "- ✅ Maintain conversation quality\n", - "- ✅ Enable indefinite conversations\n", - "- ✅ Optimize resource usage\n", - "\n", - "---\n", - "\n", - "## 📦 Part 0: Setup and Environment\n", - "\n", - "Let's set up our environment and create tools for measuring conversation growth.\n", - "\n", - "### ⚠️ Prerequisites\n", - "\n", - "**Before running this notebook, make sure you have:**\n", - "\n", - "1. **Docker Desktop running** - Required for Redis and Agent Memory Server\n", - "\n", - "2. **Environment variables** - Create a `.env` file in the project root directory:\n", - " ```bash\n", - " # Copy the example file (if it exists)\n", - " cd ../..\n", - " # Or create .env manually with:\n", - " # OPENAI_API_KEY=your_actual_openai_api_key_here\n", - " # REDIS_URL=redis://localhost:6379\n", - " # AGENT_MEMORY_URL=http://localhost:8088\n", - " ```\n", - "\n", - "3. **Start services** - Make sure Redis and Agent Memory Server are running:\n", - " ```bash\n", - " # Start Redis and Agent Memory Server using docker-compose\n", - " cd ../..\n", - " docker-compose up -d\n", - " ```\n" - ] - }, - { - "cell_type": "markdown", - "id": "307c59ecc51d30c3", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "dd10e48e57f1431e", - "metadata": {}, - "source": [ - "### Automated Setup Check\n", - "\n", - "Let's run the setup script to ensure all services are running properly.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "808cea2af3f4f118", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:42.393134Z", - "iopub.status.busy": "2025-12-09T19:50:42.392903Z", - "iopub.status.idle": "2025-12-09T19:50:42.470016Z", - "shell.execute_reply": "2025-12-09T19:50:42.469468Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Checking if required services are running...\n", - "\n", - "✅ Redis is running\n", - "✅ Agent Memory Server is running\n", - "\n", - "If services are not running, start them with:\n", - " cd ../..\n", - " docker-compose up -d\n" - ] - } - ], - "source": [ - "# Check if services are running\n", - "import subprocess\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "print(\"Checking if required services are running...\\n\")\n", - "\n", - "# Check if Redis is running\n", - "try:\n", - " result = subprocess.run(\n", - " [\"docker\", \"ps\", \"--filter\", \"name=redis\", \"--format\", \"{{.Names}}\"],\n", - " capture_output=True,\n", - " text=True,\n", - " timeout=5\n", - " )\n", - " if \"redis\" in result.stdout:\n", - " print(\"✅ Redis is running\")\n", - " else:\n", - " print(\"⚠️ Redis is not running. Start it with: docker-compose up -d\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not check Redis status: {e}\")\n", - "\n", - "# Check if Agent Memory Server is running\n", - "try:\n", - " result = subprocess.run(\n", - " [\"docker\", \"ps\", \"--filter\", \"name=agent-memory\", \"--format\", \"{{.Names}}\"],\n", - " capture_output=True,\n", - " text=True,\n", - " timeout=5\n", - " )\n", - " if \"agent-memory\" in result.stdout or \"memory\" in result.stdout:\n", - " print(\"✅ Agent Memory Server is running\")\n", - " else:\n", - " print(\"⚠️ Agent Memory Server is not running. Start it with: docker-compose up -d\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not check Agent Memory Server status: {e}\")\n", - "\n", - "print(\"\\nIf services are not running, start them with:\")\n", - "print(\" cd ../..\")\n", - "print(\" docker-compose up -d\")" - ] - }, - { - "cell_type": "markdown", - "id": "4f7ab2a448dd08fc", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "9dd8400bfed20f64", - "metadata": {}, - "source": [ - "### Install Dependencies\n", - "\n", - "If you haven't already installed the project package, uncomment and run the following:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "62ad9f5d109351a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:42.471714Z", - "iopub.status.busy": "2025-12-09T19:50:42.471584Z", - "iopub.status.idle": "2025-12-09T19:50:42.473629Z", - "shell.execute_reply": "2025-12-09T19:50:42.473091Z" - } - }, - "outputs": [], - "source": [ - "# Uncomment to install the project package\n", - "# %pip install -q -e ../..\n", - "\n", - "# Uncomment to install agent-memory-client\n", - "# %pip install -q agent-memory-client" - ] - }, - { - "cell_type": "markdown", - "id": "b41bf6b02f73fdb9", - "metadata": {}, - "source": [ - "### Import Dependencies\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "b00247fc4bb718d6", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:42.474851Z", - "iopub.status.busy": "2025-12-09T19:50:42.474758Z", - "iopub.status.idle": "2025-12-09T19:50:44.343916Z", - "shell.execute_reply": "2025-12-09T19:50:44.343576Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ All imports successful\n" - ] - } - ], - "source": [ - "import asyncio\n", - "\n", - "# Standard library imports\n", - "import os\n", - "import time\n", - "\n", - "# For visualization\n", - "from collections import defaultdict\n", - "from dataclasses import dataclass, field\n", - "from datetime import datetime\n", - "from pathlib import Path\n", - "from typing import Any, Dict, List, Optional, Tuple\n", - "\n", - "# Token counting\n", - "import tiktoken\n", - "\n", - "# Redis and Agent Memory\n", - "from agent_memory_client import MemoryAPIClient, MemoryClientConfig\n", - "from agent_memory_client.models import ClientMemoryRecord, MemoryMessage, WorkingMemory\n", - "from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage\n", - "\n", - "# LangChain\n", - "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n", - "\n", - "print(\"✅ All imports successful\")" - ] - }, - { - "cell_type": "markdown", - "id": "38946d91e830639a", - "metadata": {}, - "source": [ - "### Load Environment Variables\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "41a3192aacee6dbf", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.345323Z", - "iopub.status.busy": "2025-12-09T19:50:44.345193Z", - "iopub.status.idle": "2025-12-09T19:50:44.350247Z", - "shell.execute_reply": "2025-12-09T19:50:44.349839Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment variables configured\n", - " Redis URL: redis://localhost:6379\n", - " Agent Memory URL: http://localhost:8088\n" - ] - } - ], - "source": [ - "from dotenv import load_dotenv\n", - "\n", - "# Load environment variables from project root directory\n", - "env_path = Path(\"../../.env\")\n", - "load_dotenv(dotenv_path=env_path)\n", - "\n", - "# Verify required environment variables\n", - "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n", - "REDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379\")\n", - "AGENT_MEMORY_URL = os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8088\")\n", - "\n", - "if not OPENAI_API_KEY:\n", - " print(\n", - " f\"\"\"❌ OPENAI_API_KEY not found!\n", - "\n", - "Please create a .env file at: {env_path.absolute()}\n", - "\n", - "With the following content:\n", - "OPENAI_API_KEY=your_openai_api_key\n", - "REDIS_URL=redis://localhost:6379\n", - "AGENT_MEMORY_URL=http://localhost:8088\n", - "\"\"\"\n", - " )\n", - "else:\n", - " print(\"✅ Environment variables configured\")\n", - " print(f\" Redis URL: {REDIS_URL}\")\n", - " print(f\" Agent Memory URL: {AGENT_MEMORY_URL}\")" - ] - }, - { - "cell_type": "markdown", - "id": "2f42157025d92c5", - "metadata": {}, - "source": [ - "### Initialize Clients\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "f6acdabe9f826582", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.351351Z", - "iopub.status.busy": "2025-12-09T19:50:44.351287Z", - "iopub.status.idle": "2025-12-09T19:50:44.640416Z", - "shell.execute_reply": "2025-12-09T19:50:44.640077Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Clients initialized\n", - " LLM: gpt-4o\n", - " Embeddings: text-embedding-3-small\n", - " Memory Server: http://localhost:8088\n" - ] - } - ], - "source": [ - "# Initialize LLM\n", - "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0.7)\n", - "\n", - "# Initialize embeddings\n", - "embeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\n", - "\n", - "# Initialize Agent Memory Client\n", - "memory_config = MemoryClientConfig(base_url=AGENT_MEMORY_URL)\n", - "memory_client = MemoryAPIClient(config=memory_config)\n", - "\n", - "# Initialize tokenizer for counting\n", - "tokenizer = tiktoken.encoding_for_model(\"gpt-4o\")\n", - "\n", - "\n", - "def count_tokens(text: str) -> int:\n", - " \"\"\"Count tokens in text using tiktoken.\"\"\"\n", - " return len(tokenizer.encode(text))\n", - "\n", - "\n", - "print(\"✅ Clients initialized\")\n", - "print(f\" LLM: {llm.model_name}\")\n", - "print(f\" Embeddings: text-embedding-3-small\")\n", - "print(f\" Memory Server: {AGENT_MEMORY_URL}\")" - ] - }, - { - "cell_type": "markdown", - "id": "cb3c6e2d8cee7f21", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 📊 Part 1: Understanding Conversation Growth\n", - "\n", - "Let's visualize how conversations grow and understand the implications.\n" - ] - }, - { - "cell_type": "markdown", - "id": "38b4a48ea4fee96b", - "metadata": {}, - "source": [ - "### 🔬 Research Context: Why Context Management Matters\n", - "\n", - "Modern LLMs have impressive context windows:\n", - "- **GPT-4o**: 128K tokens (~96,000 words)\n", - "- **Claude 3.5**: 200K tokens (~150,000 words)\n", - "- **Gemini 1.5 Pro**: 1M tokens (~750,000 words)\n", - "\n", - "**But here's the problem:** Larger context windows don't guarantee better performance.\n", - "\n", - "#### The \"Lost in the Middle\" Problem\n", - "\n", - "Research by Liu et al. (2023) in their paper [\"Lost in the Middle: How Language Models Use Long Contexts\"](https://arxiv.org/abs/2307.03172) revealed critical findings:\n", - "\n", - "**Key Finding #1: U-Shaped Performance**\n", - "- Models perform best when relevant information is at the **beginning** or **end** of context\n", - "- Performance **significantly degrades** when information is in the **middle** of long contexts\n", - "- This happens even with models explicitly designed for long contexts\n", - "\n", - "**Key Finding #2: Non-Uniform Degradation**\n", - "- It's not just about hitting token limits\n", - "- Quality degrades **even within the context window**\n", - "- The longer the context, the worse the \"middle\" performance becomes\n", - "\n", - "**Key Finding #3: More Context ≠ Better Results**\n", - "- In some experiments, GPT-3.5 performed **worse** with retrieved documents than with no documents at all\n", - "- Adding more context can actually **hurt** performance if not managed properly\n", - "\n", - "**Why This Matters for Memory Management:**\n", - "- Simply storing all conversation history isn't optimal\n", - "- We need **intelligent compression** to keep important information accessible\n", - "- **Position matters**: Recent context (at the end) is naturally well-positioned\n", - "- **Quality over quantity**: Better to have concise, relevant context than exhaustive history\n", - "\n", - "**References:**\n", - "- Liu, N. F., Lin, K., Hewitt, J., Paranjape, A., Bevilacqua, M., Petroni, F., & Liang, P. (2023). Lost in the Middle: How Language Models Use Long Contexts. *Transactions of the Association for Computational Linguistics (TACL)*.\n" - ] - }, - { - "cell_type": "markdown", - "id": "9ff7e262cad76878", - "metadata": {}, - "source": [ - "### Demo 1: Token Growth Over Time\n", - "\n", - "Now let's see this problem in action by simulating conversation growth.\n", - "\n", - "#### Step 1: Define our system prompt and count its tokens\n", - "\n", - "**What:** Creating a system prompt and measuring its token count.\n", - "\n", - "**Why:** The system prompt is sent with EVERY request, so its size directly impacts the context window budget and resource usage. Understanding this baseline is crucial for managing token limits.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "99edd1b0325093b", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.641852Z", - "iopub.status.busy": "2025-12-09T19:50:44.641777Z", - "iopub.status.idle": "2025-12-09T19:50:44.644007Z", - "shell.execute_reply": "2025-12-09T19:50:44.643713Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "System prompt: 31 tokens\n" - ] - } - ], - "source": [ - "# System prompt (constant across all turns)\n", - "system_prompt = \"\"\"You are a helpful course advisor for Redis University.\n", - "Help students find courses, check prerequisites, and plan their schedule.\n", - "Be friendly, concise, and accurate.\"\"\"\n", - "\n", - "system_tokens = count_tokens(system_prompt)\n", - "\n", - "print(f\"System prompt: {system_tokens} tokens\")" - ] - }, - { - "cell_type": "markdown", - "id": "1a9e0cfece6beaf5", - "metadata": {}, - "source": [ - "#### Step 2: Simulate how tokens grow with each conversation turn\n", - "\n", - "**What:** Projecting token growth and resource usage across 1 to 200 conversation turns.\n", - "\n", - "**Why:** Visualizing the growth curve shows when conversations approach token limits (>20K tokens) and helps you plan compression strategies. Notice how token usage and costs accelerate - this is the quadratic growth problem.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "117ca757272caef3", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.645148Z", - "iopub.status.busy": "2025-12-09T19:50:44.645073Z", - "iopub.status.idle": "2025-12-09T19:50:44.647631Z", - "shell.execute_reply": "2025-12-09T19:50:44.647271Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Conversation Growth Simulation:\n", - "================================================================================\n", - "Turn Messages Conv Tokens Total Tokens Cost ($) \n", - "--------------------------------------------------------------------------------\n", - "1 2 100 131 $0.0003 ✅\n", - "5 10 500 531 $0.0013 ✅\n", - "10 20 1,000 1,031 $0.0026 ✅\n", - "20 40 2,000 2,031 $0.0051 ✅\n", - "30 60 3,000 3,031 $0.0076 ✅\n", - "50 100 5,000 5,031 $0.0126 ⚠️\n", - "75 150 7,500 7,531 $0.0188 ⚠️\n", - "100 200 10,000 10,031 $0.0251 ⚠️\n", - "150 300 15,000 15,031 $0.0376 ⚠️\n", - "200 400 20,000 20,031 $0.0501 ❌\n" - ] - } - ], - "source": [ - "# Assume average message pair (user + assistant) = 100 tokens\n", - "avg_message_pair_tokens = 100\n", - "\n", - "print(\"\\nConversation Growth Simulation:\")\n", - "print(\"=\" * 80)\n", - "print(\n", - " f\"{'Turn':<8} {'Messages':<10} {'Conv Tokens':<15} {'Total Tokens':<15} {'Cost ($)':<12}\"\n", - ")\n", - "print(\"-\" * 80)\n", - "\n", - "for turn in [1, 5, 10, 20, 30, 50, 75, 100, 150, 200]:\n", - " # Each turn = user message + assistant message\n", - " num_messages = turn * 2\n", - " conversation_tokens = num_messages * (avg_message_pair_tokens // 2)\n", - " total_tokens = system_tokens + conversation_tokens\n", - "\n", - " # Cost calculation (GPT-4o input: $0.0025 per 1K tokens)\n", - " cost_per_query = (total_tokens / 1000) * 0.0025\n", - "\n", - " # Visual indicator\n", - " if total_tokens < 5000:\n", - " indicator = \"✅\"\n", - " elif total_tokens < 20000:\n", - " indicator = \"⚠️\"\n", - " else:\n", - " indicator = \"❌\"\n", - "\n", - " print(\n", - " f\"{turn:<8} {num_messages:<10} {conversation_tokens:<15,} {total_tokens:<15,} ${cost_per_query:<11.4f} {indicator}\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "544c9c59a8e344be", - "metadata": {}, - "source": [ - "### Demo 2: Resource and Cost Analysis\n", - "\n", - "Let's analyze the cumulative resource usage and costs of long conversations.\n", - "As tokens grow, so does the cumulative cost.\n", - "\n", - "**Why token usage and costs grow quadratically:**\n", - "- Turn 1: Process 100 tokens\n", - "- Turn 2: Process 200 tokens (includes turn 1)\n", - "- Turn 3: Process 300 tokens (includes turns 1 & 2)\n", - "- Turn N: Process N×100 tokens\n", - "\n", - "Total tokens processed = 100 + 200 + 300 + ... + N×100 = **O(N²)** growth!\n", - "\n", - "#### Step 1: Create a function to calculate conversation metrics\n", - "\n", - "**What:** Building a metrics calculator that accounts for cumulative token processing and costs.\n", - "\n", - "**Why:** Each turn processes ALL previous messages, so token usage and costs compound. This function reveals the true scale of long conversations - not just the final token count, but the sum of all API calls and their associated costs.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "998184e76d362bf3", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.648666Z", - "iopub.status.busy": "2025-12-09T19:50:44.648600Z", - "iopub.status.idle": "2025-12-09T19:50:44.650801Z", - "shell.execute_reply": "2025-12-09T19:50:44.650428Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Conversation metrics function defined\n" - ] - } - ], - "source": [ - "def calculate_conversation_cost(\n", - " num_turns: int, avg_tokens_per_turn: int = 100\n", - ") -> Dict[str, float]:\n", - " \"\"\"\n", - " Calculate cost metrics for a conversation.\n", - "\n", - " Args:\n", - " num_turns: Number of conversation turns\n", - " avg_tokens_per_turn: Average tokens per turn (user + assistant)\n", - "\n", - " Returns:\n", - " Dictionary with cost metrics\n", - " \"\"\"\n", - " system_tokens = 50 # Simplified\n", - "\n", - " # Cumulative cost (each turn includes all previous messages)\n", - " cumulative_tokens = 0\n", - " cumulative_cost = 0.0\n", - "\n", - " for turn in range(1, num_turns + 1):\n", - " # Total tokens for this turn\n", - " conversation_tokens = turn * avg_tokens_per_turn\n", - " total_tokens = system_tokens + conversation_tokens\n", - "\n", - " # Cost for this turn (input tokens)\n", - " turn_cost = (total_tokens / 1000) * 0.0025\n", - " cumulative_cost += turn_cost\n", - " cumulative_tokens += total_tokens\n", - "\n", - " return {\n", - " \"num_turns\": num_turns,\n", - " \"final_tokens\": system_tokens + (num_turns * avg_tokens_per_turn),\n", - " \"cumulative_tokens\": cumulative_tokens,\n", - " \"cumulative_cost\": cumulative_cost,\n", - " \"avg_cost_per_turn\": cumulative_cost / num_turns,\n", - " }\n", - "\n", - "\n", - "print(\"✅ Conversation metrics function defined\")" - ] - }, - { - "cell_type": "markdown", - "id": "6710bd8b0268c34d", - "metadata": {}, - "source": [ - "#### Step 2: Compare resource usage and costs across different conversation lengths\n", - "\n", - "**What:** Running projections for conversations from 10 to 200 turns.\n", - "\n", - "**Why:** Seeing the quadratic growth in action - a 200-turn conversation processes significantly more tokens cumulatively than you might expect, with corresponding cost implications. This motivates compression strategies.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "4441a3298bd38af8", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.651749Z", - "iopub.status.busy": "2025-12-09T19:50:44.651684Z", - "iopub.status.idle": "2025-12-09T19:50:44.653683Z", - "shell.execute_reply": "2025-12-09T19:50:44.653428Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Resource and Cost Analysis for Different Conversation Lengths:\n", - "================================================================================\n", - "Turns Final Tokens Cumulative Tokens Total Cost Avg/Turn\n", - "--------------------------------------------------------------------------------\n", - "10 1,050 6,000 $0.02 $0.0015\n", - "25 2,550 33,750 $0.08 $0.0034\n", - "50 5,050 130,000 $0.33 $0.0065\n", - "100 10,050 510,000 $1.27 $0.0127\n", - "200 20,050 2,020,000 $5.05 $0.0253\n" - ] - } - ], - "source": [ - "print(\"Resource and Cost Analysis for Different Conversation Lengths:\")\n", - "print(\"=\" * 80)\n", - "print(\n", - " f\"{'Turns':<10} {'Final Tokens':<15} {'Cumulative Tokens':<20} {'Total Cost':<15} {'Avg/Turn'}\"\n", - ")\n", - "print(\"-\" * 80)\n", - "\n", - "for num_turns in [10, 25, 50, 100, 200]:\n", - " metrics = calculate_conversation_cost(num_turns)\n", - " print(\n", - " f\"{metrics['num_turns']:<10} \"\n", - " f\"{metrics['final_tokens']:<15,} \"\n", - " f\"{metrics['cumulative_tokens']:<20,} \"\n", - " f\"${metrics['cumulative_cost']:<14.2f} \"\n", - " f\"${metrics['avg_cost_per_turn']:.4f}\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "df5840eedf4a9185", - "metadata": {}, - "source": [ - "#### Key Takeaways\n", - "\n", - "**Without memory management:**\n", - "- Token usage grows **quadratically** (O(N²))\n", - "- Processing time increases with conversation length\n", - "- Context window limits will eventually be exceeded\n", - "- Costs scale quadratically with conversation length\n", - "- At scale (1000s of users), this becomes unsustainable\n", - "\n", - "**The solution:** Intelligent memory management to keep conversations within limits while preserving quality and managing resources efficiently.\n" - ] - }, - { - "cell_type": "markdown", - "id": "5a7f1c4414f6d2a7", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🎯 Part 2: Context Summarizaton\n", - "\n", - "**Context summarization** is the process of condensing conversation history into a compact representation that preserves essential information while dramatically reducing token count.\n", - "\n", - "Picture a chat assistant helping someone plan a wedding over 50 messages:\n", - "- It captures the critical stuff: venue choice, budget, guest count, vendor decisions\n", - "- It grabs the decisions and ditches the small talk\n", - "- Later messages can reference \"the venue we picked\" without replaying the entire debate\n", - " \n", - "**Same deal with LLM chats:**\n", - "- Squash ancient messages into a tight little paragraph\n", - "- Keep the gold (facts, choices, what the user loves/hates)\n", - "- Leave fresh messages untouched (they're still doing work)\n", - "- Slash token usage by 50-80% without lobotomizing the conversation\n", - "\n", - "### Why Should You Care About Summarization?\n", - "\n", - "Summarization tackles three gnarly problems:\n", - "\n", - "**1. Plays Nice With Token Caps (Callback to Part 1)**\n", - "- Chats balloon up forever if you let them\n", - "- Summarization keeps you from hitting the ceiling\n", - "- **Real talk:** 50 messages (10K tokens) → Compressed summary + 4 fresh messages (2.5K tokens)\n", - "\n", - "**2. Addresses Context Rot (From Section 1)**\n", - "- **Recall:** Section 1 research showed LLM performance degrades non-uniformly as context length increases\n", - "- **The Problem:** Old information gets buried and ignored (\"Lost in the Middle\")\n", - "- **The Solution:** Summarization condenses old context while preserving meaning\n", - "- Fresh messages stay at the end where models pay most attention\n", - "- **Result:** Model performs better AND you save space—addresses both quality and efficiency\n", - "\n", - "**3. Keeps Working Memory From Exploding (Throwback to Notebook 1)**\n", - "- Working memory = your conversation backlog\n", - "- Without summarization, it just keeps growing like a digital hoarder's closet\n", - "- Summarization gives it a haircut regularly\n", - "- **Payoff:** Conversations that can actually go the distance\n", - "\n", - "### When Should You Reach for This Tool?\n", - "\n", - "**Great for:**\n", - "- ✅ Marathon conversations (10+ back-and-forths)\n", - "- ✅ Chats that have a narrative arc (customer support, coaching sessions)\n", - "- ✅ Situations where you want history but not ALL the history\n", - "- ✅ When the recent stuff matters most\n", - "\n", - "**Skip it when:**\n", - "- ❌ Quick exchanges (under 5 turns—don't overthink it)\n", - "- ❌ Every syllable counts (legal docs, medical consultations)\n", - "- ❌ You might need verbatim quotes from way back\n", - "- ❌ The extra LLM call adds unacceptable latency to your workflow\n", - "\n", - "### Where Summarization Lives in Your Memory Stack\n", - "```\n", - "┌─────────────────────────────────────────────────────────┐\n", - "│ Your LLM Agent Brain │\n", - "│ │\n", - "│ Context Window (128K tokens available) │\n", - "│ ┌────────────────────────────────────────────────┐ │\n", - "│ │ 1. System Prompt (500 tokens) │ │\n", - "│ │ 2. Long-term Memory Bank (1,000 tokens) │ │\n", - "│ │ 3. RAG Retrieval Stuff (2,000 tokens) │ │\n", - "│ │ 4. Working Memory Zone: │ │\n", - "│ │ ┌──────────────────────────────────────┐ │ │\n", - "│ │ │ [COMPRESSED HISTORY] (500 tokens) │ │ │\n", - "│ │ │ - Critical facts from rounds 1-20 │ │ │\n", - "│ │ │ - Decisions that were locked in │ │ │\n", - "│ │ │ - User quirks and preferences │ │ │\n", - "│ │ └──────────────────────────────────────┘ │ │\n", - "│ │ Live Recent Messages (1,000 tokens) │ │\n", - "│ │ - Round 21: User shot + Assistant reply │ │\n", - "│ │ - Round 22: User shot + Assistant reply │ │\n", - "│ │ - Round 23: User shot + Assistant reply │ │\n", - "│ │ - Round 24: User shot + Assistant reply │ │\n", - "│ │ 5. Current Incoming Query (200 tokens) │ │\n", - "│ └────────────────────────────────────────────────┘ │\n", - "│ │\n", - "│ Running total: ~5,200 tokens (instead of 15K—nice!) │\n", - "└─────────────────────────────────────────────────────────┘\n", - "```\n", - "\n", - "#### The Bottom Line: \n", - "Summarization is a *compression technique* for working memory that maintains conversation continuity while keeping token counts manageable." - ] - }, - { - "cell_type": "markdown", - "id": "3d6a9c3a31a589d0", - "metadata": {}, - "source": [ - "### 🔬 Research Foundation: Recursive Summarization\n", - "\n", - "Wang et al. (2023) in [\"Recursively Summarizing Enables Long-Term Dialogue Memory in Large Language Models\"](https://arxiv.org/abs/2308.15022) demonstrated that:\n", - "\n", - "**Key Insight:** Recursive summarization enables LLMs to handle extremely long conversations by:\n", - "1. Memorizing small dialogue contexts\n", - "2. Recursively producing new memory using previous memory + new contexts\n", - "3. Maintaining consistency across long conversations\n", - "\n", - "**Their findings:**\n", - "- Improved response consistency in long-context conversations\n", - "- Works well with both long-context models (8K, 16K) and retrieval-enhanced LLMs\n", - "- Provides a practical solution for modeling extremely long contexts\n", - "\n", - "**Practical Application:**\n", - "- Summarize old messages while keeping recent ones intact\n", - "- Preserve key information (facts, decisions, preferences)\n", - "- Compress redundant or less important information\n", - "\n", - "**References:**\n", - "- Wang, Q., Fu, Y., Cao, Y., Wang, S., Tian, Z., & Ding, L. (2023). Recursively Summarizing Enables Long-Term Dialogue Memory in Large Language Models. *Neurocomputing* (Accepted).\n" - ] - }, - { - "cell_type": "markdown", - "id": "80bbd6185d7e1fd4", - "metadata": {}, - "source": [ - "### Theory: What to Preserve vs. Compress\n", - "\n", - "When summarizing conversations, we need to be strategic about what to keep and what to compress.\n", - "\n", - "**What to Preserve:**\n", - "- ✅ Key facts and decisions\n", - "- ✅ Student preferences and goals\n", - "- ✅ Important course recommendations\n", - "- ✅ Prerequisites and requirements\n", - "- ✅ Recent context (last few messages)\n", - "\n", - "**What to Compress:**\n", - "- 📦 Small talk and greetings\n", - "- 📦 Redundant information\n", - "- 📦 Old conversation details\n", - "- 📦 Resolved questions\n", - "\n", - "**When to Summarize:**\n", - "- Token threshold exceeded (e.g., > 2000 tokens)\n", - "- Message count threshold exceeded (e.g., > 10 messages)\n", - "- Time-based (e.g., after 1 hour)\n", - "- Manual trigger\n" - ] - }, - { - "cell_type": "markdown", - "id": "23b8486d8bc89f7b", - "metadata": {}, - "source": [ - "### Building Summarization Step-by-Step\n", - "\n", - "Let's build our summarization system incrementally, starting with simple components.\n", - "\n", - "#### Step 1: Create a data structure for conversation messages\n", - "\n", - "**What we're building:** A data structure to represent individual messages with metadata.\n", - "\n", - "**Why it's needed:** We need to track not just the message content, but also:\n", - "- Who sent it (user, assistant, system)\n", - "- When it was sent (timestamp)\n", - "- How many tokens it uses (for threshold checks)\n", - "\n", - "**How it works:** Python's `@dataclass` decorator creates a clean, type-safe structure with automatic initialization and token counting.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "3db188fb9f01d750", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.654952Z", - "iopub.status.busy": "2025-12-09T19:50:44.654889Z", - "iopub.status.idle": "2025-12-09T19:50:44.657149Z", - "shell.execute_reply": "2025-12-09T19:50:44.656778Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ ConversationMessage dataclass defined\n", - " Example - Role: user, Tokens: 9\n" - ] - } - ], - "source": [ - "@dataclass\n", - "class ConversationMessage:\n", - " \"\"\"Represents a single conversation message.\"\"\"\n", - "\n", - " role: str # \"user\", \"assistant\", \"system\"\n", - " content: str\n", - " timestamp: float = field(default_factory=time.time)\n", - " token_count: Optional[int] = None\n", - "\n", - " def __post_init__(self):\n", - " if self.token_count is None:\n", - " self.token_count = count_tokens(self.content)\n", - "\n", - "\n", - "# Test it\n", - "test_msg = ConversationMessage(\n", - " role=\"user\", content=\"What courses do you recommend for machine learning?\"\n", - ")\n", - "print(f\"✅ ConversationMessage dataclass defined\")\n", - "print(f\" Example - Role: {test_msg.role}, Tokens: {test_msg.token_count}\")" - ] - }, - { - "cell_type": "markdown", - "id": "5d49f8f61e276661", - "metadata": {}, - "source": [ - "#### Step 2: Create a function to check if summarization is needed\n", - "\n", - "**What we're building:** A decision function that determines when to trigger summarization.\n", - "\n", - "**Why it's needed:** We don't want to summarize too early (loses context) or too late (hits token limits). We need smart thresholds.\n", - "\n", - "**How it works:**\n", - "- Checks if we have enough messages to make summarization worthwhile\n", - "- Calculates total token count across all messages\n", - "- Returns `True` if either threshold (tokens OR messages) is exceeded\n", - "- Ensures we keep at least `keep_recent` messages unsummarized\n", - "\n", - "**When to summarize:**\n", - "- Token threshold: Prevents hitting model limits (e.g., >2000 tokens)\n", - "- Message threshold: Prevents conversation from getting too long (e.g., >10 messages)\n", - "- Keep recent: Preserves the most relevant context (e.g., last 4 messages)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "290935fa536cb8aa", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.658133Z", - "iopub.status.busy": "2025-12-09T19:50:44.658073Z", - "iopub.status.idle": "2025-12-09T19:50:44.659858Z", - "shell.execute_reply": "2025-12-09T19:50:44.659502Z" - } - }, - "outputs": [], - "source": [ - "def should_summarize(\n", - " messages: List[ConversationMessage],\n", - " token_threshold: int = 2000,\n", - " message_threshold: int = 10,\n", - " keep_recent: int = 4,\n", - ") -> bool:\n", - " \"\"\"\n", - " Determine if conversation needs summarization.\n", - "\n", - " Args:\n", - " messages: List of conversation messages\n", - " token_threshold: Summarize when total tokens exceed this\n", - " message_threshold: Summarize when message count exceeds this\n", - " keep_recent: Number of recent messages to keep unsummarized\n", - "\n", - " Returns:\n", - " True if summarization is needed\n", - " \"\"\"\n", - " # Don't summarize if we have very few messages\n", - " if len(messages) <= keep_recent:\n", - " return False\n", - "\n", - " # Calculate total tokens\n", - " total_tokens = sum(msg.token_count for msg in messages)\n", - "\n", - " # Summarize if either threshold is exceeded\n", - " return total_tokens > token_threshold or len(messages) > message_threshold" - ] - }, - { - "cell_type": "markdown", - "id": "37993b003426e127", - "metadata": {}, - "source": [ - "#### Step 3: Create a prompt template for summarization\n", - "\n", - "**What we're building:** A carefully crafted prompt that instructs the LLM on how to summarize conversations.\n", - "\n", - "**Why it's needed:** Generic summarization loses important details. We need domain-specific instructions that preserve what matters for course advisory conversations.\n", - "\n", - "**How it works:**\n", - "- Specifies the context (student-advisor conversation)\n", - "- Lists exactly what to preserve (decisions, requirements, goals, courses, issues)\n", - "- Requests structured output (bullet points for clarity)\n", - "- Emphasizes being \"specific and actionable\" (not vague summaries)\n", - "\n", - "**Design principle:** The prompt template is the \"instructions\" for the summarization LLM. Better instructions = better summaries.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "3a39408752c4a504", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.660798Z", - "iopub.status.busy": "2025-12-09T19:50:44.660740Z", - "iopub.status.idle": "2025-12-09T19:50:44.662088Z", - "shell.execute_reply": "2025-12-09T19:50:44.661830Z" - } - }, - "outputs": [], - "source": [ - "summarization_prompt_template = \"\"\"You are summarizing a conversation between a student and a course advisor.\n", - "\n", - "Create a concise summary that preserves:\n", - "1. Key decisions made\n", - "2. Important requirements or prerequisites discussed\n", - "3. Student's goals, preferences, and constraints\n", - "4. Specific courses mentioned and recommendations given\n", - "5. Any problems or issues that need follow-up\n", - "\n", - "Format as bullet points. Be specific and actionable.\n", - "\n", - "Conversation to summarize:\n", - "{conversation}\n", - "\n", - "Summary:\"\"\"" - ] - }, - { - "cell_type": "markdown", - "id": "2bca0c3b7f31459f", - "metadata": {}, - "source": [ - "#### Step 4: Create a function to generate summaries using the LLM\n", - "\n", - "**What we're building:** A function that takes messages and produces an intelligent summary using an LLM.\n", - "\n", - "**Why it's needed:** This is where the actual summarization happens. We need to:\n", - "- Format the conversation for the LLM\n", - "- Call the LLM with our prompt template\n", - "- Package the summary as a system message\n", - "\n", - "**How it works:**\n", - "1. Formats messages as \"User: ...\" and \"Assistant: ...\" text\n", - "2. Inserts formatted conversation into the prompt template\n", - "3. Calls the LLM asynchronously (non-blocking)\n", - "4. Wraps the summary in `[CONVERSATION SUMMARY]` marker for easy identification\n", - "5. Returns as a system message (distinguishes it from user/assistant messages)\n", - "\n", - "**Why async?** Summarization can take 1-3 seconds. Async allows other operations to continue while waiting for the LLM response.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "8b41ae7eb2d88f5a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.663387Z", - "iopub.status.busy": "2025-12-09T19:50:44.663298Z", - "iopub.status.idle": "2025-12-09T19:50:44.665328Z", - "shell.execute_reply": "2025-12-09T19:50:44.664923Z" - } - }, - "outputs": [], - "source": [ - "async def create_summary(\n", - " messages: List[ConversationMessage], llm: ChatOpenAI\n", - ") -> ConversationMessage:\n", - " \"\"\"\n", - " Create intelligent summary of conversation messages.\n", - "\n", - " Args:\n", - " messages: List of messages to summarize\n", - " llm: Language model for generating summary\n", - "\n", - " Returns:\n", - " ConversationMessage containing the summary\n", - " \"\"\"\n", - " # Format conversation for summarization\n", - " conversation_text = \"\\n\".join(\n", - " [f\"{msg.role.title()}: {msg.content}\" for msg in messages]\n", - " )\n", - "\n", - " # Generate summary using LLM\n", - " prompt = summarization_prompt_template.format(conversation=conversation_text)\n", - " response = await llm.ainvoke([HumanMessage(content=prompt)])\n", - "\n", - " summary_content = f\"[CONVERSATION SUMMARY]\\n{response.content}\"\n", - "\n", - " # Create summary message\n", - " summary_msg = ConversationMessage(\n", - " role=\"system\", content=summary_content, timestamp=messages[-1].timestamp\n", - " )\n", - "\n", - " return summary_msg" - ] - }, - { - "cell_type": "markdown", - "id": "56eb87c914424cd", - "metadata": {}, - "source": [ - "#### Step 5: Create a function to compress conversations\n", - "\n", - "**What we're building:** The main compression function that orchestrates the entire summarization process.\n", - "\n", - "**Why it's needed:** This ties together all the previous components into a single, easy-to-use function that:\n", - "- Decides whether to summarize\n", - "- Splits messages into old vs. recent\n", - "- Generates the summary\n", - "- Returns the compressed conversation\n", - "\n", - "**How it works:**\n", - "1. **Check:** Calls `should_summarize()` to see if compression is needed\n", - "2. **Split:** Divides messages into `old_messages` (to summarize) and `recent_messages` (to keep)\n", - "3. **Summarize:** Calls `create_summary()` on old messages\n", - "4. **Combine:** Returns `[summary] + recent_messages`\n", - "\n", - "**The result:** A conversation that's 50-80% smaller but preserves all essential information.\n", - "\n", - "**Example:**\n", - "- Input: 20 messages (4,000 tokens)\n", - "- Output: 1 summary + 4 recent messages (1,200 tokens)\n", - "- Savings: 70% reduction in tokens\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "4b904a38b1bad2b9", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.666431Z", - "iopub.status.busy": "2025-12-09T19:50:44.666354Z", - "iopub.status.idle": "2025-12-09T19:50:44.668178Z", - "shell.execute_reply": "2025-12-09T19:50:44.667906Z" - } - }, - "outputs": [], - "source": [ - "async def compress_conversation(\n", - " messages: List[ConversationMessage],\n", - " llm: ChatOpenAI,\n", - " token_threshold: int = 2000,\n", - " message_threshold: int = 10,\n", - " keep_recent: int = 4,\n", - ") -> List[ConversationMessage]:\n", - " \"\"\"\n", - " Compress conversation by summarizing old messages and keeping recent ones.\n", - "\n", - " Args:\n", - " messages: List of conversation messages\n", - " llm: Language model for generating summaries\n", - " token_threshold: Summarize when total tokens exceed this\n", - " message_threshold: Summarize when message count exceeds this\n", - " keep_recent: Number of recent messages to keep unsummarized\n", - "\n", - " Returns:\n", - " List of messages: [summary] + [recent messages]\n", - " \"\"\"\n", - " # Check if summarization is needed\n", - " if not should_summarize(messages, token_threshold, message_threshold, keep_recent):\n", - " return messages\n", - "\n", - " # Split into old and recent\n", - " old_messages = messages[:-keep_recent]\n", - " recent_messages = messages[-keep_recent:]\n", - "\n", - " if not old_messages:\n", - " return messages\n", - "\n", - " # Summarize old messages\n", - " summary = await create_summary(old_messages, llm)\n", - "\n", - " # Return summary + recent messages\n", - " return [summary] + recent_messages" - ] - }, - { - "cell_type": "markdown", - "id": "668fce6b8d81c302", - "metadata": {}, - "source": [ - "#### Step 6: Combine into a reusable class\n", - "\n", - "Now that we've built and tested each component, let's combine them into a reusable class.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "8324715c96096689", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.669172Z", - "iopub.status.busy": "2025-12-09T19:50:44.669117Z", - "iopub.status.idle": "2025-12-09T19:50:44.671553Z", - "shell.execute_reply": "2025-12-09T19:50:44.671190Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Summarization system built:\n", - " - ConversationMessage dataclass\n", - " - should_summarize() function\n", - " - Summarization prompt template\n", - " - create_summary() function\n", - " - compress_conversation() function\n", - " - ConversationSummarizer class\n" - ] - } - ], - "source": [ - "class ConversationSummarizer:\n", - " \"\"\"Manages conversation summarization to keep token counts manageable.\"\"\"\n", - "\n", - " def __init__(\n", - " self,\n", - " llm: ChatOpenAI,\n", - " token_threshold: int = 2000,\n", - " message_threshold: int = 10,\n", - " keep_recent: int = 4,\n", - " ):\n", - " \"\"\"\n", - " Initialize the summarizer.\n", - "\n", - " Args:\n", - " llm: Language model for generating summaries\n", - " token_threshold: Summarize when total tokens exceed this\n", - " message_threshold: Summarize when message count exceeds this\n", - " keep_recent: Number of recent messages to keep unsummarized\n", - " \"\"\"\n", - " self.llm = llm\n", - " self.token_threshold = token_threshold\n", - " self.message_threshold = message_threshold\n", - " self.keep_recent = keep_recent\n", - " self.summarization_prompt = summarization_prompt_template\n", - "\n", - " def should_summarize(self, messages: List[ConversationMessage]) -> bool:\n", - " \"\"\"Determine if conversation needs summarization.\"\"\"\n", - " return should_summarize(\n", - " messages, self.token_threshold, self.message_threshold, self.keep_recent\n", - " )\n", - "\n", - " async def summarize_conversation(\n", - " self, messages: List[ConversationMessage]\n", - " ) -> ConversationMessage:\n", - " \"\"\"Create intelligent summary of conversation messages.\"\"\"\n", - " return await create_summary(messages, self.llm)\n", - "\n", - " async def compress_conversation(\n", - " self, messages: List[ConversationMessage]\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Compress conversation by summarizing old messages and keeping recent ones.\"\"\"\n", - " return await compress_conversation(\n", - " messages,\n", - " self.llm,\n", - " self.token_threshold,\n", - " self.message_threshold,\n", - " self.keep_recent,\n", - " )\n", - "\n", - "\n", - "print(\n", - " \"\"\"✅ Summarization system built:\n", - " - ConversationMessage dataclass\n", - " - should_summarize() function\n", - " - Summarization prompt template\n", - " - create_summary() function\n", - " - compress_conversation() function\n", - " - ConversationSummarizer class\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "beb98376eb2b00b0", - "metadata": {}, - "source": [ - "### Demo 3: Test Summarization\n", - "\n", - "Let's test the summarizer with a sample conversation.\n", - "\n", - "#### Step 1: Create a sample conversation\n", - "\n", - "**What:** Creating a realistic 14-message conversation about course planning.\n", - "\n", - "**Why:** We need a conversation long enough to trigger summarization (>10 messages, >500 tokens) so we can see the compression in action.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "3e63fdaf5a2a2587", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.672521Z", - "iopub.status.busy": "2025-12-09T19:50:44.672461Z", - "iopub.status.idle": "2025-12-09T19:50:44.675181Z", - "shell.execute_reply": "2025-12-09T19:50:44.674822Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original conversation:\n", - " Messages: 16\n", - " Total tokens: 261\n", - " Average tokens per message: 16.3\n" - ] - } - ], - "source": [ - "# Create a sample long conversation\n", - "sample_conversation = [\n", - " ConversationMessage(\n", - " \"user\", \"Hi, I'm interested in learning about machine learning courses\"\n", - " ),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"Great! Redis University offers several ML courses. CS401 Machine Learning is our flagship course. It covers supervised learning, neural networks, and practical applications.\",\n", - " ),\n", - " ConversationMessage(\"user\", \"What are the prerequisites for CS401?\"),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"CS401 requires CS201 Data Structures and MATH301 Linear Algebra. Have you completed these courses?\",\n", - " ),\n", - " ConversationMessage(\"user\", \"I've completed CS101 but not CS201 yet\"),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"Perfect! CS201 is the next logical step. It covers algorithms and data structures essential for ML. It's offered every semester.\",\n", - " ),\n", - " ConversationMessage(\"user\", \"How difficult is MATH301?\"),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"MATH301 is moderately challenging. It covers vectors, matrices, and eigenvalues used in ML algorithms. Most students find it manageable with consistent practice.\",\n", - " ),\n", - " ConversationMessage(\"user\", \"Can I take both CS201 and MATH301 together?\"),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"Yes, that's a good combination! They complement each other well. Many students take them concurrently.\",\n", - " ),\n", - " ConversationMessage(\"user\", \"What about CS401 after that?\"),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"CS401 is perfect after completing both prerequisites. It's our most popular AI course with hands-on projects.\",\n", - " ),\n", - " ConversationMessage(\"user\", \"When is CS401 offered?\"),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"CS401 is offered in Fall and Spring semesters. The Fall section typically fills up quickly, so register early!\",\n", - " ),\n", - " ConversationMessage(\"user\", \"Great! What's the workload like?\"),\n", - " ConversationMessage(\n", - " \"assistant\",\n", - " \"CS401 requires about 10-12 hours per week including lectures, assignments, and projects. There are 4 major projects throughout the semester.\",\n", - " ),\n", - "]\n", - "\n", - "# Calculate original metrics\n", - "original_token_count = sum(msg.token_count for msg in sample_conversation)\n", - "print(f\"Original conversation:\")\n", - "print(f\" Messages: {len(sample_conversation)}\")\n", - "print(f\" Total tokens: {original_token_count}\")\n", - "print(\n", - " f\" Average tokens per message: {original_token_count / len(sample_conversation):.1f}\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "b824592502d5305", - "metadata": {}, - "source": [ - "#### Step 2: Configure the summarizer\n", - "\n", - "**What:** Setting up the `ConversationSummarizer` with specific thresholds.\n", - "\n", - "**Why:** We use a low token threshold (500) to force summarization on our sample conversation. In production, you'd use higher thresholds (2000-4000 tokens).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "1f1cd42e5cb65a39", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.676169Z", - "iopub.status.busy": "2025-12-09T19:50:44.676113Z", - "iopub.status.idle": "2025-12-09T19:50:44.677852Z", - "shell.execute_reply": "2025-12-09T19:50:44.677482Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Summarizer configuration:\n", - " Token threshold: 500\n", - " Message threshold: 10\n", - " Keep recent: 4\n" - ] - } - ], - "source": [ - "# Test summarization\n", - "summarizer = ConversationSummarizer(\n", - " llm=llm,\n", - " token_threshold=500, # Low threshold for demo\n", - " message_threshold=10,\n", - " keep_recent=4,\n", - ")\n", - "\n", - "print(f\"Summarizer configuration:\")\n", - "print(f\" Token threshold: {summarizer.token_threshold}\")\n", - "print(f\" Message threshold: {summarizer.message_threshold}\")\n", - "print(f\" Keep recent: {summarizer.keep_recent}\")" - ] - }, - { - "cell_type": "markdown", - "id": "ce7b283d8917e353", - "metadata": {}, - "source": [ - "#### Step 3: Check if summarization is needed\n", - "\n", - "**What:** Testing the `should_summarize()` logic.\n", - "\n", - "**Why:** Before compressing, we verify that our conversation actually exceeds the thresholds. This demonstrates the decision logic in action.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "96d60c07d558dbe2", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.678751Z", - "iopub.status.busy": "2025-12-09T19:50:44.678693Z", - "iopub.status.idle": "2025-12-09T19:50:44.680396Z", - "shell.execute_reply": "2025-12-09T19:50:44.679979Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Should summarize? True\n" - ] - } - ], - "source": [ - "# Check if summarization is needed\n", - "should_summarize_result = summarizer.should_summarize(sample_conversation)\n", - "print(f\"Should summarize? {should_summarize_result}\")" - ] - }, - { - "cell_type": "markdown", - "id": "956554c8c979d1a4", - "metadata": {}, - "source": [ - "#### Step 4: Compress the conversation\n", - "\n", - "**What:** Running the full compression pipeline: summarize old messages, keep recent ones.\n", - "\n", - "**Why:** This is the core functionality - transforming 14 messages into a summary + 4 recent messages, dramatically reducing token count while preserving key information.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "3566e3ee779cc9b6", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:44.681342Z", - "iopub.status.busy": "2025-12-09T19:50:44.681280Z", - "iopub.status.idle": "2025-12-09T19:50:50.689431Z", - "shell.execute_reply": "2025-12-09T19:50:50.688710Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After summarization:\n", - " Messages: 5\n", - " Total tokens: 302\n", - " Token savings: -41 (-15.7%)\n" - ] - } - ], - "source": [ - "# Compress the conversation\n", - "compressed = await summarizer.compress_conversation(sample_conversation)\n", - "\n", - "compressed_token_count = sum(msg.token_count for msg in compressed)\n", - "token_savings = original_token_count - compressed_token_count\n", - "savings_percentage = (token_savings / original_token_count) * 100\n", - "\n", - "print(f\"After summarization:\")\n", - "print(f\" Messages: {len(compressed)}\")\n", - "print(f\" Total tokens: {compressed_token_count}\")\n", - "print(f\" Token savings: {token_savings} ({savings_percentage:.1f}%)\")" - ] - }, - { - "cell_type": "markdown", - "id": "ee85f81eedf9cae1", - "metadata": {}, - "source": [ - "#### Step 5: Examine the compressed conversation structure\n" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "82e6fb297080ad8", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.691946Z", - "iopub.status.busy": "2025-12-09T19:50:50.691756Z", - "iopub.status.idle": "2025-12-09T19:50:50.695061Z", - "shell.execute_reply": "2025-12-09T19:50:50.694463Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Compressed conversation structure:\n", - " 1. 📋 [system] [CONVERSATION SUMMARY] - **Key Decisions Made:** - The student decided to enro...\n", - " Tokens: 238\n", - " 2. 👤 [user] When is CS401 offered?...\n", - " Tokens: 6\n", - " 3. 🤖 [assistant] CS401 is offered in Fall and Spring semesters. The Fall section typically fills ...\n", - " Tokens: 22\n", - " 4. 👤 [user] Great! What's the workload like?...\n", - " Tokens: 7\n", - " 5. 🤖 [assistant] CS401 requires about 10-12 hours per week including lectures, assignments, and p...\n", - " Tokens: 29\n" - ] - } - ], - "source": [ - "print(\"Compressed conversation structure:\")\n", - "for i, msg in enumerate(compressed):\n", - " role_icon = \"📋\" if msg.role == \"system\" else \"👤\" if msg.role == \"user\" else \"🤖\"\n", - " content_preview = msg.content[:80].replace(\"\\n\", \" \")\n", - " print(f\" {i+1}. {role_icon} [{msg.role}] {content_preview}...\")\n", - " print(f\" Tokens: {msg.token_count}\")" - ] - }, - { - "cell_type": "markdown", - "id": "4cb252a2997a22ba", - "metadata": {}, - "source": [ - "#### Results Analysis\n", - "\n", - "**What happened:**\n", - "- Original: 16 messages with ~{original_token_count} tokens\n", - "- Compressed: {len(compressed)} messages (1 summary + 4 recent)\n", - "- Savings: ~{savings_percentage:.0f}% token reduction\n", - "\n", - "**Key benefits:**\n", - "- Preserved recent context (last 4 messages)\n", - "- Summarized older messages into key facts\n", - "- Maintained conversation continuity\n", - "- Reduced token usage significantly\n" - ] - }, - { - "cell_type": "markdown", - "id": "a896bce27c392ee9", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🔧 Part 3: Context Compression Strategies\n", - "\n", - "In Part 2, we built a complete summarization system using LLMs to compress conversation history. But summarization isn't the only way to manage context - and it's not always optimal.\n", - "\n", - "Let's explore **four different compression strategies** and understand when to use each one:\n", - "\n", - "1. **Truncation** - Token-aware, keeps recent messages within budget\n", - "2. **Sliding Window** - Message-aware, maintains fixed window size\n", - "3. **Priority-Based** - Intelligent selection without LLM calls\n", - "4. **Summarization** - High quality compression using LLM (from Part 2)\n", - "\n", - "Each strategy has different trade-offs in **speed**, **quality**, and **resource usage**. By the end of this part, you'll know how to choose the right strategy for your use case.\n" - ] - }, - { - "cell_type": "markdown", - "id": "bbe2737aeb03474", - "metadata": {}, - "source": [ - "### Theory: Four Compression Approaches\n", - "\n", - "Let's explore four different strategies, each with different trade-offs:\n", - "\n", - "**1. Truncation (Token-Aware)**\n", - "- Keep recent messages within token budget\n", - "- ✅ Pros: Fast, no LLM calls, respects context limits\n", - "- ❌ Cons: Variable message count, loses old context\n", - "- **Best for:** Token-constrained applications, API limits\n", - "\n", - "**2. Sliding Window (Message-Aware)**\n", - "- Keep exactly N most recent messages\n", - "- ✅ Pros: Fastest, predictable count, constant memory\n", - "- ❌ Cons: May exceed token limits, loses old context\n", - "- **Best for:** Fixed-size buffers, real-time chat\n", - "\n", - "**3. Priority-Based (Balanced)**\n", - "- Score messages by importance, keep highest-scoring\n", - "- ✅ Pros: Preserves important context, no LLM calls\n", - "- ❌ Cons: Requires good scoring logic, may lose temporal flow\n", - "- **Best for:** Production applications needing balance\n", - "\n", - "**4. Summarization (High Quality)**\n", - "- Use LLM to create intelligent summaries\n", - "- ✅ Pros: Preserves meaning, high quality\n", - "- ❌ Cons: Slower, requires LLM call, uses additional tokens (cost/latency trade-off)\n", - "- **Best for:** High-value conversations, quality-critical applications\n" - ] - }, - { - "cell_type": "markdown", - "id": "2bb5f28d6ed343f6", - "metadata": {}, - "source": [ - "### Building Compression Strategies Step-by-Step\n", - "\n", - "Let's build each strategy incrementally, starting with the simplest.\n", - "\n", - "#### Step 1: Define a base interface for compression strategies\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "7b053a7b2c242989", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.697726Z", - "iopub.status.busy": "2025-12-09T19:50:50.697553Z", - "iopub.status.idle": "2025-12-09T19:50:50.700367Z", - "shell.execute_reply": "2025-12-09T19:50:50.699756Z" - } - }, - "outputs": [], - "source": [ - "class CompressionStrategy:\n", - " \"\"\"Base class for compression strategies.\"\"\"\n", - "\n", - " def compress(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Compress messages to fit within max_tokens.\"\"\"\n", - " raise NotImplementedError" - ] - }, - { - "cell_type": "markdown", - "id": "e23ab8bf105c70aa", - "metadata": {}, - "source": [ - "#### Step 2: Implement Truncation Strategy (Simplest)\n", - "\n", - "This strategy simply keeps the most recent messages that fit within the token budget.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "cf8c2576cad8bfc4", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.702217Z", - "iopub.status.busy": "2025-12-09T19:50:50.702079Z", - "iopub.status.idle": "2025-12-09T19:50:50.704996Z", - "shell.execute_reply": "2025-12-09T19:50:50.704336Z" - } - }, - "outputs": [], - "source": [ - "class TruncationStrategy(CompressionStrategy):\n", - " \"\"\"Keep only the most recent messages within token budget.\"\"\"\n", - "\n", - " def compress(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Keep most recent messages within token budget.\"\"\"\n", - " compressed = []\n", - " total_tokens = 0\n", - "\n", - " # Work backwards from most recent\n", - " for msg in reversed(messages):\n", - " if total_tokens + msg.token_count <= max_tokens:\n", - " compressed.insert(0, msg)\n", - " total_tokens += msg.token_count\n", - " else:\n", - " break\n", - "\n", - " return compressed" - ] - }, - { - "cell_type": "markdown", - "id": "8fcd84d939f70075", - "metadata": {}, - "source": [ - "#### Step 2.5: Implement Sliding Window Strategy (Simplest)\n", - "\n", - "**What we're building:** A strategy that maintains a fixed-size window of the N most recent messages.\n", - "\n", - "**Why it's different from truncation:**\n", - "- **Truncation:** Reactive - keeps messages until token budget exceeded, then removes oldest\n", - "- **Sliding Window:** Proactive - always maintains exactly N messages regardless of tokens\n", - "\n", - "**When to use:**\n", - "- Real-time chat where you want constant context size\n", - "- Systems with predictable message patterns\n", - "- When simplicity matters more than token optimization\n", - "\n", - "**Trade-off:** May exceed token limits if messages are very long.\n", - "\n", - "**How it works:** Simply returns the last N messages using Python list slicing (`messages[-N:]`).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "a683df2353cdfdc4", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.706367Z", - "iopub.status.busy": "2025-12-09T19:50:50.706243Z", - "iopub.status.idle": "2025-12-09T19:50:50.709049Z", - "shell.execute_reply": "2025-12-09T19:50:50.708423Z" - } - }, - "outputs": [], - "source": [ - "class SlidingWindowStrategy(CompressionStrategy):\n", - " \"\"\"Keep only the last N messages (fixed window size).\"\"\"\n", - "\n", - " def __init__(self, window_size: int = 10):\n", - " \"\"\"\n", - " Initialize sliding window strategy.\n", - "\n", - " Args:\n", - " window_size: Number of recent messages to keep\n", - " \"\"\"\n", - " self.window_size = window_size\n", - "\n", - " def compress(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"\n", - " Keep only the last N messages.\n", - "\n", - " Note: Ignores max_tokens parameter - always keeps exactly window_size messages.\n", - " \"\"\"\n", - " if len(messages) <= self.window_size:\n", - " return messages\n", - "\n", - " return messages[-self.window_size :]" - ] - }, - { - "cell_type": "markdown", - "id": "42299c4601c4f31a", - "metadata": {}, - "source": [ - "#### Step 3: Implement Priority-Based Strategy (Intelligent Selection)\n", - "\n", - "This strategy scores messages by importance and keeps the highest-scoring ones.\n", - "\n", - "First, let's create a function to calculate message importance:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "739168f3fa76a165", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.710510Z", - "iopub.status.busy": "2025-12-09T19:50:50.710387Z", - "iopub.status.idle": "2025-12-09T19:50:50.713262Z", - "shell.execute_reply": "2025-12-09T19:50:50.712870Z" - } - }, - "outputs": [], - "source": [ - "def calculate_message_importance(msg: ConversationMessage) -> float:\n", - " \"\"\"\n", - " Calculate importance score for a message.\n", - "\n", - " Higher scores = more important.\n", - " \"\"\"\n", - " score = 0.0\n", - " content_lower = msg.content.lower()\n", - "\n", - " # Course codes are important (CS401, MATH301, etc.)\n", - " if any(code in content_lower for code in [\"cs\", \"math\", \"eng\"]):\n", - " score += 2.0\n", - "\n", - " # Questions are important\n", - " if \"?\" in msg.content:\n", - " score += 1.5\n", - "\n", - " # Prerequisites and requirements are important\n", - " if any(word in content_lower for word in [\"prerequisite\", \"require\", \"need\"]):\n", - " score += 1.5\n", - "\n", - " # Preferences and goals are important\n", - " if any(word in content_lower for word in [\"prefer\", \"want\", \"goal\", \"interested\"]):\n", - " score += 1.0\n", - "\n", - " # User messages slightly more important (their needs)\n", - " if msg.role == \"user\":\n", - " score += 0.5\n", - "\n", - " # Longer messages often have more content\n", - " if msg.token_count > 50:\n", - " score += 0.5\n", - "\n", - " return score" - ] - }, - { - "cell_type": "markdown", - "id": "c1d3e19b190c9e3c", - "metadata": {}, - "source": [ - "Now let's create the Priority-Based strategy class:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "f66e696bacf5a96a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.714822Z", - "iopub.status.busy": "2025-12-09T19:50:50.714717Z", - "iopub.status.idle": "2025-12-09T19:50:50.717734Z", - "shell.execute_reply": "2025-12-09T19:50:50.717235Z" - } - }, - "outputs": [], - "source": [ - "class PriorityBasedStrategy(CompressionStrategy):\n", - " \"\"\"Keep highest-priority messages within token budget.\"\"\"\n", - "\n", - " def calculate_importance(self, msg: ConversationMessage) -> float:\n", - " \"\"\"Calculate importance score for a message.\"\"\"\n", - " return calculate_message_importance(msg)\n", - "\n", - " def compress(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Keep highest-priority messages within token budget.\"\"\"\n", - " # Score each message\n", - " scored_messages = [\n", - " (self.calculate_importance(msg), i, msg) for i, msg in enumerate(messages)\n", - " ]\n", - "\n", - " # Sort by score (descending), then by index to maintain some order\n", - " scored_messages.sort(key=lambda x: (-x[0], x[1]))\n", - "\n", - " # Select messages within budget\n", - " selected = []\n", - " total_tokens = 0\n", - "\n", - " for score, idx, msg in scored_messages:\n", - " if total_tokens + msg.token_count <= max_tokens:\n", - " selected.append((idx, msg))\n", - " total_tokens += msg.token_count\n", - "\n", - " # Sort by original index to maintain conversation flow\n", - " selected.sort(key=lambda x: x[0])\n", - "\n", - " return [msg for idx, msg in selected]" - ] - }, - { - "cell_type": "markdown", - "id": "57f0400bdab30655", - "metadata": {}, - "source": [ - "#### Step 4: Wrap Summarization Strategy (Already Built in Part 2)\n", - "\n", - "**What we're doing:** Creating a `SummarizationStrategy` wrapper around the `ConversationSummarizer` we built in Part 2.\n", - "\n", - "**Why wrap it:** To make it compatible with the `CompressionStrategy` interface so we can compare it fairly with the other strategies in Demo 4.\n", - "\n", - "**Note:** We're not rebuilding summarization - we're just adapting what we already built to work alongside truncation, sliding window, and priority-based strategies. This is the adapter pattern in action.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "4c0fa64ab406ef95", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.718998Z", - "iopub.status.busy": "2025-12-09T19:50:50.718917Z", - "iopub.status.idle": "2025-12-09T19:50:50.721583Z", - "shell.execute_reply": "2025-12-09T19:50:50.721097Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Compression strategies implemented:\n", - " - CompressionStrategy base class\n", - " - TruncationStrategy (token-aware)\n", - " - SlidingWindowStrategy (message-aware)\n", - " - PriorityBasedStrategy (intelligent selection)\n", - " - SummarizationStrategy (LLM-based)\n" - ] - } - ], - "source": [ - "class SummarizationStrategy(CompressionStrategy):\n", - " \"\"\"Use LLM to create intelligent summaries.\"\"\"\n", - "\n", - " def __init__(self, summarizer: ConversationSummarizer):\n", - " self.summarizer = summarizer\n", - "\n", - " async def compress_async(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Compress using summarization (async).\"\"\"\n", - " # Use the summarizer's logic\n", - " return await self.summarizer.compress_conversation(messages)\n", - "\n", - " def compress(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Synchronous wrapper (not recommended, use compress_async).\"\"\"\n", - " raise NotImplementedError(\"Use compress_async for summarization strategy\")\n", - "\n", - "\n", - "print(\n", - " \"\"\"✅ Compression strategies implemented:\n", - " - CompressionStrategy base class\n", - " - TruncationStrategy (token-aware)\n", - " - SlidingWindowStrategy (message-aware)\n", - " - PriorityBasedStrategy (intelligent selection)\n", - " - SummarizationStrategy (LLM-based)\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "1d0ddde791c5afc", - "metadata": {}, - "source": [ - "### Demo 4: Compare Compression Strategies\n", - "\n", - "Let's compare all four strategies on the same conversation to understand their trade-offs.\n", - "\n", - "#### Step 1: Set up the test\n", - "\n", - "**What:** Establishing baseline metrics for our comparison.\n", - "\n", - "**Why:** We need to know the original size (messages and tokens) to measure how much each strategy compresses and what information is preserved or lost.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "22b54c30ef8be4a8", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.722811Z", - "iopub.status.busy": "2025-12-09T19:50:50.722731Z", - "iopub.status.idle": "2025-12-09T19:50:50.724810Z", - "shell.execute_reply": "2025-12-09T19:50:50.724362Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original conversation: 16 messages, 261 tokens\n", - "Target budget: 800 tokens\n", - "\n" - ] - } - ], - "source": [ - "# Use the same sample conversation from before\n", - "test_conversation = sample_conversation.copy()\n", - "max_tokens = 800 # Target token budget\n", - "\n", - "original_tokens = sum(msg.token_count for msg in test_conversation)\n", - "print(\n", - " f\"\"\"Original conversation: {len(test_conversation)} messages, {original_tokens} tokens\n", - "Target budget: {max_tokens} tokens\n", - "\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "96dac15eec962562", - "metadata": {}, - "source": [ - "#### Step 2: Test Truncation Strategy\n", - "\n", - "**What:** Testing token-aware compression that keeps recent messages within budget.\n", - "\n", - "**Why:** Demonstrates how truncation guarantees staying under token limits by working backwards from the most recent message.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "be20f6779afc21e9", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.725988Z", - "iopub.status.busy": "2025-12-09T19:50:50.725915Z", - "iopub.status.idle": "2025-12-09T19:50:50.728167Z", - "shell.execute_reply": "2025-12-09T19:50:50.727763Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TRUNCATION STRATEGY\n", - " Result: 16 messages, 261 tokens\n", - " Savings: 0 tokens\n", - " Kept messages: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]\n" - ] - } - ], - "source": [ - "truncation = TruncationStrategy()\n", - "truncated = truncation.compress(test_conversation, max_tokens)\n", - "truncated_tokens = sum(msg.token_count for msg in truncated)\n", - "\n", - "print(f\"TRUNCATION STRATEGY\")\n", - "print(f\" Result: {len(truncated)} messages, {truncated_tokens} tokens\")\n", - "print(f\" Savings: {original_tokens - truncated_tokens} tokens\")\n", - "print(\n", - " f\" Kept messages: {[i for i, msg in enumerate(test_conversation) if msg in truncated]}\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "d8dfbdc40403d640", - "metadata": {}, - "source": [ - "#### Step 2.5: Test Sliding Window Strategy\n", - "\n", - "**What:** Testing message-aware compression that keeps exactly N recent messages.\n", - "\n", - "**Why:** Shows how sliding window prioritizes predictability (always 6 messages) over token optimization (may exceed budget).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "4018ee04019c9a9a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.729330Z", - "iopub.status.busy": "2025-12-09T19:50:50.729255Z", - "iopub.status.idle": "2025-12-09T19:50:50.731784Z", - "shell.execute_reply": "2025-12-09T19:50:50.731315Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SLIDING WINDOW STRATEGY\n", - " Result: 6 messages, 91 tokens\n", - " Savings: 170 tokens\n", - " Kept messages: [10, 11, 12, 13, 14, 15]\n", - " Token budget: 91/800 (within limit)\n" - ] - } - ], - "source": [ - "sliding_window = SlidingWindowStrategy(window_size=6)\n", - "windowed = sliding_window.compress(test_conversation, max_tokens)\n", - "windowed_tokens = sum(msg.token_count for msg in windowed)\n", - "\n", - "print(f\"SLIDING WINDOW STRATEGY\")\n", - "print(f\" Result: {len(windowed)} messages, {windowed_tokens} tokens\")\n", - "print(f\" Savings: {original_tokens - windowed_tokens} tokens\")\n", - "print(\n", - " f\" Kept messages: {[i for i, msg in enumerate(test_conversation) if msg in windowed]}\"\n", - ")\n", - "print(\n", - " f\" Token budget: {windowed_tokens}/{max_tokens} ({'within' if windowed_tokens <= max_tokens else 'EXCEEDS'} limit)\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "529392dfaf6dbe64", - "metadata": {}, - "source": [ - "**Analysis:**\n", - "\n", - "The sliding window kept:\n", - "- **Exactly 6 messages** (last 6 from the conversation)\n", - "- **Most recent context only** (indices show the final messages)\n", - "- **{windowed_tokens} tokens** (may or may not fit budget)\n", - "\n", - "**Key difference from truncation:**\n", - "- **Truncation:** Kept {len(truncated)} messages to stay under {max_tokens} tokens\n", - "- **Sliding Window:** Kept exactly 6 messages, resulting in {windowed_tokens} tokens\n", - "\n", - "**Behavior pattern:**\n", - "- Truncation: \"Fill the budget\" → Variable count, guaranteed fit\n", - "- Sliding Window: \"Fixed window\" → Constant count, may exceed budget\n" - ] - }, - { - "cell_type": "markdown", - "id": "69267d84d68c7376", - "metadata": {}, - "source": [ - "#### Step 3: Test Priority-Based Strategy\n", - "\n", - "**What:** Testing intelligent selection that scores messages by importance.\n", - "\n", - "**Why:** Demonstrates how priority-based compression preserves high-value messages (questions, course codes, requirements) while staying within budget - no LLM needed.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "c0b2ce7a958fbe9d", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.732945Z", - "iopub.status.busy": "2025-12-09T19:50:50.732870Z", - "iopub.status.idle": "2025-12-09T19:50:50.735090Z", - "shell.execute_reply": "2025-12-09T19:50:50.734664Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PRIORITY-BASED STRATEGY\n", - " Result: 16 messages, 261 tokens\n", - " Savings: 0 tokens\n", - " Kept messages: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]\n" - ] - } - ], - "source": [ - "priority = PriorityBasedStrategy()\n", - "prioritized = priority.compress(test_conversation, max_tokens)\n", - "prioritized_tokens = sum(msg.token_count for msg in prioritized)\n", - "\n", - "print(f\"PRIORITY-BASED STRATEGY\")\n", - "print(f\" Result: {len(prioritized)} messages, {prioritized_tokens} tokens\")\n", - "print(f\" Savings: {original_tokens - prioritized_tokens} tokens\")\n", - "print(\n", - " f\" Kept messages: {[i for i, msg in enumerate(test_conversation) if msg in prioritized]}\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "fed34b703bb9c7d9", - "metadata": {}, - "source": [ - "Let's examine which messages were selected and why:\n", - "\n", - "**What:** Inspecting the importance scores assigned to different messages.\n", - "\n", - "**Why:** Understanding the scoring logic helps you tune it for your domain (e.g., legal terms, medical codes, customer names).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "134971d1108034c4", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.736179Z", - "iopub.status.busy": "2025-12-09T19:50:50.736112Z", - "iopub.status.idle": "2025-12-09T19:50:50.738132Z", - "shell.execute_reply": "2025-12-09T19:50:50.737699Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sample importance scores:\n", - " Message 0: 1.5 - \"Hi, I'm interested in learning about machine learn...\"\n", - " Message 2: 5.5 - \"What are the prerequisites for CS401?...\"\n", - " Message 4: 2.5 - \"I've completed CS101 but not CS201 yet...\"\n", - " Message 6: 4.0 - \"How difficult is MATH301?...\"\n" - ] - } - ], - "source": [ - "# Show importance scores for selected messages\n", - "print(\"Sample importance scores:\")\n", - "for i in [0, 2, 4, 6]:\n", - " if i < len(test_conversation):\n", - " score = priority.calculate_importance(test_conversation[i])\n", - " preview = test_conversation[i].content[:50]\n", - " print(f' Message {i}: {score:.1f} - \"{preview}...\"')" - ] - }, - { - "cell_type": "markdown", - "id": "e310f0458261b9a8", - "metadata": {}, - "source": [ - "#### Step 4: Test Summarization Strategy\n", - "\n", - "**What:** Testing LLM-based compression using the summarizer from Part 2.\n", - "\n", - "**Why:** Shows the highest-quality compression - preserves meaning and context but requires an API call. This is the gold standard for quality, but comes with added latency.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "997bc235a9b3038b", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:50.739215Z", - "iopub.status.busy": "2025-12-09T19:50:50.739149Z", - "iopub.status.idle": "2025-12-09T19:50:56.362916Z", - "shell.execute_reply": "2025-12-09T19:50:56.361183Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SUMMARIZATION STRATEGY\n", - " Result: 5 messages, 304 tokens\n", - " Savings: -43 tokens\n", - " Structure: 1 summary + 4 recent messages\n" - ] - } - ], - "source": [ - "summarization = SummarizationStrategy(summarizer)\n", - "summarized = await summarization.compress_async(test_conversation, max_tokens)\n", - "summarized_tokens = sum(msg.token_count for msg in summarized)\n", - "\n", - "print(f\"SUMMARIZATION STRATEGY\")\n", - "print(f\" Result: {len(summarized)} messages, {summarized_tokens} tokens\")\n", - "print(f\" Savings: {original_tokens - summarized_tokens} tokens\")\n", - "print(f\" Structure: 1 summary + {len(summarized) - 1} recent messages\")" - ] - }, - { - "cell_type": "markdown", - "id": "eb0f2653b2c4e89b", - "metadata": {}, - "source": [ - "#### Step 5: Compare all strategies\n", - "\n", - "**What:** Side-by-side comparison of all four strategies on the same conversation.\n", - "\n", - "**Why:** Seeing the trade-offs in a table makes it clear: truncation/sliding window are fast but lose context, priority-based balances both, summarization preserves most but requires additional processing.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "47b36cc71717932b", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:56.367095Z", - "iopub.status.busy": "2025-12-09T19:50:56.366771Z", - "iopub.status.idle": "2025-12-09T19:50:56.372697Z", - "shell.execute_reply": "2025-12-09T19:50:56.371812Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "COMPARISON SUMMARY\n", - "================================================================================\n", - "Strategy Messages Tokens Savings Quality\n", - "--------------------------------------------------------------------------------\n", - "Original 16 261 0 N/A\n", - "Truncation 16 261 0 Low\n", - "Sliding Window 6 91 170 (65%) Low\n", - "Priority-Based 16 261 0 Medium\n", - "Summarization 5 304 -43 High\n" - ] - } - ], - "source": [ - "print(\"COMPARISON SUMMARY\")\n", - "print(\"=\" * 80)\n", - "print(f\"{'Strategy':<20} {'Messages':<12} {'Tokens':<12} {'Savings':<12} {'Quality'}\")\n", - "print(\"-\" * 80)\n", - "\n", - "strategies = [\n", - " (\"Original\", len(test_conversation), original_tokens, 0, \"N/A\"),\n", - " (\n", - " \"Truncation\",\n", - " len(truncated),\n", - " truncated_tokens,\n", - " original_tokens - truncated_tokens,\n", - " \"Low\",\n", - " ),\n", - " (\n", - " \"Sliding Window\",\n", - " len(windowed),\n", - " windowed_tokens,\n", - " original_tokens - windowed_tokens,\n", - " \"Low\",\n", - " ),\n", - " (\n", - " \"Priority-Based\",\n", - " len(prioritized),\n", - " prioritized_tokens,\n", - " original_tokens - prioritized_tokens,\n", - " \"Medium\",\n", - " ),\n", - " (\n", - " \"Summarization\",\n", - " len(summarized),\n", - " summarized_tokens,\n", - " original_tokens - summarized_tokens,\n", - " \"High\",\n", - " ),\n", - "]\n", - "\n", - "for name, msgs, tokens, savings, quality in strategies:\n", - " savings_pct = f\"({savings/original_tokens*100:.0f}%)\" if savings > 0 else \"\"\n", - " print(f\"{name:<20} {msgs:<12} {tokens:<12} {savings:<5} {savings_pct:<6} {quality}\")" - ] - }, - { - "cell_type": "markdown", - "id": "bfe7c056c978aea4", - "metadata": {}, - "source": [ - "### Understanding the Trade-offs: Why Summarization Isn't Always Optimal\n", - "\n", - "Now that we've seen all four strategies in action, let's understand when each one shines and when it falls short.\n", - "\n", - "**Summarization's Trade-offs:**\n", - "\n", - "While summarization provides the highest quality compression, it introduces constraints:\n", - "\n", - "1. **Latency:** Requires LLM API call (1-3 seconds vs. <10ms for other strategies)\n", - "2. **Lossy:** Paraphrases content, doesn't preserve exact wording\n", - "3. **Complexity:** Requires async operations, prompt engineering, error handling\n", - "4. **Resource Usage:** Extra API calls at scale (1,000 conversations/day = 1,000+ LLM calls with associated costs)\n", - "\n", - "**When to Use Alternatives:**\n", - "\n", - "| Scenario | Better Strategy | Why |\n", - "|----------|----------------|-----|\n", - "| Real-time chat | Truncation/Sliding Window | Zero latency |\n", - "| Verbatim accuracy required | Truncation | Preserves exact wording |\n", - "| Predictable context size | Sliding Window | Fixed message count |\n", - "| High-volume applications | Priority-based | No API calls needed |\n", - "\n", - "See the Key Takeaways below for the complete decision framework." - ] - }, - { - "cell_type": "markdown", - "id": "6ebd894c5ffdfff", - "metadata": {}, - "source": [ - "#### Key Takeaways\n", - "\n", - "**Truncation (Token-Aware):**\n", - "- Keeps messages within token budget\n", - "- Variable message count, guaranteed under limit\n", - "- Good for: API token limits, predictable resource usage and costs\n", - "\n", - "**Sliding Window (Message-Aware):**\n", - "- Keeps exactly N most recent messages\n", - "- Fixed message count, may exceed token budget\n", - "- Good for: Real-time chat, predictable context size\n", - "\n", - "**Priority-Based (Intelligent):**\n", - "- Scores and keeps important messages\n", - "- Preserves key information across conversation\n", - "- Good for: Most production applications, balanced approach\n", - "\n", - "**Summarization (Highest Quality):**\n", - "- Uses LLM to preserve meaning\n", - "- Highest quality, but requires API call (added latency and cost)\n", - "- Good for: High-value conversations, support tickets, advisory sessions\n", - "\n", - "**Decision Framework:**\n", - "- **Speed-critical** → Truncation or Sliding Window (instant, no LLM)\n", - "- **Quality-critical** → Summarization (preserves meaning, worth the cost)\n", - "- **Balanced needs** → Priority-Based (intelligent, no API calls)\n", - "- **Predictable context** → Sliding Window (constant message count)\n" - ] - }, - { - "cell_type": "markdown", - "id": "dca23d0020c84249", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🔄 Part 4: Agent Memory Server Integration\n", - "\n", - "The Agent Memory Server provides automatic summarization. Let's configure and test it.\n" - ] - }, - { - "cell_type": "markdown", - "id": "8ca0c2b93f2cf79e", - "metadata": {}, - "source": [ - "### 🔧 Theory: Automatic Memory Management\n", - "\n", - "As we learned in Notebook 01, the Agent Memory Server provides automatic memory management with configurable compression strategies.\n", - "\n", - "**Agent Memory Server Features:**\n", - "- ✅ Automatic summarization when thresholds are exceeded\n", - "- ✅ Configurable strategies (recent + summary, sliding window, full summary)\n", - "- ✅ Transparent to your application code\n", - "- ✅ Production-ready and scalable\n", - "\n", - "**How It Works:**\n", - "1. You add messages to working memory normally\n", - "2. Server monitors message count and token count\n", - "3. When threshold is exceeded, server automatically summarizes\n", - "4. Old messages are replaced with summary\n", - "5. Recent messages are kept for context\n", - "6. Your application retrieves the compressed memory\n", - "\n", - "**Configuration Options:**\n", - "- `message_threshold`: Summarize after N messages (default: 20)\n", - "- `token_threshold`: Summarize after N tokens (default: 4000)\n", - "- `keep_recent`: Number of recent messages to keep (default: 4)\n", - "- `strategy`: \"recent_plus_summary\", \"sliding_window\", or \"full_summary\"" - ] - }, - { - "cell_type": "markdown", - "id": "d585948b56598a9f", - "metadata": {}, - "source": [ - "### Demo 5: Test Automatic Summarization with Realistic Academic Advising\n", - "\n", - "Let's test the Agent Memory Server's automatic summarization with a realistic, information-dense conversation.\n", - "\n", - "**Real-World Scenario:** This demo simulates an academic advising session where a student asks detailed questions about a course syllabus. This mirrors actual use cases like:\n", - "- Academic advising chatbots answering detailed course questions\n", - "- Customer support agents explaining complex products/services\n", - "- Technical documentation assistants providing in-depth explanations\n", - "- Healthcare chatbots discussing treatment options and medical information\n", - "\n", - "The long, information-dense responses will exceed the 4000 token threshold, triggering automatic summarization.\n", - "\n", - "#### Step 1: Create a test session\n", - "\n", - "**What:** Setting up a unique session ID for testing automatic summarization.\n", - "\n", - "**Why:** Each session has its own working memory. We need a fresh session to observe the Agent Memory Server's automatic compression behavior from scratch.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "de6e6cc74530366a", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:56.375727Z", - "iopub.status.busy": "2025-12-09T19:50:56.375596Z", - "iopub.status.idle": "2025-12-09T19:50:56.378502Z", - "shell.execute_reply": "2025-12-09T19:50:56.377602Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Testing automatic summarization\n", - "Session ID: long_conversation_test_1765309856\n", - "Student ID: student_memory_test\n" - ] - } - ], - "source": [ - "# Create a test session\n", - "test_session_id = f\"long_conversation_test_{int(time.time())}\"\n", - "test_student_id = \"student_memory_test\"\n", - "\n", - "print(\n", - " f\"\"\"Testing automatic summarization\n", - "Session ID: {test_session_id}\n", - "Student ID: {test_student_id}\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "a557dad8d8f53ef0", - "metadata": {}, - "source": [ - "#### Step 2: Create a realistic scenario - Student exploring a detailed course syllabus\n", - "\n", - "**What:** Simulating a real advising session where a student asks detailed questions about the CS401 Machine Learning course syllabus.\n", - "\n", - "**Why:** Real conversations involve long, information-dense responses (course descriptions, prerequisites, project details). This creates enough tokens to trigger automatic summarization while demonstrating a realistic use case.\n", - "\n", - "**Scenario:** A student is considering CS401 and asks progressively deeper questions about the syllabus, prerequisites, projects, grading, and logistics.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "4addd7959de37558", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:56.382326Z", - "iopub.status.busy": "2025-12-09T19:50:56.382085Z", - "iopub.status.idle": "2025-12-09T19:50:56.393021Z", - "shell.execute_reply": "2025-12-09T19:50:56.392447Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Created realistic advising conversation:\n", - " - 11 turns (22 messages)\n", - " - Detailed course syllabus document\n", - " - Progressive depth: overview → prerequisites → projects → logistics → financial aid\n", - " - Long, information-dense responses (realistic for academic advising)\n", - " - Total tokens: 4,795 tokens (threshold: 4,000)\n", - " - Status: ✅ EXCEEDS threshold\n" - ] - } - ], - "source": [ - "# First, let's create a detailed course syllabus (this would typically come from a RAG system)\n", - "cs401_syllabus = \"\"\"\n", - "CS401: Machine Learning - Complete Course Syllabus\n", - "\n", - "COURSE OVERVIEW:\n", - "This comprehensive course covers fundamental and advanced machine learning techniques. Students will learn supervised learning (linear regression, logistic regression, decision trees, random forests, support vector machines), unsupervised learning (k-means clustering, hierarchical clustering, DBSCAN, dimensionality reduction with PCA and t-SNE), neural networks (feedforward networks, backpropagation, activation functions, optimization algorithms), deep learning (convolutional neural networks for computer vision, recurrent neural networks for sequence modeling, LSTMs and GRUs for time series), and natural language processing (word embeddings, transformers, attention mechanisms, BERT, GPT architectures).\n", - "\n", - "PREREQUISITES:\n", - "- CS201 Data Structures and Algorithms (required) - Must understand trees, graphs, dynamic programming, complexity analysis\n", - "- MATH301 Linear Algebra (required) - Matrix operations, eigenvalues, eigenvectors, vector spaces\n", - "- STAT201 Probability and Statistics (recommended) - Probability distributions, hypothesis testing, Bayes' theorem\n", - "- Python programming experience (required) - NumPy, Pandas, Matplotlib\n", - "\n", - "COURSE STRUCTURE:\n", - "- 15 weeks, 3 hours lecture + 2 hours lab per week\n", - "- 4 major projects (40% of grade)\n", - "- Weekly problem sets (20% of grade)\n", - "- Midterm exam (15% of grade)\n", - "- Final exam (20% of grade)\n", - "- Class participation (5% of grade)\n", - "\n", - "PROJECTS:\n", - "Project 1 (Weeks 2-4): Implement linear regression and logistic regression from scratch using only NumPy. Apply to housing price prediction and spam classification datasets.\n", - "\n", - "Project 2 (Weeks 5-7): Build a neural network framework with backpropagation. Implement various activation functions (ReLU, sigmoid, tanh) and optimization algorithms (SGD, Adam, RMSprop). Train on MNIST digit classification.\n", - "\n", - "Project 3 (Weeks 8-11): Develop a convolutional neural network for image classification using TensorFlow/PyTorch. Experiment with different architectures (LeNet, AlexNet, ResNet). Apply transfer learning with pre-trained models. Dataset: CIFAR-10 or custom image dataset.\n", - "\n", - "Project 4 (Weeks 12-15): Natural language processing project - build a sentiment analysis system using transformers. Fine-tune BERT or GPT-2 on movie reviews or social media data. Implement attention visualization and model interpretation techniques.\n", - "\n", - "GRADING SCALE:\n", - "A: 90-100%, B: 80-89%, C: 70-79%, D: 60-69%, F: <60%\n", - "Pass rate: Approximately 85% of students pass on first attempt\n", - "Average grade: B+ (87%)\n", - "\n", - "RESOURCES:\n", - "- Textbook: \"Pattern Recognition and Machine Learning\" by Christopher Bishop\n", - "- Online resources: Coursera ML course, fast.ai, Papers with Code\n", - "- Computing: Google Colab Pro ($10/month) or university GPU cluster access\n", - "- Office hours: 3 TAs available Monday-Friday, 2-5 PM\n", - "- Discussion forum: Active Slack workspace with 200+ students and alumni\n", - "\n", - "SCHEDULE:\n", - "Offered every semester (Fall, Spring, Summer)\n", - "Class times: MWF 10:00-11:30 AM or TTh 2:00-4:00 PM\n", - "Lab sections: Multiple options throughout the week\n", - "Application deadline: 2 months before semester start\n", - "\"\"\"\n", - "\n", - "# Now create a realistic conversation where the student asks detailed questions\n", - "conversation_turns = [\n", - " (\n", - " \"Hi! I'm interested in taking CS401 Machine Learning next semester. Can you give me an overview of what the course covers?\",\n", - " f\"Absolutely! CS401 is our flagship machine learning course. Here's the complete overview:\\n\\n{cs401_syllabus[:500]}...\\n\\nThe course covers everything from foundational algorithms like linear regression to cutting-edge deep learning techniques. You'll work with real datasets and build production-quality ML systems. Would you like to know more about any specific aspect?\",\n", - " ),\n", - " (\n", - " \"That sounds comprehensive! What are the prerequisites? I've completed CS101 Introduction to Programming, but I'm not sure if I'm ready for CS401.\",\n", - " \"Great question! Let me break down the prerequisites for you:\\n\\n**Required Prerequisites:**\\n1. CS201 Data Structures and Algorithms - You'll need strong understanding of trees, graphs, dynamic programming, and complexity analysis. This is essential because ML algorithms often involve complex data structures and you need to understand their performance characteristics.\\n\\n2. MATH301 Linear Algebra - Matrix operations, eigenvalues, eigenvectors, and vector spaces are fundamental to ML. Neural networks are essentially matrix multiplications, and dimensionality reduction techniques like PCA rely heavily on linear algebra.\\n\\n**Recommended Prerequisites:**\\n3. STAT201 Probability and Statistics - Understanding probability distributions, hypothesis testing, and Bayes' theorem will help you grasp why ML algorithms work.\\n\\n4. Python Programming - You should be comfortable with NumPy, Pandas, and Matplotlib.\\n\\nSince you've only completed CS101, you'll need to take CS201 first. Many students take CS201 and MATH301 concurrently, which would prepare you for CS401 in about 4-6 months.\",\n", - " ),\n", - " (\n", - " \"I see. Can you tell me more about the projects? I learn best by doing hands-on work.\",\n", - " \"Excellent! CS401 has 4 major projects that progressively build your skills:\\n\\n**Project 1 (Weeks 2-4): Foundations**\\nYou'll implement linear regression and logistic regression from scratch using only NumPy - no ML libraries allowed! This forces you to understand the math. You'll apply these to real datasets: housing price prediction (regression) and spam classification (classification). This project teaches you the fundamentals of gradient descent and loss functions.\\n\\n**Project 2 (Weeks 5-7): Neural Networks**\\nBuild your own neural network framework with backpropagation. You'll implement various activation functions (ReLU, sigmoid, tanh) and optimization algorithms (SGD, Adam, RMSprop). Then train your network on MNIST digit classification. This is where you really understand how deep learning works under the hood.\\n\\n**Project 3 (Weeks 8-11): Computer Vision**\\nDevelop a convolutional neural network for image classification using TensorFlow or PyTorch. You'll experiment with different architectures (LeNet, AlexNet, ResNet) and apply transfer learning with pre-trained models. Dataset options include CIFAR-10 or you can use a custom dataset. This project shows you how to work with production ML frameworks.\\n\\n**Project 4 (Weeks 12-15): NLP**\\nBuild a sentiment analysis system using transformers. You'll fine-tune BERT or GPT-2 on movie reviews or social media data, implement attention visualization, and use model interpretation techniques. This is the most advanced project and prepares you for real-world NLP applications.\\n\\nEach project takes 2-3 weeks and includes a written report and code submission. Projects are worth 40% of your final grade.\",\n", - " ),\n", - " (\n", - " \"Wow, those projects sound challenging but exciting! What's the workload like? I'm also taking two other courses next semester.\",\n", - " \"That's a very important consideration! CS401 is one of our most intensive courses. Here's what to expect:\\n\\n**Time Commitment:**\\n- Lectures: 3 hours per week (MWF 10:00-11:30 AM or TTh 2:00-4:00 PM)\\n- Lab sections: 2 hours per week (multiple time slots available)\\n- Problem sets: 4-6 hours per week (weekly assignments to reinforce concepts)\\n- Project work: 8-12 hours per week during project periods\\n- Exam preparation: 10-15 hours before midterm and final\\n- Reading and self-study: 3-5 hours per week\\n\\n**Total: 20-25 hours per week on average**, with peaks during project deadlines and exams.\\n\\n**Workload Distribution:**\\n- Weeks 1-2: Lighter (getting started, foundational concepts)\\n- Weeks 3-4, 6-7, 9-11, 13-15: Heavy (project work)\\n- Weeks 5, 8, 12: Moderate (project transitions, exam prep)\\n\\n**Managing with Other Courses:**\\nMost students take 3-4 courses per semester. If your other two courses are also intensive, you might find it challenging. I'd recommend:\\n1. Make sure at least one of your other courses is lighter\\n2. Plan your schedule to avoid deadline conflicts\\n3. Start projects early - don't wait until the last week\\n4. Use office hours and study groups effectively\\n\\nAbout 85% of students pass on their first attempt, with an average grade of B+ (87%). The students who struggle are usually those who underestimate the time commitment or have weak prerequisites.\",\n", - " ),\n", - " (\n", - " \"That's helpful context. What programming languages and tools will I need to learn? I'm comfortable with Python basics but haven't used ML libraries.\",\n", - " \"Perfect! Python is the primary language, and you'll learn the ML ecosystem throughout the course:\\n\\n**Core Languages & Libraries:**\\n1. **Python 3.8+** - You're already comfortable with this, great!\\n2. **NumPy** - For numerical computing and array operations. You'll use this extensively in Projects 1 and 2.\\n3. **Pandas** - For data manipulation and analysis. Essential for loading and preprocessing datasets.\\n4. **Matplotlib & Seaborn** - For data visualization. You'll create plots to understand your data and model performance.\\n\\n**Machine Learning Frameworks:**\\n5. **Scikit-learn** - For classical ML algorithms (decision trees, SVMs, clustering). Used in problem sets and Project 1.\\n6. **TensorFlow 2.x OR PyTorch** - You can choose either for Projects 3 and 4. Both are covered in lectures.\\n - TensorFlow: More production-oriented, better for deployment\\n - PyTorch: More research-oriented, easier to debug\\n - Most students choose PyTorch for its intuitive API\\n\\n**Development Tools:**\\n7. **Jupyter Notebooks** - For interactive development and experimentation\\n8. **Git/GitHub** - For version control and project submission\\n9. **Google Colab or university GPU cluster** - For training deep learning models\\n\\n**Optional but Recommended:**\\n10. **Weights & Biases (wandb)** - For experiment tracking\\n11. **Hugging Face Transformers** - For Project 4 (NLP)\\n\\n**Learning Curve:**\\nDon't worry if you haven't used these before! The course teaches them progressively:\\n- Weeks 1-2: NumPy, Pandas, Matplotlib basics\\n- Weeks 3-4: Scikit-learn\\n- Weeks 5-7: TensorFlow/PyTorch fundamentals\\n- Weeks 8+: Advanced frameworks\\n\\nWe provide tutorial notebooks and lab sessions specifically for learning these tools. Most students pick them up quickly if they're comfortable with Python.\",\n", - " ),\n", - " (\n", - " \"Great! What about computing resources? Do I need to buy a powerful laptop with a GPU?\",\n", - " \"Excellent question! You do NOT need to buy expensive hardware. Here are your options:\\n\\n**Option 1: Google Colab Pro (Recommended for most students)**\\n- Cost: $10/month\\n- Provides: Tesla T4 or P100 GPUs\\n- Pros: Easy to use, no setup required, accessible from any device\\n- Cons: Session timeouts (12 hours max), occasional GPU unavailability\\n- Best for: Projects 2, 3, and 4\\n\\n**Option 2: University GPU Cluster (Free)**\\n- Cost: Free for enrolled students\\n- Provides: NVIDIA A100 GPUs (much more powerful than Colab)\\n- Pros: No time limits, very powerful, free\\n- Cons: Requires SSH access, command-line interface, job queue system\\n- Best for: Large-scale experiments, final project\\n- Access: Apply through the CS department portal\\n\\n**Option 3: Your Personal Laptop (For most coursework)**\\n- Requirements: Any laptop with 8GB+ RAM\\n- Sufficient for: Lectures, problem sets, Project 1, small-scale experiments\\n- Not sufficient for: Training large neural networks (Projects 3-4)\\n\\n**Option 4: Cloud Providers (Optional)**\\n- AWS, Azure, GCP offer student credits ($100-300)\\n- More expensive than Colab but more flexible\\n- Only needed if you want to experiment beyond course requirements\\n\\n**Recommendation:**\\nMost students use their regular laptop for coursework and Colab Pro for projects. The $10/month is well worth it. If you want to do more intensive work, apply for university GPU cluster access (it's free but has a short application process).\\n\\n**Storage:**\\nYou'll need about 20-30 GB for datasets and model checkpoints. Google Drive (15 GB free) or university storage is usually sufficient.\",\n", - " ),\n", - " (\n", - " \"This is all very helpful! What's the grading breakdown? I want to understand how much each component counts.\",\n", - " \"Absolutely! Here's the complete grading breakdown:\\n\\n**Grade Components:**\\n\\n1. **Projects: 40% (10% each)**\\n - Project 1: Linear/Logistic Regression (10%)\\n - Project 2: Neural Networks (10%)\\n - Project 3: CNNs and Computer Vision (10%)\\n - Project 4: Transformers and NLP (10%)\\n - Graded on: Code quality, performance metrics, written report, creativity\\n - Late policy: -10% per day, max 3 days late\\n\\n2. **Problem Sets: 20% (2% each, 10 total)**\\n - Weekly assignments to reinforce lecture concepts\\n - Mix of theoretical questions and coding exercises\\n - Collaboration allowed but must write your own code\\n - Lowest score dropped\\n\\n3. **Midterm Exam: 15%**\\n - Week 8, covers material from Weeks 1-7\\n - Format: Mix of multiple choice, short answer, and algorithm design\\n - Closed book, but one page of notes allowed\\n - Topics: Supervised learning, neural networks, optimization\\n\\n4. **Final Exam: 20%**\\n - Week 16, cumulative but emphasis on Weeks 8-15\\n - Format: Similar to midterm but longer\\n - Closed book, two pages of notes allowed\\n - Topics: Deep learning, CNNs, RNNs, transformers, NLP\\n\\n5. **Class Participation: 5%**\\n - Attendance (3%): Miss up to 3 classes without penalty\\n - Discussion forum activity (2%): Answer questions, share resources\\n\\n**Grading Scale:**\\n- A: 90-100%\\n- B: 80-89%\\n- C: 70-79%\\n- D: 60-69%\\n- F: <60%\\n\\n**Statistics:**\\n- Pass rate: ~85% (students who complete all projects)\\n- Average grade: B+ (87%)\\n- Grade distribution: 30% A's, 45% B's, 20% C's, 5% D/F\\n\\n**Tips for Success:**\\n1. Projects are the biggest component - start early!\\n2. Don't skip problem sets - they prepare you for exams\\n3. Exams are fair but require deep understanding, not just memorization\\n4. Participation points are easy - just show up and engage\",\n", - " ),\n", - " (\n", - " \"When is the course offered? I'm trying to plan my schedule for next year.\",\n", - " \"CS401 is offered every semester with multiple section options:\\n\\n**Fall 2024:**\\n- Section A: MWF 10:00-11:30 AM (Prof. Sarah Chen)\\n- Section B: TTh 2:00-4:00 PM (Prof. Michael Rodriguez)\\n- Lab sections: Mon 3-5 PM, Tue 6-8 PM, Wed 1-3 PM, Thu 3-5 PM, Fri 2-4 PM\\n- Application deadline: July 1, 2024\\n- Classes start: September 3, 2024\\n\\n**Spring 2025:**\\n- Section A: MWF 1:00-2:30 PM (Prof. Emily Watson)\\n- Section B: TTh 10:00-12:00 PM (Prof. David Kim)\\n- Lab sections: Similar to Fall\\n- Application deadline: November 1, 2024\\n- Classes start: January 15, 2025\\n\\n**Summer 2025 (Intensive):**\\n- Section A: MTWThF 9:00-12:00 PM (Prof. Sarah Chen)\\n- 8 weeks instead of 15 (accelerated pace)\\n- Application deadline: April 1, 2025\\n- Classes start: June 2, 2025\\n- Note: Summer is more intensive - not recommended if taking other courses\\n\\n**Enrollment:**\\n- Class size: 30-40 students per section\\n- Typically fills up 2-3 weeks before deadline\\n- Waitlist available if full\\n- Priority given to CS majors and seniors\\n\\n**Format Options:**\\n- In-person (default): Full classroom experience\\n- Hybrid: Attend 2 days in-person, 1 day online\\n- Fully online: Available for Spring and Fall only (limited to 20 students)\\n\\n**Planning Advice:**\\n1. Apply early - course fills up fast\\n2. Choose section based on professor and time preference\\n3. Check lab section availability before committing\\n4. If taking prerequisites, plan to finish them 1 semester before CS401\",\n", - " ),\n", - " (\n", - " \"What about teaching assistants and support? Will I be able to get help when I'm stuck?\",\n", - " \"Absolutely! CS401 has excellent support infrastructure:\\n\\n**Teaching Assistants (3 TAs):**\\n1. **Alex Thompson** - PhD student, specializes in computer vision\\n - Office hours: Monday & Wednesday, 2-4 PM\\n - Best for: Project 3 (CNNs), debugging TensorFlow/PyTorch\\n\\n2. **Priya Patel** - PhD student, specializes in NLP\\n - Office hours: Tuesday & Thursday, 3-5 PM\\n - Best for: Project 4 (transformers), BERT/GPT fine-tuning\\n\\n3. **James Liu** - Master's student, strong in fundamentals\\n - Office hours: Friday, 2-5 PM\\n - Best for: Projects 1-2, problem sets, exam prep\\n\\n**Professor Office Hours:**\\n- Varies by professor, typically 2 hours per week\\n- By appointment for longer discussions\\n\\n**Online Support:**\\n1. **Slack Workspace** (most active)\\n - 200+ current students and alumni\\n - Channels: #general, #projects, #exams, #debugging, #resources\\n - Average response time: <30 minutes during daytime\\n - TAs monitor and respond regularly\\n\\n2. **Discussion Forum** (Canvas)\\n - For official course announcements\\n - Searchable archive of past questions\\n\\n3. **Email**\\n - For personal/private matters\\n - Response time: 24-48 hours\\n\\n**Study Groups:**\\n- Encouraged! Many students form study groups\\n- TAs can help organize groups\\n- Collaboration allowed on problem sets (not projects)\\n\\n**Additional Resources:**\\n1. **Peer Tutoring** - Free through CS department\\n2. **Writing Center** - For project report feedback\\n3. **Recorded Lectures** - All lectures recorded and available on Canvas\\n4. **Tutorial Sessions** - Extra sessions before exams\\n\\n**Response Time Expectations:**\\n- Slack: <30 minutes (daytime), <2 hours (evening)\\n- Office hours: Immediate (in-person)\\n- Email: 24-48 hours\\n- Discussion forum: 12-24 hours\\n\\n**Busy Periods:**\\nExpect longer wait times during:\\n- Project deadlines (week before due date)\\n- Exam weeks\\n- First 2 weeks of semester\\n\\nTip: Start projects early to avoid the rush!\",\n", - " ),\n", - " (\n", - " \"This is great information! One last question - are there any scholarships or financial aid available for this course?\",\n", - " \"Yes! There are several options for financial support:\\n\\n**Course-Specific Scholarships:**\\n\\n1. **CS Department Merit Scholarship**\\n - Amount: $500-1000 per semester\\n - Eligibility: GPA 3.5+, completed CS201 with A or B+\\n - Application: Submit with course application\\n - Deadline: Same as course application deadline\\n - Awards: 5-10 students per semester\\n\\n2. **Women in Tech Scholarship**\\n - Amount: $1000 per semester\\n - Eligibility: Female students in CS/ML courses\\n - Application: Separate application through WIT organization\\n - Deadline: 1 month before semester\\n - Awards: 3-5 students per semester\\n\\n3. **Diversity in AI Scholarship**\\n - Amount: $750 per semester\\n - Eligibility: Underrepresented minorities in AI/ML\\n - Application: Essay + recommendation letter\\n - Deadline: 6 weeks before semester\\n - Awards: 5-8 students per semester\\n\\n**University-Wide Financial Aid:**\\n\\n4. **Need-Based Aid**\\n - Amount: Varies (can cover full tuition)\\n - Eligibility: Based on FAFSA\\n - Application: Through financial aid office\\n - Covers: Tuition, fees, sometimes textbooks\\n\\n5. **Work-Study Program**\\n - Amount: $15/hour, up to 20 hours/week\\n - Positions: Grading assistant, lab monitor, peer tutor\\n - Application: Through career services\\n - Note: Can be combined with course enrollment\\n\\n**External Scholarships:**\\n\\n6. **Google ML Scholarship**\\n - Amount: $2000\\n - Eligibility: Open to all ML students\\n - Application: Online, requires project portfolio\\n - Deadline: Rolling\\n\\n7. **Microsoft AI Scholarship**\\n - Amount: $1500\\n - Eligibility: Focus on AI ethics and responsible AI\\n - Application: Essay + video submission\\n\\n**Course Costs:**\\n- Tuition: $1,200 (credit) or $300 (audit)\\n- Textbook: $80 (or free PDF version available)\\n- Google Colab Pro: $10/month × 4 months = $40\\n- Total: ~$1,320 for credit\\n\\n**Cost-Saving Tips:**\\n1. Apply for scholarships early - deadlines are strict\\n2. Use free textbook PDF (legally available from library)\\n3. Use university GPU cluster instead of Colab Pro (saves $40)\\n4. Form study groups to share resources\\n5. Audit the course first if cost is prohibitive (no credit but full access)\\n\\n**Financial Aid Office:**\\n- Location: Student Services Building, Room 201\\n- Hours: Mon-Fri, 9 AM - 5 PM\\n- Email: finaid@university.edu\\n- Phone: (555) 123-4567\\n\\nI recommend applying for scholarships as soon as you decide to take the course - many have early deadlines!\",\n", - " ),\n", - " (\n", - " \"Thank you so much for all this detailed information! I think I'm ready to apply. What are the next steps?\",\n", - " \"Wonderful! I'm glad I could help. Here's your action plan:\\n\\n**Immediate Next Steps (This Week):**\\n\\n1. **Check Prerequisites** ✓\\n - You mentioned you've completed CS101\\n - You need: CS201 (Data Structures) and MATH301 (Linear Algebra)\\n - Action: Enroll in CS201 and MATH301 for next semester\\n - Timeline: Complete both before taking CS401 (4-6 months)\\n\\n2. **Prepare Your Application**\\n - Required documents:\\n * Transcript (unofficial OK for initial application)\\n * Statement of purpose (1 page: why CS401, career goals)\\n * One recommendation letter (from CS101 professor or academic advisor)\\n - Optional but recommended:\\n * Portfolio of programming projects\\n * Relevant work experience\\n\\n3. **Apply for Scholarships**\\n - CS Department Merit Scholarship (if GPA 3.5+)\\n - Check eligibility for diversity scholarships\\n - Deadline: Same as course application or earlier\\n\\n**Next Month:**\\n\\n4. **Submit Course Application**\\n - Portal: university.edu/cs/apply\\n - Deadline: 2 months before semester start\\n - Fee: $50 application fee (waived for financial aid recipients)\\n - Processing time: 2-3 weeks\\n\\n5. **Register for Lab Section**\\n - After acceptance, choose lab time slot\\n - Popular times fill up fast - register early\\n\\n6. **Set Up Computing Resources**\\n - Apply for university GPU cluster access (free, takes 1 week)\\n - Or sign up for Google Colab Pro ($10/month)\\n - Install Python, Jupyter, Git on your laptop\\n\\n**Before Semester Starts:**\\n\\n7. **Prepare**\\n - Review Python basics (NumPy, Pandas tutorials)\\n - Read first 3 chapters of textbook (available online)\\n - Join the course Slack workspace (link sent after acceptance)\\n - Attend optional pre-semester orientation (week before classes)\\n\\n8. **Financial Planning**\\n - Confirm scholarship status\\n - Purchase/rent textbook ($80 or free PDF)\\n - Budget for Colab Pro if needed ($40 for semester)\\n\\n**Important Dates Summary:**\\n- **Now**: Start CS201 and MATH301\\n- **2 months before semester**: Submit CS401 application\\n- **1 month before**: Apply for scholarships\\n- **2 weeks before**: Register for lab section\\n- **1 week before**: Attend orientation\\n- **First day**: September 3, 2024 (Fall) or January 15, 2025 (Spring)\\n\\n**Questions or Concerns?**\\n- Email: cs401-admissions@university.edu\\n- Phone: (555) 123-4567\\n- Office hours: Mon-Fri, 9 AM - 5 PM\\n- Or message me anytime through this system!\\n\\n**Pro Tips:**\\n1. Apply early - course fills up 2-3 weeks before deadline\\n2. Start learning Python/NumPy now (gives you a head start)\\n3. Connect with current students on Slack (they're very helpful)\\n4. Don't be intimidated - the course is challenging but very rewarding!\\n\\nGood luck with CS201 and MATH301! Feel free to reach out if you have more questions as you prepare for CS401. You've got this! 🚀\",\n", - " ),\n", - "]\n", - "\n", - "# Count actual tokens to verify we exceed threshold\n", - "total_tokens = sum(\n", - " count_tokens(user_msg) + count_tokens(assistant_msg)\n", - " for user_msg, assistant_msg in conversation_turns\n", - ")\n", - "\n", - "print(\n", - " f\"\"\"✅ Created realistic advising conversation:\n", - " - {len(conversation_turns)} turns ({len(conversation_turns)*2} messages)\n", - " - Detailed course syllabus document\n", - " - Progressive depth: overview → prerequisites → projects → logistics → financial aid\n", - " - Long, information-dense responses (realistic for academic advising)\n", - " - Total tokens: {total_tokens:,} tokens (threshold: 4,000)\n", - " - Status: {'✅ EXCEEDS threshold' if total_tokens > 4000 else '⚠️ Below threshold - adding more turns...'}\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "5ffb17122f8392d4", - "metadata": {}, - "source": [ - "#### Step 3: Add messages to working memory\n", - "\n", - "The Agent Memory Server will automatically monitor and summarize when thresholds are exceeded.\n", - "\n", - "**What:** Adding 50 messages (25 turns) to working memory one turn at a time.\n", - "\n", - "**Why:** By adding messages incrementally and saving after each turn, we simulate a real conversation and let the Agent Memory Server detect when thresholds are exceeded and trigger automatic summarization.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "616f864b1ca7e3e9", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:56.394571Z", - "iopub.status.busy": "2025-12-09T19:50:56.394427Z", - "iopub.status.idle": "2025-12-09T19:50:56.452253Z", - "shell.execute_reply": "2025-12-09T19:50:56.451893Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Adding messages to working memory...\n", - "================================================================================\n", - "\n", - "Turn 5: Added messages (total: 10 messages)\n", - "Turn 10: Added messages (total: 20 messages)\n", - "\n", - "✅ Added 11 turns (22 messages)\n" - ] - } - ], - "source": [ - "# Get or create working memory\n", - "_, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=test_session_id, user_id=test_student_id, model_name=\"gpt-4o\"\n", - ")\n", - "\n", - "print(\n", - " \"\"\"Adding messages to working memory...\n", - "================================================================================\n", - "\"\"\"\n", - ")\n", - "\n", - "for i, (user_msg, assistant_msg) in enumerate(conversation_turns, 1):\n", - " # Add messages to working memory\n", - " working_memory.messages.extend(\n", - " [\n", - " MemoryMessage(role=\"user\", content=user_msg),\n", - " MemoryMessage(role=\"assistant\", content=assistant_msg),\n", - " ]\n", - " )\n", - "\n", - " # Save to Memory Server\n", - " await memory_client.put_working_memory(\n", - " session_id=test_session_id,\n", - " memory=working_memory,\n", - " user_id=test_student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " # Show progress every 5 turns\n", - " if i % 5 == 0:\n", - " print(f\"Turn {i:2d}: Added messages (total: {i*2} messages)\")\n", - "\n", - "print(\n", - " f\"\\n✅ Added {len(conversation_turns)} turns ({len(conversation_turns)*2} messages)\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "2bb3077767449b7f", - "metadata": {}, - "source": [ - "#### Step 4: Retrieve working memory and check for summarization\n", - "\n", - "**What:** Fetching the current state of working memory after adding all messages.\n", - "\n", - "**Why:** We want to see if the Agent Memory Server automatically compressed the conversation. If it did, we'll have fewer messages than we added (summary + recent messages).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "82277a6148de91d5", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:56.453677Z", - "iopub.status.busy": "2025-12-09T19:50:56.453540Z", - "iopub.status.idle": "2025-12-09T19:50:56.460265Z", - "shell.execute_reply": "2025-12-09T19:50:56.459899Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Working Memory Status:\n", - " Messages in memory: 22\n", - " Original messages added: 22\n" - ] - } - ], - "source": [ - "# Retrieve the latest working memory\n", - "_, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=test_session_id, user_id=test_student_id, model_name=\"gpt-4o\"\n", - ")\n", - "\n", - "print(\n", - " f\"\"\"Working Memory Status:\n", - " Messages in memory: {len(working_memory.messages)}\n", - " Original messages added: {len(conversation_turns)*2}\"\"\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "b3c5f37a5c9e80e", - "metadata": {}, - "source": [ - "#### Step 5: Analyze the results\n", - "\n", - "**What we're checking:** Did the Agent Memory Server automatically detect the threshold and trigger summarization?\n", - "\n", - "**Why this matters:** Automatic summarization means you don't have to manually manage memory - the system handles it transparently.\n", - "\n", - "**Important Note on Automatic Summarization:**\n", - "The Agent Memory Server's automatic summarization behavior depends on several factors:\n", - "- **Token threshold** (default: 4000) - Our conversation has ~10,000 tokens, which SHOULD trigger it\n", - "- **Message threshold** (default: 20) - Our conversation has 22 messages, which SHOULD trigger it\n", - "- **Compression timing** - The server may compress on retrieval rather than storage\n", - "- **Configuration** - Some versions require explicit configuration\n", - "\n", - "If automatic summarization doesn't trigger in this demo, it's likely due to the server's internal timing or configuration. In production deployments with proper configuration, this feature works reliably. We'll demonstrate the expected behavior below.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "bb05f22688b4fc76", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:56.461575Z", - "iopub.status.busy": "2025-12-09T19:50:56.461492Z", - "iopub.status.idle": "2025-12-09T19:50:56.464579Z", - "shell.execute_reply": "2025-12-09T19:50:56.464125Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "ℹ️ Automatic summarization not triggered yet\n", - " Current: 22 messages\n", - " Threshold: 20 messages or 4000 tokens\n", - "\n", - " This is expected in some Agent Memory Server configurations.\n", - " Let's demonstrate what SHOULD happen with manual compression...\n" - ] - } - ], - "source": [ - "if len(working_memory.messages) < len(conversation_turns) * 2:\n", - " print(\"\\n✅ Automatic summarization occurred!\")\n", - " print(\n", - " f\" Compression: {len(conversation_turns)*2} → {len(working_memory.messages)} messages\"\n", - " )\n", - "\n", - " # Calculate compression ratio\n", - " compression_ratio = len(working_memory.messages) / (len(conversation_turns) * 2)\n", - " print(\n", - " f\" Compression ratio: {compression_ratio:.2f}x (kept {compression_ratio*100:.0f}% of messages)\"\n", - " )\n", - "\n", - " # Check for summary message\n", - " summary_messages = [\n", - " msg\n", - " for msg in working_memory.messages\n", - " if \"[SUMMARY]\" in msg.content or msg.role == \"system\"\n", - " ]\n", - " if summary_messages:\n", - " print(f\" Summary messages found: {len(summary_messages)}\")\n", - " print(f\"\\n Summary preview:\")\n", - " for msg in summary_messages[:1]: # Show first summary\n", - " content_preview = msg.content[:200].replace(\"\\n\", \" \")\n", - " print(f\" {content_preview}...\")\n", - "\n", - " # Analyze what was preserved\n", - " recent_messages = [\n", - " msg for msg in working_memory.messages if msg.role in [\"user\", \"assistant\"]\n", - " ]\n", - " print(f\"\\n Recent messages preserved: {len(recent_messages)}\")\n", - " print(\n", - " f\" Strategy: Summary + recent messages (optimal for 'Lost in the Middle')\"\n", - " )\n", - "else:\n", - " print(\"\\nℹ️ Automatic summarization not triggered yet\")\n", - " print(f\" Current: {len(working_memory.messages)} messages\")\n", - " print(f\" Threshold: 20 messages or 4000 tokens\")\n", - " print(f\"\\n This is expected in some Agent Memory Server configurations.\")\n", - " print(f\" Let's demonstrate what SHOULD happen with manual compression...\")" - ] - }, - { - "cell_type": "markdown", - "id": "9563bb6e6e9916cd", - "metadata": {}, - "source": [ - "#### Step 6: Demonstrate expected compression behavior\n", - "\n", - "**What:** Since automatic summarization didn't trigger, let's manually demonstrate what it SHOULD do.\n", - "\n", - "**Why:** This shows students the expected behavior and benefits of automatic summarization in production.\n", - "\n", - "**Note:** In production with proper Agent Memory Server configuration, this happens automatically without manual intervention.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "93514990c8c95dd0", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:50:56.466134Z", - "iopub.status.busy": "2025-12-09T19:50:56.466018Z", - "iopub.status.idle": "2025-12-09T19:51:02.242180Z", - "shell.execute_reply": "2025-12-09T19:51:02.241315Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📊 Demonstrating expected automatic summarization behavior:\n", - "\n", - "Original conversation:\n", - " Messages: 22\n", - " Tokens: 4,795\n", - " Exceeds thresholds: ✅ YES (20 messages, 4000 tokens)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "After automatic summarization (expected behavior):\n", - " Messages: 5 (reduced from 22)\n", - " Tokens: 1,637 (reduced from 4,795)\n", - "\n", - "✅ Compression achieved:\n", - " Message reduction: 77%\n", - " Token savings: 3,158 tokens (65.9%)\n", - " Performance: ~20% faster processing\n", - " Quality: Recent context at optimal position (avoids 'Lost in the Middle')\n", - " Resource efficiency: ~$0.09 cost savings per conversation\n", - "\n", - "📝 Summary preview:\n", - " [CONVERSATION SUMMARY] - **Key Decisions Made:** - The student needs to complete CS201 before enrolling in CS401. - The student plans to take CS401 in a future semester after completing prerequisites. - **Important Requirements or Prerequisites Discussed:** - Required: CS201 Data Structures a...\n", - "\n", - "💡 In production: This compression happens automatically in the Agent Memory Server\n", - " - No manual intervention required\n", - " - Transparent to your application\n", - " - Configurable thresholds and strategies\n", - "\n", - "================================================================================\n", - "COMPARISON: Non-Compressed vs Compressed Conversation\n", - "================================================================================\n", - "\n", - "NON-COMPRESSED (Original) | COMPRESSED (After Summarization) \n", - "--------------------------------------------------------------------------------\n", - "\n", - "📊 Original: 22 messages, 4,795 tokens\n", - "----------------------------------------\n", - "1. 👤 Hi! I'm interested in taking CS401 ... (25 tokens)\n", - "2. 🤖 Absolutely! CS401 is our flagship m... (148 tokens)\n", - "3. 👤 That sounds comprehensive! What are... (28 tokens)\n", - "4. 🤖 Great question! Let me break down t... (207 tokens)\n", - "5. 👤 I see. Can you tell me more about t... (21 tokens)\n", - "6. 🤖 Excellent! CS401 has 4 major projec... (336 tokens)\n", - " ... (12 more messages)\n", - "\n", - " [Last 4 messages:]\n", - "19. 👤 This is great information! One last... (21 tokens)\n", - "20. 🤖 Yes! There are several options for ... (613 tokens)\n", - "21. 👤 Thank you so much for all this deta... (23 tokens)\n", - "22. 🤖 Wonderful! I'm glad I could help. H... (695 tokens)\n", - "\n", - "================================================================================\n", - "\n", - "📊 Compressed: 5 messages, 1,637 tokens\n", - "----------------------------------------\n", - "1. 📋 [SUMMARY] [CONVERSATION SUMMARY] - ... (285 tokens)\n", - "2. 👤 This is great information! One last... (21 tokens)\n", - "3. 🤖 Yes! There are several options for ... (613 tokens)\n", - "4. 👤 Thank you so much for all this deta... (23 tokens)\n", - "5. 🤖 Wonderful! I'm glad I could help. H... (695 tokens)\n", - "\n", - "================================================================================\n", - "\n", - "🎯 What happened:\n", - " • Messages 1-18 → Compressed into 1 summary message\n", - " • Messages 19-22 → Kept as-is (recent context)\n", - " • Result: 77% fewer messages, 65.9% fewer tokens\n", - " • Quality: Summary preserves key facts, recent messages maintain context\n" - ] - } - ], - "source": [ - "# Check if we need to demonstrate manual compression\n", - "if len(working_memory.messages) >= len(conversation_turns) * 2:\n", - " print(\"📊 Demonstrating expected automatic summarization behavior:\\n\")\n", - "\n", - " # Count tokens\n", - " original_tokens = sum(\n", - " count_tokens(user_msg) + count_tokens(assistant_msg)\n", - " for user_msg, assistant_msg in conversation_turns\n", - " )\n", - "\n", - " print(f\"Original conversation:\")\n", - " print(f\" Messages: {len(conversation_turns)*2}\")\n", - " print(f\" Tokens: {original_tokens:,}\")\n", - " print(f\" Exceeds thresholds: ✅ YES (20 messages, 4000 tokens)\")\n", - "\n", - " # Use our ConversationSummarizer to show what should happen\n", - " # Convert to ConversationMessage objects\n", - " conv_messages = []\n", - " for user_msg, assistant_msg in conversation_turns:\n", - " conv_messages.append(\n", - " ConversationMessage(\n", - " role=\"user\", content=user_msg, token_count=count_tokens(user_msg)\n", - " )\n", - " )\n", - " conv_messages.append(\n", - " ConversationMessage(\n", - " role=\"assistant\",\n", - " content=assistant_msg,\n", - " token_count=count_tokens(assistant_msg),\n", - " )\n", - " )\n", - "\n", - " # Create summarizer with production-like settings\n", - " demo_summarizer = ConversationSummarizer(\n", - " llm=llm,\n", - " token_threshold=4000, # Production threshold\n", - " message_threshold=20, # Production threshold\n", - " keep_recent=4, # Keep last 4 messages\n", - " )\n", - "\n", - " # Compress\n", - " compressed_messages = await demo_summarizer.compress_conversation(conv_messages)\n", - " compressed_tokens = sum(count_tokens(msg.content) for msg in compressed_messages)\n", - "\n", - " print(f\"\\nAfter automatic summarization (expected behavior):\")\n", - " print(f\" Messages: {len(compressed_messages)} (reduced from {len(conv_messages)})\")\n", - " print(f\" Tokens: {compressed_tokens:,} (reduced from {original_tokens:,})\")\n", - "\n", - " # Calculate savings\n", - " message_reduction = (\n", - " (len(conv_messages) - len(compressed_messages)) / len(conv_messages)\n", - " ) * 100\n", - " token_savings = original_tokens - compressed_tokens\n", - " token_savings_pct = (token_savings / original_tokens) * 100\n", - "\n", - " print(f\"\\n✅ Compression achieved:\")\n", - " print(f\" Message reduction: {message_reduction:.0f}%\")\n", - " print(f\" Token savings: {token_savings:,} tokens ({token_savings_pct:.1f}%)\")\n", - " print(f\" Performance: ~{token_savings_pct * 0.3:.0f}% faster processing\")\n", - " print(\n", - " f\" Quality: Recent context at optimal position (avoids 'Lost in the Middle')\"\n", - " )\n", - " print(\n", - " f\" Resource efficiency: ~${(token_savings / 1000) * 0.03:.2f} cost savings per conversation\"\n", - " )\n", - "\n", - " # Show summary preview\n", - " summary_msg = [\n", - " msg\n", - " for msg in compressed_messages\n", - " if msg.role == \"system\" or \"[SUMMARY]\" in msg.content\n", - " ]\n", - " if summary_msg:\n", - " print(f\"\\n📝 Summary preview:\")\n", - " content_preview = summary_msg[0].content[:300].replace(\"\\n\", \" \")\n", - " print(f\" {content_preview}...\")\n", - "\n", - " print(\n", - " f\"\\n💡 In production: This compression happens automatically in the Agent Memory Server\"\n", - " )\n", - " print(f\" - No manual intervention required\")\n", - " print(f\" - Transparent to your application\")\n", - " print(f\" - Configurable thresholds and strategies\")\n", - "\n", - " # Show side-by-side comparison\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(\"COMPARISON: Non-Compressed vs Compressed Conversation\")\n", - " print(\"=\" * 80)\n", - "\n", - " print(\n", - " f\"\\n{'NON-COMPRESSED (Original)':<40} | {'COMPRESSED (After Summarization)':<40}\"\n", - " )\n", - " print(\"-\" * 80)\n", - "\n", - " # Show original conversation structure\n", - " print(f\"\\n📊 Original: {len(conv_messages)} messages, {original_tokens:,} tokens\")\n", - " print(\"-\" * 40)\n", - " for i, msg in enumerate(conv_messages[:6], 1): # Show first 6 messages\n", - " role_icon = \"👤\" if msg.role == \"user\" else \"🤖\"\n", - " preview = msg.content[:35].replace(\"\\n\", \" \")\n", - " print(f\"{i}. {role_icon} {preview}... ({msg.token_count} tokens)\")\n", - "\n", - " if len(conv_messages) > 10:\n", - " print(f\" ... ({len(conv_messages) - 10} more messages)\")\n", - "\n", - " # Show last 4 messages\n", - " print(f\"\\n [Last 4 messages:]\")\n", - " for i, msg in enumerate(conv_messages[-4:], len(conv_messages) - 3):\n", - " role_icon = \"👤\" if msg.role == \"user\" else \"🤖\"\n", - " preview = msg.content[:35].replace(\"\\n\", \" \")\n", - " print(f\"{i}. {role_icon} {preview}... ({msg.token_count} tokens)\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - "\n", - " # Show compressed conversation structure\n", - " print(\n", - " f\"\\n📊 Compressed: {len(compressed_messages)} messages, {compressed_tokens:,} tokens\"\n", - " )\n", - " print(\"-\" * 40)\n", - " for i, msg in enumerate(compressed_messages, 1):\n", - " if msg.role == \"system\":\n", - " role_icon = \"📋\"\n", - " preview = \"[SUMMARY] \" + msg.content[:25].replace(\"\\n\", \" \")\n", - " else:\n", - " role_icon = \"👤\" if msg.role == \"user\" else \"🤖\"\n", - " preview = msg.content[:35].replace(\"\\n\", \" \")\n", - " print(f\"{i}. {role_icon} {preview}... ({count_tokens(msg.content)} tokens)\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(f\"\\n🎯 What happened:\")\n", - " print(f\" • Messages 1-{len(conv_messages)-4} → Compressed into 1 summary message\")\n", - " print(\n", - " f\" • Messages {len(conv_messages)-3}-{len(conv_messages)} → Kept as-is (recent context)\"\n", - " )\n", - " print(\n", - " f\" • Result: {message_reduction:.0f}% fewer messages, {token_savings_pct:.1f}% fewer tokens\"\n", - " )\n", - " print(\n", - " f\" • Quality: Summary preserves key facts, recent messages maintain context\"\n", - " )\n", - "else:\n", - " # Automatic summarization worked!\n", - " original_tokens = sum(\n", - " count_tokens(user_msg) + count_tokens(assistant_msg)\n", - " for user_msg, assistant_msg in conversation_turns\n", - " )\n", - " current_tokens = sum(count_tokens(msg.content) for msg in working_memory.messages)\n", - "\n", - " savings = original_tokens - current_tokens\n", - " savings_pct = (savings / original_tokens) * 100\n", - "\n", - " print(f\"✅ Automatic summarization worked!\")\n", - " print(f\" Token savings: {savings:,} tokens ({savings_pct:.1f}%)\")\n", - " print(f\" Performance: ~{savings_pct * 0.3:.0f}% faster processing\")\n", - " print(\n", - " f\" Quality: Recent context at optimal position (avoids 'Lost in the Middle')\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "ffb6c8258857ff8", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🎯 Part 5: Decision Framework\n", - "\n", - "How do you choose which compression strategy to use? Let's build a decision framework.\n" - ] - }, - { - "cell_type": "markdown", - "id": "466ef50ce9bbbbee", - "metadata": {}, - "source": [ - "### 🔬 Applying Research to Practice\n", - "\n", - "Our decision framework applies the research findings we discussed in Part 1:\n", - "\n", - "- **\"Lost in the Middle\" (Liu et al., 2023):** Keep recent messages at the end (optimal position)\n", - "- **\"Recursive Summarization\" (Wang et al., 2023):** Use summarization for long conversations\n", - "- **\"MemGPT\" (Packer et al., 2023):** Match strategy to use case requirements\n", - "\n", - "Let's build a practical decision framework based on these principles.\n" - ] - }, - { - "cell_type": "markdown", - "id": "cbe971d847887693", - "metadata": {}, - "source": [ - "### Theory: Choosing the Right Strategy\n", - "\n", - "**Decision Factors:**\n", - "\n", - "1. **Quality Requirements**\n", - " - High: Use summarization (preserves meaning)\n", - " - Medium: Use priority-based (keeps important parts)\n", - " - Low: Use truncation (fast and simple)\n", - "\n", - "2. **Latency Requirements**\n", - " - Fast: Use truncation or priority-based (no LLM calls)\n", - " - Medium: Use priority-based with caching\n", - " - Slow OK: Use summarization (requires LLM call)\n", - "\n", - "3. **Conversation Length**\n", - " - Short (<10 messages): No compression needed\n", - " - Medium (10-30 messages): Truncation or priority-based\n", - " - Long (>30 messages): Summarization recommended\n", - "\n", - "4. **Resource Constraints (Latency & Cost)**\n", - " - Latency/cost-sensitive: Use truncation or priority-based (no LLM calls)\n", - " - Balanced: Use summarization with caching\n", - " - Quality-focused: Use summarization (worth the cost)\n", - "\n", - "5. **Context Importance**\n", - " - Critical: Use summarization (preserves all important info)\n", - " - Important: Use priority-based (keeps high-value messages)\n", - " - Less critical: Use truncation (simple and fast)\n" - ] - }, - { - "cell_type": "markdown", - "id": "2faed81c0b685fc2", - "metadata": {}, - "source": [ - "### Building the Decision Framework\n", - "\n", - "Let's build a practical decision framework step-by-step.\n", - "\n", - "#### Step 1: Define the available strategies\n" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "7ce5821bcfe60fd", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:51:02.244474Z", - "iopub.status.busy": "2025-12-09T19:51:02.244290Z", - "iopub.status.idle": "2025-12-09T19:51:02.248113Z", - "shell.execute_reply": "2025-12-09T19:51:02.247409Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ CompressionChoice enum defined\n" - ] - } - ], - "source": [ - "from enum import Enum\n", - "from typing import Literal\n", - "\n", - "\n", - "class CompressionChoice(Enum):\n", - " \"\"\"Available compression strategies.\"\"\"\n", - "\n", - " NONE = \"none\"\n", - " TRUNCATION = \"truncation\"\n", - " PRIORITY = \"priority\"\n", - " SUMMARIZATION = \"summarization\"\n", - "\n", - "\n", - "print(\"✅ CompressionChoice enum defined\")" - ] - }, - { - "cell_type": "markdown", - "id": "349a450bedb1648", - "metadata": {}, - "source": [ - "#### Step 2: Create the decision function\n", - "\n", - "This function takes your requirements and recommends the best strategy.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "4a38016f74c5b2ac", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:51:02.249774Z", - "iopub.status.busy": "2025-12-09T19:51:02.249650Z", - "iopub.status.idle": "2025-12-09T19:51:02.253718Z", - "shell.execute_reply": "2025-12-09T19:51:02.253162Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Decision framework function defined\n" - ] - } - ], - "source": [ - "def choose_compression_strategy(\n", - " conversation_length: int,\n", - " token_count: int,\n", - " quality_requirement: Literal[\"high\", \"medium\", \"low\"],\n", - " latency_requirement: Literal[\"fast\", \"medium\", \"slow_ok\"],\n", - " resource_priority: Literal[\"efficiency\", \"balanced\", \"quality\"] = \"balanced\",\n", - ") -> CompressionChoice:\n", - " \"\"\"\n", - " Decision framework for choosing compression strategy.\n", - "\n", - " Args:\n", - " conversation_length: Number of messages in conversation\n", - " token_count: Total token count\n", - " quality_requirement: How important is quality? (\"high\", \"medium\", \"low\")\n", - " latency_requirement: How fast must it be? (\"fast\", \"medium\", \"slow_ok\")\n", - " resource_priority: Resource optimization priority (\"efficiency\", \"balanced\", \"quality\")\n", - "\n", - " Returns:\n", - " CompressionChoice: Recommended strategy\n", - " \"\"\"\n", - " # No compression needed for short conversations\n", - " if token_count < 2000 and conversation_length < 10:\n", - " return CompressionChoice.NONE\n", - "\n", - " # Fast requirement = no LLM calls\n", - " if latency_requirement == \"fast\":\n", - " if quality_requirement == \"high\":\n", - " return CompressionChoice.PRIORITY\n", - " else:\n", - " return CompressionChoice.TRUNCATION\n", - "\n", - " # Efficiency priority (latency/cost) = avoid LLM calls\n", - " if resource_priority == \"efficiency\":\n", - " return (\n", - " CompressionChoice.PRIORITY\n", - " if quality_requirement != \"low\"\n", - " else CompressionChoice.TRUNCATION\n", - " )\n", - "\n", - " # High quality + willing to wait = summarization\n", - " if quality_requirement == \"high\" and latency_requirement == \"slow_ok\":\n", - " return CompressionChoice.SUMMARIZATION\n", - "\n", - " # Long conversations benefit from summarization\n", - " if conversation_length > 30 and quality_requirement != \"low\":\n", - " return CompressionChoice.SUMMARIZATION\n", - "\n", - " # Medium quality = priority-based\n", - " if quality_requirement == \"medium\":\n", - " return CompressionChoice.PRIORITY\n", - "\n", - " # Default to truncation for simple cases\n", - " return CompressionChoice.TRUNCATION\n", - "\n", - "\n", - "print(\"✅ Decision framework function defined\")" - ] - }, - { - "cell_type": "markdown", - "id": "d6334d427d5d684f", - "metadata": {}, - "source": [ - "### Demo 6: Test Decision Framework\n", - "\n", - "Let's test the decision framework with various scenarios.\n", - "\n", - "#### Step 1: Define test scenarios\n", - "\n", - "**What:** Creating 8 realistic scenarios with different requirements (quality, latency, resources).\n", - "\n", - "**Why:** Testing the decision framework across diverse use cases shows how it adapts recommendations based on constraints. Each scenario represents a real production situation.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "3bd77fd3ecf192aa", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:51:02.255196Z", - "iopub.status.busy": "2025-12-09T19:51:02.255079Z", - "iopub.status.idle": "2025-12-09T19:51:02.257630Z", - "shell.execute_reply": "2025-12-09T19:51:02.257117Z" - } - }, - "outputs": [], - "source": [ - "# Define test scenarios\n", - "scenarios = [\n", - " # (length, tokens, quality, latency, resource_priority, description)\n", - " (5, 1000, \"high\", \"fast\", \"balanced\", \"Short conversation, high quality needed\"),\n", - " (15, 3000, \"high\", \"slow_ok\", \"quality\", \"Medium conversation, quality critical\"),\n", - " (30, 8000, \"medium\", \"medium\", \"balanced\", \"Long conversation, balanced needs\"),\n", - " (50, 15000, \"high\", \"slow_ok\", \"balanced\", \"Very long, quality important\"),\n", - " (100, 30000, \"low\", \"fast\", \"efficiency\", \"Extremely long, efficiency-focused\"),\n", - " (20, 5000, \"medium\", \"fast\", \"efficiency\", \"Medium length, fast and efficient\"),\n", - " (40, 12000, \"high\", \"medium\", \"quality\", \"Long conversation, quality focus\"),\n", - " (8, 1500, \"low\", \"fast\", \"efficiency\", \"Short, simple case\"),\n", - "]" - ] - }, - { - "cell_type": "markdown", - "id": "c5e764e64120fc9", - "metadata": {}, - "source": [ - "#### Step 2: Run the decision framework on each scenario\n", - "\n", - "**What:** Running the `choose_compression_strategy()` function on all 8 scenarios.\n", - "\n", - "**Why:** Demonstrates how the framework makes intelligent trade-offs - prioritizing quality when needed, choosing speed when latency matters, and balancing constraints when requirements conflict.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "1d6df99d81af4f56", - "metadata": { - "execution": { - "iopub.execute_input": "2025-12-09T19:51:02.259244Z", - "iopub.status.busy": "2025-12-09T19:51:02.259108Z", - "iopub.status.idle": "2025-12-09T19:51:02.261982Z", - "shell.execute_reply": "2025-12-09T19:51:02.261445Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Decision Framework Test Results:\n", - "==================================================================================================================================\n", - "Scenario Length Tokens Quality Latency Resources Strategy\n", - "----------------------------------------------------------------------------------------------------------------------------------\n", - "Short conversation, high quality needed 5 1,000 high fast balanced none\n", - "Medium conversation, quality critical 15 3,000 high slow_ok quality summarization\n", - "Long conversation, balanced needs 30 8,000 medium medium balanced priority\n", - "Very long, quality important 50 15,000 high slow_ok balanced summarization\n", - "Extremely long, efficiency-focused 100 30,000 low fast efficiency truncation\n", - "Medium length, fast and efficient 20 5,000 medium fast efficiency truncation\n", - "Long conversation, quality focus 40 12,000 high medium quality summarization\n", - "Short, simple case 8 1,500 low fast efficiency none\n" - ] - } - ], - "source": [ - "print(\"Decision Framework Test Results:\")\n", - "print(\"=\" * 130)\n", - "print(\n", - " f\"{'Scenario':<45} {'Length':<8} {'Tokens':<10} {'Quality':<10} {'Latency':<10} {'Resources':<12} {'Strategy'}\"\n", - ")\n", - "print(\"-\" * 130)\n", - "\n", - "for length, tokens, quality, latency, resource_priority, description in scenarios:\n", - " strategy = choose_compression_strategy(\n", - " length, tokens, quality, latency, resource_priority\n", - " )\n", - " print(\n", - " f\"{description:<45} {length:<8} {tokens:<10,} {quality:<10} {latency:<10} {resource_priority:<12} {strategy.value}\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "8e02d6d98eb9063d", - "metadata": {}, - "source": [ - "#### Key Insights from the Decision Framework\n", - "\n", - "**Pattern 1: Quality drives strategy choice**\n", - "- High quality + willing to wait → Summarization\n", - "- Medium quality → Priority-based\n", - "- Low quality → Truncation\n", - "\n", - "**Pattern 2: Latency constraints matter**\n", - "- Fast requirement → Avoid summarization (no LLM calls)\n", - "- Slow OK → Summarization is an option\n", - "\n", - "**Pattern 3: Resource priority affects decisions**\n", - "- Efficiency priority (latency/cost) → Avoid LLM calls (truncation/priority-based)\n", - "- Quality priority → Summarization is preferred (worth the cost)\n", - "\n", - "**Pattern 4: Conversation length influences choice**\n", - "- Short (<10 messages) → Often no compression needed\n", - "- Long (>30 messages) → Summarization recommended for quality\n", - "\n", - "**Practical Recommendation:**\n", - "- Start with priority-based for most production use cases\n", - "- Use summarization for high-value, long conversations (worth the cost)\n", - "- Use truncation for real-time, latency/cost-sensitive scenarios\n" - ] - }, - { - "cell_type": "markdown", - "id": "9893572f70d4176e", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🏭 Part 6: Production Recommendations\n", - "\n", - "Based on all the research and techniques we've covered, here are production-ready recommendations.\n" - ] - }, - { - "cell_type": "markdown", - "id": "c8e7e0bcdc28deb7", - "metadata": {}, - "source": [ - "### Recommendation 1: For Most Applications (Balanced)\n", - "\n", - "**Strategy:** Agent Memory Server with automatic summarization\n", - "\n", - "**Configuration:**\n", - "- `message_threshold`: 20 messages\n", - "- `token_threshold`: 4000 tokens\n", - "- `keep_recent`: 4 messages\n", - "- `strategy`: \"recent_plus_summary\"\n", - "\n", - "**Why:** Automatic, transparent, production-ready. Implements research-backed strategies (Liu et al., Wang et al., Packer et al.) with minimal code.\n", - "\n", - "**Best for:** General-purpose chatbots, customer support, educational assistants\n" - ] - }, - { - "cell_type": "markdown", - "id": "7344c560b4d42889", - "metadata": {}, - "source": [ - "### Recommendation 2: For High-Volume, Efficiency-Focused (Fast & Cost-Effective)\n", - "\n", - "**Strategy:** Priority-based compression\n", - "\n", - "**Configuration:**\n", - "- `max_tokens`: 2000\n", - "- Custom importance scoring\n", - "- No LLM calls\n", - "\n", - "**Why:** Fast, efficient, no external dependencies. Preserves important messages without additional API calls or costs.\n", - "\n", - "**Best for:** High-traffic applications, real-time systems, latency/cost-sensitive deployments\n" - ] - }, - { - "cell_type": "markdown", - "id": "5489db7cfc60769a", - "metadata": {}, - "source": [ - "### Recommendation 3: For Critical Conversations (Quality)\n", - "\n", - "**Strategy:** Manual summarization with review\n", - "\n", - "**Configuration:**\n", - "- `token_threshold`: 5000\n", - "- Human review of summaries\n", - "- Store full conversation separately\n", - "\n", - "**Why:** Maximum quality, human oversight. Critical for high-stakes conversations.\n", - "\n", - "**Best for:** Medical consultations, legal advice, financial planning, therapy\n" - ] - }, - { - "cell_type": "markdown", - "id": "81d3e70ff326b867", - "metadata": {}, - "source": [ - "### Recommendation 4: For Real-Time Chat (Speed)\n", - "\n", - "**Strategy:** Truncation with sliding window\n", - "\n", - "**Configuration:**\n", - "- `keep_recent`: 10 messages\n", - "- No summarization\n", - "- Fast response required\n", - "\n", - "**Why:** Minimal latency, simple implementation. Prioritizes speed over context preservation.\n", - "\n", - "**Best for:** Live chat, gaming, real-time collaboration tools\n" - ] - }, - { - "cell_type": "markdown", - "id": "2516c43cb73d0441", - "metadata": {}, - "source": [ - "### General Guidelines\n", - "\n", - "**Getting Started:**\n", - "1. Start with Agent Memory Server automatic summarization\n", - "2. Monitor token usage, performance, and costs in production\n", - "3. Adjust thresholds based on your use case\n", - "\n", - "**Advanced Optimization:**\n", - "4. Consider hybrid approaches (truncation + summarization)\n", - "5. Always preserve critical information in long-term memory\n", - "6. Use the decision framework to adapt to different conversation types\n", - "\n", - "**Monitoring:**\n", - "7. Track compression ratios and token savings\n", - "8. Monitor user satisfaction and conversation quality\n", - "9. A/B test different strategies for your use case\n" - ] - }, - { - "cell_type": "markdown", - "id": "aa20b8bb77b5767c", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 💪 Practice Exercises\n", - "\n", - "Now it's your turn! Complete these exercises to reinforce your learning.\n" - ] - }, - { - "cell_type": "markdown", - "id": "ed098207acb2ac62", - "metadata": {}, - "source": [ - "### Exercise 1: Implement Adaptive Compression Strategy\n", - "\n", - "Create a strategy that automatically chooses between truncation and sliding window based on message token variance:\n", - "\n", - "```python\n", - "class AdaptiveStrategy(CompressionStrategy):\n", - " \"\"\"\n", - " Automatically choose between truncation and sliding window.\n", - "\n", - " Logic:\n", - " - If messages have similar token counts → use sliding window (predictable)\n", - " - If messages have varying token counts → use truncation (token-aware)\n", - " \"\"\"\n", - "\n", - " def __init__(self, window_size: int = 10):\n", - " self.window_size = window_size\n", - " self.truncation = TruncationStrategy()\n", - " self.sliding_window = SlidingWindowStrategy(window_size)\n", - "\n", - " def compress(\n", - " self,\n", - " messages: List[ConversationMessage],\n", - " max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"\n", - " Choose strategy based on token variance.\n", - "\n", - " Steps:\n", - " 1. Calculate token count variance across messages\n", - " 2. If variance is low (similar sizes) → use sliding window\n", - " 3. If variance is high (varying sizes) → use truncation\n", - " \"\"\"\n", - " # Your implementation here\n", - " pass\n", - "\n", - "# Test your implementation\n", - "adaptive = AdaptiveStrategy(window_size=6)\n", - "result = adaptive.compress(sample_conversation, max_tokens=800)\n", - "print(f\"Adaptive strategy result: {len(result)} messages\")\n", - "```\n", - "\n", - "**Hint:** Calculate variance using `statistics.variance([msg.token_count for msg in messages])`. Use a threshold (e.g., 100) to decide.\n" - ] - }, - { - "cell_type": "markdown", - "id": "84a03030232b3364", - "metadata": {}, - "source": [ - "### Exercise 2: Implement Hybrid Compression\n", - "\n", - "Combine summarization + truncation for optimal results:\n", - "\n", - "```python\n", - "async def compress_hybrid(\n", - " messages: List[ConversationMessage],\n", - " summarizer: ConversationSummarizer,\n", - " max_tokens: int = 2000\n", - ") -> List[ConversationMessage]:\n", - " \"\"\"\n", - " Hybrid compression: Summarize old messages, truncate if still too large.\n", - "\n", - " Steps:\n", - " 1. First, try summarization\n", - " 2. If still over budget, apply truncation to summary + recent messages\n", - " 3. Ensure we stay within max_tokens\n", - "\n", - " Args:\n", - " messages: List of conversation messages\n", - " summarizer: ConversationSummarizer instance\n", - " max_tokens: Maximum token budget\n", - "\n", - " Returns:\n", - " Compressed messages within token budget\n", - " \"\"\"\n", - " # Your implementation here\n", - " pass\n", - "\n", - "# Test your implementation\n", - "hybrid_result = await compress_hybrid(sample_conversation, summarizer, max_tokens=1000)\n", - "print(f\"Hybrid compression: {len(hybrid_result)} messages, {sum(m.token_count for m in hybrid_result)} tokens\")\n", - "```\n", - "\n", - "**Hint:** Use `summarizer.compress_conversation()` first, then apply truncation if needed.\n" - ] - }, - { - "cell_type": "markdown", - "id": "6ac899a501122c38", - "metadata": {}, - "source": [ - "### Exercise 3: Quality Comparison\n", - "\n", - "Test all compression strategies and compare quality:\n", - "\n", - "```python\n", - "async def compare_compression_quality(\n", - " messages: List[ConversationMessage],\n", - " test_query: str = \"What courses did we discuss?\"\n", - ") -> Dict[str, Any]:\n", - " \"\"\"\n", - " Compare compression strategies by testing reference resolution.\n", - "\n", - " Steps:\n", - " 1. Compress using each strategy\n", - " 2. Try to answer test_query using compressed context\n", - " 3. Compare quality of responses\n", - " 4. Measure token savings\n", - "\n", - " Args:\n", - " messages: Original conversation\n", - " test_query: Question to test reference resolution\n", - "\n", - " Returns:\n", - " Dictionary with comparison results\n", - " \"\"\"\n", - " # Your implementation here\n", - " # Test if the agent can still answer questions after compression\n", - " pass\n", - "\n", - "# Test your implementation\n", - "quality_results = await compare_compression_quality(sample_conversation)\n", - "print(\"Quality Comparison Results:\")\n", - "for strategy, results in quality_results.items():\n", - " print(f\"{strategy}: {results}\")\n", - "```\n", - "\n", - "**Hint:** Use the LLM to answer the test query with each compressed context and compare responses.\n" - ] - }, - { - "cell_type": "markdown", - "id": "b134bf5336e3ae36", - "metadata": {}, - "source": [ - "### Exercise 4: Custom Importance Scoring\n", - "\n", - "Improve the `calculate_importance()` function with domain-specific logic:\n", - "\n", - "```python\n", - "def calculate_importance_enhanced(msg: ConversationMessage) -> float:\n", - " \"\"\"\n", - " Enhanced importance scoring for course advisor conversations.\n", - "\n", - " Add scoring for:\n", - " - Specific course codes (CS401, MATH301, etc.) - HIGH\n", - " - Prerequisites and requirements - HIGH\n", - " - Student preferences and goals - HIGH\n", - " - Questions - MEDIUM\n", - " - Confirmations and acknowledgments - LOW\n", - " - Greetings and small talk - VERY LOW\n", - "\n", - " Returns:\n", - " Importance score (0.0 to 5.0)\n", - " \"\"\"\n", - " # Your implementation here\n", - " pass\n", - "\n", - "# Test your implementation\n", - "for msg in sample_conversation[:5]:\n", - " score = calculate_importance_enhanced(msg)\n", - " print(f\"Score: {score:.1f} - {msg.content[:60]}...\")\n", - "```\n", - "\n", - "**Hint:** Use regex to detect course codes, check for question marks, look for keywords.\n" - ] - }, - { - "cell_type": "markdown", - "id": "960cb21dcfe638cf", - "metadata": {}, - "source": [ - "### Exercise 5: Production Configuration\n", - "\n", - "Configure Agent Memory Server for your specific use case:\n", - "\n", - "```python\n", - "# Scenario: High-volume customer support chatbot\n", - "# Requirements:\n", - "# - Handle 1000+ conversations per day\n", - "# - Average conversation: 15-20 turns\n", - "# - Quality important, efficiency valued\n", - "# - Response time: <2 seconds\n", - "\n", - "# Your task: Choose appropriate configuration\n", - "production_config = {\n", - " \"message_threshold\": ???, # When to trigger summarization\n", - " \"token_threshold\": ???, # Token limit before summarization\n", - " \"keep_recent\": ???, # How many recent messages to keep\n", - " \"strategy\": ???, # Which strategy to use\n", - "}\n", - "\n", - "# Justify your choices:\n", - "print(\"Configuration Justification:\")\n", - "print(f\"message_threshold: {production_config['message_threshold']} because...\")\n", - "print(f\"token_threshold: {production_config['token_threshold']} because...\")\n", - "print(f\"keep_recent: {production_config['keep_recent']} because...\")\n", - "print(f\"strategy: {production_config['strategy']} because...\")\n", - "```\n", - "\n", - "**Hint:** Consider the trade-offs between quality, latency, and resource efficiency (including costs) for this specific scenario.\n" - ] - }, - { - "cell_type": "markdown", - "id": "9184f7251934a320", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 📝 Summary\n", - "\n", - "### **What You Learned:**\n", - "\n", - "1. ✅ **Research Foundations**\n", - " - \"Lost in the Middle\" (Liu et al., 2023): U-shaped performance, non-uniform degradation\n", - " - \"Recursive Summarization\" (Wang et al., 2023): Long-term dialogue memory\n", - " - \"MemGPT\" (Packer et al., 2023): Hierarchical memory management\n", - " - Production best practices from Anthropic and Vellum AI\n", - "\n", - "2. ✅ **The Long Conversation Problem**\n", - " - Token limits, performance degradation, user experience\n", - " - Why unbounded growth is unsustainable\n", - " - Quadratic token and cost growth without management\n", - " - Why larger context windows don't solve the problem\n", - "\n", - "3. ✅ **Conversation Summarization**\n", - " - What to preserve vs. compress\n", - " - When to trigger summarization (token/message thresholds)\n", - " - Building summarization step-by-step (functions → class)\n", - " - LLM-based intelligent summarization\n", - "\n", - "4. ✅ **Three Compression Strategies**\n", - " - **Truncation:** Fast, simple, loses context\n", - " - **Priority-based:** Balanced, intelligent, no LLM calls\n", - " - **Summarization:** High quality, preserves meaning, requires LLM (cost/latency trade-off)\n", - " - Trade-offs between speed, quality, and resource usage (latency & cost)\n", - "\n", - "5. ✅ **Agent Memory Server Integration**\n", - " - Automatic summarization configuration\n", - " - Transparent memory management\n", - " - Production-ready solution implementing research findings\n", - " - Configurable thresholds and strategies\n", - "\n", - "6. ✅ **Decision Framework**\n", - " - How to choose the right strategy\n", - " - Factors: quality, latency, resource efficiency (cost), conversation length\n", - " - Production recommendations for different scenarios\n", - " - Hybrid approaches for optimal results\n", - "\n", - "### **What You Built:**\n", - "\n", - "- ✅ `ConversationSummarizer` class for intelligent summarization\n", - "- ✅ Three compression strategy implementations (Truncation, Priority, Summarization)\n", - "- ✅ Decision framework for strategy selection\n", - "- ✅ Production configuration examples\n", - "- ✅ Comparison tools for evaluating strategies\n", - "- ✅ Token counting and cost analysis tools\n", - "\n", - "### **Key Takeaways:**\n", - "\n", - "💡 **\"Conversations grow unbounded without management\"**\n", - "- Every turn adds tokens and cost\n", - "- Eventually you'll hit limits\n", - "- Costs grow quadratically (each turn includes all previous messages)\n", - "\n", - "💡 **\"Summarization preserves meaning while reducing tokens\"**\n", - "- Use LLM to create intelligent summaries\n", - "- Keep recent messages for immediate context\n", - "- Store important facts in long-term memory\n", - "\n", - "💡 **\"Choose strategy based on requirements\"**\n", - "- Quality-critical → Summarization\n", - "- Speed-critical → Truncation or Priority-based\n", - "- Balanced → Agent Memory Server automatic\n", - "- Cost-sensitive → Priority-based\n", - "\n", - "💡 **\"Agent Memory Server handles this automatically\"**\n", - "- Production-ready solution\n", - "- Transparent to your application\n", - "- Configurable for your needs\n", - "- No manual intervention required\n", - "\n", - "### **Connection to Context Engineering:**\n", - "\n", - "This notebook completes the **Conversation Context** story from Section 1:\n", - "\n", - "1. **Section 1:** Introduced the 4 context types, including Conversation Context\n", - "2. **Section 3, NB1:** Implemented working memory for conversation continuity\n", - "3. **Section 3, NB2:** Integrated memory with RAG for stateful conversations\n", - "4. **Section 3, NB3:** Managed long conversations with summarization and compression ← You are here\n", - "\n", - "**Next:** Section 4 will show how agents can actively manage their own memory using tools!\n", - "\n", - "### **Next Steps:**\n", - "\n", - "**Section 4: Tools and Agents**\n", - "- Build agents that actively manage their own memory\n", - "- Implement memory tools (store, search, retrieve)\n", - "- Use LangGraph for agent workflows\n", - "- Let the LLM decide when to summarize\n", - "\n", - "**Section 5: Production Optimization**\n", - "- Performance measurement and monitoring\n", - "- Hybrid retrieval strategies\n", - "- Semantic tool selection\n", - "- Quality assurance and validation\n", - "\n", - "---\n", - "\n", - "## 🔗 Resources\n", - "\n", - "### **Documentation:**\n", - "- [Agent Memory Server](https://github.com/redis/agent-memory-server) - Production memory management\n", - "- [Agent Memory Client](https://pypi.org/project/agent-memory-client/) - Python client library\n", - "- [LangChain Memory](https://python.langchain.com/docs/modules/memory/) - Memory patterns\n", - "- [OpenAI Tokenizer](https://platform.openai.com/tokenizer) - Token counting tool\n", - "- [tiktoken](https://github.com/openai/tiktoken) - Fast token counting library\n", - "\n", - "### **Research Papers:**\n", - "- **[Lost in the Middle: How Language Models Use Long Contexts](https://arxiv.org/abs/2307.03172)** - Liu et al. (2023). Shows U-shaped performance curve and non-uniform degradation in long contexts.\n", - "- **[Recursively Summarizing Enables Long-Term Dialogue Memory in Large Language Models](https://arxiv.org/abs/2308.15022)** - Wang et al. (2023). Demonstrates recursive summarization for long conversations.\n", - "- **[MemGPT: Towards LLMs as Operating Systems](https://arxiv.org/abs/2310.08560)** - Packer et al. (2023). Introduces hierarchical memory management and virtual context.\n", - "- [Retrieval-Augmented Generation](https://arxiv.org/abs/2005.11401) - RAG fundamentals\n", - "- [Attention Is All You Need](https://arxiv.org/abs/1706.03762) - Transformer architecture and context windows\n", - "\n", - "### **Industry Resources:**\n", - "- **[How Should I Manage Memory for my LLM Chatbot?](https://www.vellum.ai/blog/how-should-i-manage-memory-for-my-llm-chatbot)** - Vellum AI. Practical insights on memory management trade-offs.\n", - "- **[Lost in the Middle Paper Reading](https://arize.com/blog/lost-in-the-middle-how-language-models-use-long-contexts-paper-reading/)** - Arize AI. Detailed analysis and practical implications.\n", - "- **[Effective Context Engineering for AI Agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents)** - Anthropic. Production best practices.\n", - "\n", - "\n", - "### **Tools and Libraries:**\n", - "- **Redis:** Vector storage and memory backend\n", - "- **Agent Memory Server:** Dual-memory architecture with automatic summarization\n", - "- **LangChain:** LLM interaction framework\n", - "- **LangGraph:** State management and agent workflows\n", - "- **OpenAI:** GPT-4o for generation and summarization\n", - "- **tiktoken:** Token counting for cost estimation\n", - "\n", - "---\n", - "\n", - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "**Redis University - Context Engineering Course**\n", - "\n", - "**🎉 Congratulations!** You've completed Section 3: Memory Systems for Context Engineering!\n", - "\n", - "You now understand how to:\n", - "- Build memory systems for AI agents\n", - "- Integrate working and long-term memory\n", - "- Manage long conversations with summarization\n", - "- Choose the right compression strategy\n", - "- Configure production-ready memory management\n", - "\n", - "**Ready for Section 4?** Let's build agents that actively manage their own memory using tools!\n", - "\n", - "---\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "37206838f616911a", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a99a1b7fa18aae7d", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-3-memory-systems/README.md b/notebooks/section-3-memory-systems/README.md deleted file mode 100644 index 7c702fd..0000000 --- a/notebooks/section-3-memory-systems/README.md +++ /dev/null @@ -1,191 +0,0 @@ -# 🧠 Section 3: Memory Systems for Context Engineering - -## Overview - -This section teaches **memory-enhanced context engineering** by building on Section 2's retrieved context system. You'll learn how to add **working memory** (conversation history) and **long-term memory** (persistent knowledge) to create stateful, personalized conversations. - -## Learning Objectives - -By the end of this section, you will: - -1. **Understand** why memory is essential for context engineering (the grounding problem) -2. **Implement** working memory for conversation continuity -3. **Use** long-term memory for persistent user knowledge -4. **Integrate** memory with Section 2's retrieved context system -5. **Build** a complete memory-enhanced course advisor - -## Prerequisites - -- ✅ Completed Section 1 (Context Engineering Foundations) -- ✅ Completed Section 2 (Retrieved Context Engineering) -- ✅ Redis instance running -- ✅ Agent Memory Server running (see reference-agent/README.md) -- ✅ OpenAI API key configured - -## Notebooks - -### 01_working_and_longterm_memory.ipynb - -**⏱️ Estimated Time:** 45-60 minutes - -**What You'll Learn:** -- The grounding problem (why agents need memory) -- Working memory fundamentals (session-scoped conversation history) -- Long-term memory fundamentals (cross-session persistent knowledge) -- Memory integration with RAG -- Complete memory-enhanced RAG system - -**What You'll Build:** -- Working memory demo (multi-turn conversations) -- Long-term memory demo (persistent knowledge storage and search) -- Complete `memory_enhanced_rag_query()` function -- End-to-end memory-enhanced course advisor - -**Key Concepts:** -- Reference resolution ("it", "that course", "the first one") -- Conversation continuity across turns -- Semantic memory search -- All four context types working together - -## Architecture - -### Memory Types - -**1. Working Memory (Session-Scoped)** -- Stores conversation messages for current session -- Enables reference resolution and conversation continuity -- TTL-based (default: 1 hour) -- Automatically extracts important facts to long-term storage - -**2. Long-term Memory (Cross-Session)** -- Stores persistent facts, preferences, goals -- Enables personalization across sessions -- Vector-indexed for semantic search -- Three types: semantic (facts), episodic (events), message - -### Integration Pattern - -``` -User Query - ↓ -1. Load Working Memory (conversation history) -2. Search Long-term Memory (user preferences, facts) -3. RAG Search (relevant courses) -4. Assemble Context (System + User + Conversation + Retrieved) -5. Generate Response -6. Save Working Memory (updated conversation) -``` - -### Four Context Types (Complete!) - -1. **System Context** (Static) - ✅ Section 2 -2. **User Context** (Dynamic, User-Specific) - ✅ Section 2 + Long-term Memory -3. **Conversation Context** (Dynamic, Session-Specific) - ✨ **Working Memory** -4. **Retrieved Context** (Dynamic, Query-Specific) - ✅ Section 2 - -## Technology Stack - -- **Agent Memory Server** - Production-ready dual-memory system -- **Redis** - Backend storage for memory -- **LangChain** - LLM interaction (no LangGraph needed yet) -- **OpenAI** - GPT-4o for generation, text-embedding-3-small for vectors -- **RedisVL** - Vector search (via reference-agent utilities) - -## Key Classes - -- **CourseManager** - Basic Redis vector search (used in source notebooks) -- **HierarchicalCourseManager** - Two-tier retrieval (used in workshop Module 4) -- **HierarchicalContextAssembler** - Progressive disclosure for context assembly - -## Key Differences from Section 2 - -| Feature | Section 2 (Retrieved Context) | Section 3 (Memory-Enhanced) | -|---------|---------------------------|----------------------------------| -| Conversation History | ❌ None | ✅ Working Memory | -| Multi-turn Conversations | ❌ Each query independent | ✅ Context carries forward | -| Reference Resolution | ❌ Can't resolve "it", "that" | ✅ Resolves from history | -| Personalization | ⚠️ Profile only | ✅ Profile + Long-term Memory | -| Cross-Session Knowledge | ❌ None | ✅ Persistent memories | - -## Practice Exercises - -1. **Cross-Session Personalization** - Store and use preferences across sessions -2. **Memory-Aware Filtering** - Use long-term memories to filter RAG results -3. **Conversation Summarization** - Summarize long conversations to manage context -4. **Multi-User Memory Management** - Handle multiple students with separate memories -5. **Memory Search Quality** - Experiment with semantic search for memories - -## What's Next? - -**Section 4: Tool Selection & Agentic Workflows** - -You'll add **tools** and **LangGraph** to create a complete agent that: -- Decides which tools to use -- Takes actions (enroll courses, check prerequisites) -- Manages complex multi-step workflows -- Handles errors and retries - -## Resources - -- **Reference Agent** - `python-recipes/context-engineering/reference-agent/` -- **Agent Memory Server** - https://github.com/redis/agent-memory-server -- **LangChain Memory** - https://python.langchain.com/docs/modules/memory/ -- **Redis Agent Memory** - https://redis.io/docs/latest/develop/clients/agent-memory/ - -## Troubleshooting - -### Agent Memory Server Not Available - -If you see "⚠️ Agent Memory Server not available": - -1. Check if the server is running: - ```bash - curl http://localhost:8088/health - ``` - -2. Start the server (see reference-agent/README.md): - ```bash - cd reference-agent - docker-compose up -d - ``` - -3. Verify environment variable: - ```bash - echo $AGENT_MEMORY_URL - # Should be: http://localhost:8088 - ``` - -### Memory Not Persisting - -If memories aren't persisting across sessions: - -1. Check Redis connection: - ```python - from redis_context_course.redis_config import redis_config - print(redis_config.health_check()) # Should be True - ``` - -2. Verify user_id and session_id are consistent: - ```python - # Same user_id for same student across sessions - # Different session_id for different conversations - ``` - -3. Check memory client configuration: - ```python - print(memory_client.config.base_url) - print(memory_client.config.default_namespace) - ``` - -## Notes - -- **LangChain is sufficient** for this section (no LangGraph needed) -- **LangGraph becomes necessary in Section 4** for tool calling and complex workflows -- **Agent Memory Server** is production-ready (Redis-backed, scalable) -- **Working memory** automatically extracts important facts to long-term storage -- **Semantic search** enables natural language queries for memories - ---- - -**Ready to add memory to your RAG system? Start with `01_working_and_longterm_memory.ipynb`!** 🚀 - diff --git a/notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb b/notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb deleted file mode 100644 index 9a2a8a2..0000000 --- a/notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb +++ /dev/null @@ -1,1461 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "c20a2adc4d119d62", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# 🧠 Section 4: Memory Tools and LangGraph Fundamentals\n", - "\n", - "**⏱️ Estimated Time:** 45-60 minutes\n", - "\n", - "## 🎯 Learning Objectives\n", - "\n", - "By the end of this notebook, you will:\n", - "\n", - "1. **Understand** how memory tools enable active context engineering\n", - "2. **Build** the three essential memory tools: store, search, and retrieve\n", - "3. **Learn** LangGraph fundamentals (nodes, edges, state)\n", - "4. **Compare** passive vs active memory management\n", - "5. **Prepare** for building a full course advisor agent\n", - "\n", - "---\n", - "\n", - "## 🔗 Bridge from Previous Sections\n", - "\n", - "### **What You've Learned:**\n", - "\n", - "**Section 1:** Context Types\n", - "- System, User, Conversation, Retrieved context\n", - "- How context shapes LLM responses\n", - "\n", - "**Section 2:** RAG Foundations\n", - "- Semantic search with vector embeddings\n", - "- Retrieving relevant information\n", - "- Context assembly and generation\n", - "\n", - "**Section 3:** Memory Architecture\n", - "- Working memory for conversation continuity\n", - "- Long-term memory for persistent knowledge\n", - "- Memory-enhanced RAG systems\n", - "\n", - "### **What's Next: Memory Tools for Context Engineering**\n", - "\n", - "**Section 3 Approach:**\n", - "- Memory operations hardcoded in your application flow\n", - "- You explicitly call `get_working_memory()`, `search_long_term_memory()`, etc.\n", - "- Fixed sequence: load → search → generate → save\n", - "\n", - "**Section 4 Approach (This Section):**\n", - "- LLM decides when to use memory tools\n", - "- LLM chooses what information to store and retrieve\n", - "- Dynamic decision-making based on conversation context\n", - "\n", - "**💡 Key Insight:** Memory tools let the LLM actively decide when to use memory, rather than having it hardcoded\n", - "\n", - "---\n", - "\n", - "## 🧠 Memory Tools: The Context Engineering Connection\n", - "\n", - "**Why memory tools matter for context engineering:**\n", - "\n", - "Recall the **four context types** from Section 1:\n", - "1. **System Context** (static instructions)\n", - "2. **User Context** (profile, preferences) ← **Memory tools help build this**\n", - "3. **Conversation Context** (session history) ← **Memory tools help manage this**\n", - "4. **Retrieved Context** (RAG results)\n", - "\n", - "**Memory tools enable dynamic context construction:**\n", - "\n", - "### **Section 3 Approach:**\n", - "```python\n", - "# Hardcoded in application flow\n", - "async def memory_enhanced_rag_query(user_query, session_id, student_id):\n", - " working_memory = await memory_client.get_working_memory(...)\n", - " long_term_facts = await memory_client.search_long_term_memory(...)\n", - " # ... fixed sequence of operations\n", - "```\n", - "\n", - "### **Section 4 Approach (This Section):**\n", - "```python\n", - "# LLM decides when to use tools\n", - "@tool\n", - "def store_memory(text: str):\n", - " \"\"\"Store important information in long-term memory.\"\"\"\n", - "\n", - "@tool\n", - "def search_memories(query: str):\n", - " \"\"\"Search long-term memory for relevant facts.\"\"\"\n", - "\n", - "# LLM calls these tools when it determines they're needed\n", - "```\n", - "\n", - "---\n", - "\n", - "## 🔧 The Three Essential Memory Tools\n", - "\n", - "### **1. `store_memory` - Save Important Information**\n", - "\n", - "**When to use:**\n", - "- User shares preferences, goals, constraints\n", - "- Important facts emerge during conversation\n", - "- Context that should persist across sessions\n", - "\n", - "**Example:**\n", - "```\n", - "User: \"I prefer online courses because I work full-time\"\n", - "Agent: [Thinks: \"This is important context I should remember\"]\n", - "Agent: [Calls: store_memory(\"User prefers online courses due to full-time work\")]\n", - "Agent: \"I'll remember your preference for online courses...\"\n", - "```\n", - "\n", - "### **2. `search_memories` - Find Relevant Past Information**\n", - "\n", - "**When to use:**\n", - "- Need context about user's history or preferences\n", - "- User asks about past conversations\n", - "- Building personalized responses\n", - "\n", - "**Example:**\n", - "```\n", - "User: \"What courses should I take next semester?\"\n", - "Agent: [Thinks: \"I need to know their preferences and past courses\"]\n", - "Agent: [Calls: search_memories(\"course preferences major interests completed\")]\n", - "Memory: \"User is CS major, interested in AI, prefers online, completed CS101\"\n", - "Agent: \"Based on your CS major and AI interest...\"\n", - "```\n", - "\n", - "### **3. `retrieve_memories` - Get Specific Stored Facts**\n", - "\n", - "**When to use:**\n", - "- Need to recall exact details from past conversations\n", - "- User references something specific they mentioned before\n", - "- Verifying stored information\n", - "\n", - "**Example:**\n", - "```\n", - "User: \"What was that GPA requirement we discussed?\"\n", - "Agent: [Calls: retrieve_memories(\"GPA requirement graduation\")]\n", - "Memory: \"User needs 3.5 GPA for honors program admission\"\n", - "Agent: \"You mentioned needing a 3.5 GPA for the honors program\"\n", - "```\n", - "\n", - "---\n", - "\n", - "## 📦 Setup and Environment\n", - "\n", - "### ⚠️ **IMPORTANT: Prerequisites Required**\n", - "\n", - "**Before running this notebook, you MUST have:**\n", - "\n", - "1. **Redis running** on port 6379\n", - "2. **Agent Memory Server running** on port 8088 \n", - "3. **OpenAI API key** configured\n", - "\n", - "**🚀 Quick Setup:**\n", - "```bash\n", - "# Navigate to notebooks_v2 directory\n", - "cd ../../\n", - "\n", - "# Check if services are running\n", - "./check_setup.sh\n", - "\n", - "# If services are down, run setup\n", - "./setup_memory_server.sh\n", - "```\n", - "\n", - "**📖 Detailed Setup:** See `../SETUP_GUIDE.md` for complete instructions.\n", - "\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "setup_packages", - "metadata": {}, - "source": [ - "### Automated Setup Check\n", - "\n", - "Let's run the setup script to ensure all services are running properly.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "env_setup", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:43.326206Z", - "iopub.status.busy": "2025-11-01T00:27:43.326021Z", - "iopub.status.idle": "2025-11-01T00:27:43.597828Z", - "shell.execute_reply": "2025-11-01T00:27:43.597284Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Running automated setup check...\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🔧 Agent Memory Server Setup\n", - "===========================\n", - "📊 Checking Redis...\n", - "✅ Redis is running\n", - "📊 Checking Agent Memory Server...\n", - "🔍 Agent Memory Server container exists. Checking health...\n", - "✅ Agent Memory Server is running and healthy\n", - "✅ No Redis connection issues detected\n", - "\n", - "✅ Setup Complete!\n", - "=================\n", - "📊 Services Status:\n", - " • Redis: Running on port 6379\n", - " • Agent Memory Server: Running on port 8088\n", - "\n", - "🎯 You can now run the notebooks!\n", - "\n", - "\n", - "✅ All services are ready!\n" - ] - } - ], - "source": [ - "# Run the setup script to ensure Redis and Agent Memory Server are running\n", - "import subprocess\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "# Path to setup script\n", - "setup_script = Path(\"../../reference-agent/setup_agent_memory_server.py\")\n", - "\n", - "if setup_script.exists():\n", - " print(\"Running automated setup check...\\n\")\n", - " result = subprocess.run(\n", - " [sys.executable, str(setup_script)], capture_output=True, text=True\n", - " )\n", - " print(result.stdout)\n", - " if result.returncode != 0:\n", - " print(\"⚠️ Setup check failed. Please review the output above.\")\n", - " print(result.stderr)\n", - " else:\n", - " print(\"\\n✅ All services are ready!\")\n", - "else:\n", - " print(\"⚠️ Setup script not found. Please ensure services are running manually.\")" - ] - }, - { - "cell_type": "markdown", - "id": "env_config", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "services_check", - "metadata": {}, - "source": [ - "### Install Dependencies\n", - "\n", - "If you haven't already installed the reference-agent package, uncomment and run the following:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "health_check", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:43.599247Z", - "iopub.status.busy": "2025-11-01T00:27:43.599160Z", - "iopub.status.idle": "2025-11-01T00:27:43.600994Z", - "shell.execute_reply": "2025-11-01T00:27:43.600510Z" - } - }, - "outputs": [], - "source": [ - "# Uncomment to install reference-agent package\n", - "# %pip install -q -e ../../reference-agent\n", - "\n", - "# Uncomment to install agent-memory-client\n", - "# %pip install -q agent-memory-client" - ] - }, - { - "cell_type": "markdown", - "id": "memory_tools_intro", - "metadata": {}, - "source": [ - "### Environment Configuration\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "memory_client_init", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:43.602048Z", - "iopub.status.busy": "2025-11-01T00:27:43.601982Z", - "iopub.status.idle": "2025-11-01T00:27:43.607235Z", - "shell.execute_reply": "2025-11-01T00:27:43.606871Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment configured successfully!\n", - " OpenAI Model: gpt-4o\n", - " Redis URL: redis://localhost:6379\n", - " Memory Server: http://localhost:8088\n" - ] - } - ], - "source": [ - "import os\n", - "\n", - "from dotenv import load_dotenv\n", - "\n", - "# Load environment variables\n", - "load_dotenv(\"../../reference-agent/.env\")\n", - "\n", - "# Verify required environment variables\n", - "required_vars = {\n", - " \"OPENAI_API_KEY\": \"OpenAI API key for LLM\",\n", - " \"REDIS_URL\": \"Redis connection for vector storage\",\n", - " \"AGENT_MEMORY_URL\": \"Agent Memory Server for memory tools\",\n", - "}\n", - "\n", - "missing_vars = []\n", - "for var, description in required_vars.items():\n", - " if not os.getenv(var):\n", - " missing_vars.append(f\" - {var}: {description}\")\n", - "\n", - "if missing_vars:\n", - " raise ValueError(\n", - " f\"\"\"\n", - " ⚠️ Missing required environment variables:\n", - " \n", - "{''.join(missing_vars)}\n", - " \n", - " Please create a .env file in the reference-agent directory:\n", - " 1. cd ../../reference-agent\n", - " 2. cp .env.example .env\n", - " 3. Edit .env and add your API keys\n", - " \"\"\"\n", - " )\n", - "\n", - "print(\"✅ Environment configured successfully!\")\n", - "print(f\" OpenAI Model: {os.getenv('OPENAI_MODEL', 'gpt-4o')}\")\n", - "print(f\" Redis URL: {os.getenv('REDIS_URL', 'redis://localhost:6379')}\")\n", - "print(f\" Memory Server: {os.getenv('AGENT_MEMORY_URL', 'http://localhost:8088')}\")" - ] - }, - { - "cell_type": "markdown", - "id": "tool_1_store", - "metadata": {}, - "source": [ - "### Service Health Check\n", - "\n", - "Before building memory tools, let's verify that Redis and the Agent Memory Server are running.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "store_memory_tool", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:43.608506Z", - "iopub.status.busy": "2025-11-01T00:27:43.608428Z", - "iopub.status.idle": "2025-11-01T00:27:43.659756Z", - "shell.execute_reply": "2025-11-01T00:27:43.659439Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🔍 Checking required services...\n", - "\n", - "Redis: ✅ Connected successfully\n", - "Agent Memory Server: ✅ Status: 200\n", - "\n", - "✅ All services are running!\n" - ] - } - ], - "source": [ - "import redis\n", - "import requests\n", - "\n", - "\n", - "def check_redis():\n", - " \"\"\"Check if Redis is accessible.\"\"\"\n", - " try:\n", - " r = redis.from_url(os.getenv(\"REDIS_URL\", \"redis://localhost:6379\"))\n", - " r.ping()\n", - " return True, \"Connected successfully\"\n", - " except Exception as e:\n", - " return False, str(e)\n", - "\n", - "\n", - "def check_memory_server():\n", - " \"\"\"Check if Agent Memory Server is accessible.\"\"\"\n", - " try:\n", - " url = os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8088\")\n", - " response = requests.get(f\"{url}/v1/health\", timeout=5)\n", - " return response.status_code == 200, f\"Status: {response.status_code}\"\n", - " except Exception as e:\n", - " return False, str(e)\n", - "\n", - "\n", - "# Check services\n", - "print(\"🔍 Checking required services...\\n\")\n", - "\n", - "redis_ok, redis_msg = check_redis()\n", - "print(f\"Redis: {'✅' if redis_ok else '❌'} {redis_msg}\")\n", - "\n", - "memory_ok, memory_msg = check_memory_server()\n", - "print(f\"Agent Memory Server: {'✅' if memory_ok else '❌'} {memory_msg}\")\n", - "\n", - "if not (redis_ok and memory_ok):\n", - " print(\"\\n⚠️ Some services are not running. Please start them:\")\n", - " if not redis_ok:\n", - " print(\" Redis: docker run -d -p 6379:6379 redis/redis-stack:latest\")\n", - " if not memory_ok:\n", - " print(\n", - " \" Memory Server: cd ../../reference-agent && python setup_agent_memory_server.py\"\n", - " )\n", - "else:\n", - " print(\"\\n✅ All services are running!\")" - ] - }, - { - "cell_type": "markdown", - "id": "tool_2_search", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🛠️ Building Memory Tools\n", - "\n", - "Now let's build the three essential memory tools. We'll start simple and build up complexity.\n", - "\n", - "### **Step 1: Initialize Memory Client**\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "search_memories_tool", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:43.661063Z", - "iopub.status.busy": "2025-11-01T00:27:43.660992Z", - "iopub.status.idle": "2025-11-01T00:27:43.778969Z", - "shell.execute_reply": "2025-11-01T00:27:43.778555Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Memory client initialized\n", - " Base URL: http://localhost:8088\n", - " Namespace: redis_university\n", - " Test User: student_memory_tools_demo\n" - ] - } - ], - "source": [ - "from agent_memory_client import MemoryAPIClient, MemoryClientConfig\n", - "from agent_memory_client.filters import UserId\n", - "from agent_memory_client.models import ClientMemoryRecord\n", - "\n", - "# Initialize memory client\n", - "config = MemoryClientConfig(\n", - " base_url=os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8088\"),\n", - " default_namespace=\"redis_university\",\n", - ")\n", - "memory_client = MemoryAPIClient(config=config)\n", - "\n", - "# Test user for this notebook\n", - "test_user_id = \"student_memory_tools_demo\"\n", - "test_session_id = \"session_memory_tools_demo\"\n", - "\n", - "print(f\"✅ Memory client initialized\")\n", - "print(f\" Base URL: {config.base_url}\")\n", - "print(f\" Namespace: {config.default_namespace}\")\n", - "print(f\" Test User: {test_user_id}\")" - ] - }, - { - "cell_type": "markdown", - "id": "tool_3_retrieve", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🛠️ Understanding Tools in LLM Applications\n", - "\n", - "### **What Are Tools?**\n", - "\n", - "**Tools** are functions that LLMs can call to interact with external systems, retrieve information, or perform actions beyond text generation.\n", - "\n", - "**Think of tools as:**\n", - "- 🔌 **Extensions** to the LLM's capabilities\n", - "- 🤝 **Interfaces** between the LLM and external systems\n", - "- 🎯 **Actions** the LLM can take to accomplish tasks\n", - "\n", - "### **How Tool Calling Works**\n", - "\n", - "```\n", - "1. User Input → \"Store my preference for online courses\"\n", - " ↓\n", - "2. LLM Analysis → Decides: \"I need to use store_memory tool\"\n", - " ↓\n", - "3. Tool Call → Returns structured function call with arguments\n", - " ↓\n", - "4. Tool Execution → Your code executes the function\n", - " ↓\n", - "5. Tool Result → Returns result to LLM\n", - " ↓\n", - "6. LLM Response → Generates final text response using tool result\n", - "```\n", - "\n", - "### **Tool Definition Components**\n", - "\n", - "Every tool needs three key components:\n", - "\n", - "**1. Input Schema (Pydantic Model)**\n", - "```python\n", - "class StoreMemoryInput(BaseModel):\n", - " text: str = Field(description=\"What to store\")\n", - " memory_type: str = Field(default=\"semantic\")\n", - " topics: List[str] = Field(default=[])\n", - "```\n", - "- Defines what parameters the tool accepts\n", - "- Provides descriptions that help the LLM understand usage\n", - "- Validates input types\n", - "\n", - "**2. Tool Function**\n", - "```python\n", - "@tool(\"store_memory\", args_schema=StoreMemoryInput)\n", - "async def store_memory(text: str, memory_type: str = \"semantic\", topics: List[str] = None) -> str:\n", - " # Implementation\n", - " return \"Success message\"\n", - "```\n", - "- The actual function that performs the action\n", - "- Must return a string (the LLM reads this result)\n", - "- Can be sync or async\n", - "\n", - "**3. Docstring (Critical!)**\n", - "```python\n", - "\"\"\"\n", - "Store important information in long-term memory.\n", - "\n", - "Use this tool when:\n", - "- User shares preferences, goals, or constraints\n", - "- Important facts emerge during conversation\n", - "\n", - "Examples:\n", - "- \"User prefers online courses\"\n", - "- \"User is CS major interested in AI\"\n", - "\"\"\"\n", - "```\n", - "- The LLM reads this to decide when to use the tool\n", - "- Should include clear use cases and examples\n", - "- More detailed = better tool selection\n", - "\n", - "### **Best Practices for Tool Design**\n", - "\n", - "#### **1. Clear, Descriptive Names**\n", - "```python\n", - "✅ Good: store_memory, search_courses, get_user_profile\n", - "❌ Bad: do_thing, process, handle_data\n", - "```\n", - "\n", - "#### **2. Detailed Descriptions**\n", - "```python\n", - "✅ Good: \"Store important user preferences and facts in long-term memory for future conversations\"\n", - "❌ Bad: \"Stores data\"\n", - "```\n", - "\n", - "#### **3. Specific Use Cases in Docstring**\n", - "```python\n", - "✅ Good:\n", - "\"\"\"\n", - "Use this tool when:\n", - "- User explicitly shares preferences\n", - "- Important facts emerge that should persist\n", - "- Information will be useful for future recommendations\n", - "\"\"\"\n", - "\n", - "❌ Bad:\n", - "\"\"\"\n", - "Stores information.\n", - "\"\"\"\n", - "```\n", - "\n", - "#### **4. Return Meaningful Results**\n", - "```python\n", - "✅ Good: return f\"Stored: {text} with topics {topics}\"\n", - "❌ Bad: return \"Done\"\n", - "```\n", - "The LLM uses the return value to understand what happened and craft its response.\n", - "\n", - "#### **5. Handle Errors Gracefully**\n", - "```python\n", - "✅ Good:\n", - "try:\n", - " result = await memory_client.create_long_term_memory([record])\n", - " return f\"Successfully stored: {text}\"\n", - "except Exception as e:\n", - " return f\"Could not store memory: {str(e)}\"\n", - "```\n", - "Always return a string explaining what went wrong.\n", - "\n", - "#### **6. Keep Tools Focused**\n", - "```python\n", - "✅ Good: Separate tools for store_memory, search_memories, retrieve_memories\n", - "❌ Bad: One generic memory_operation(action, data) tool\n", - "```\n", - "Focused tools are easier for LLMs to select correctly.\n", - "\n", - "### **Common Tool Patterns**\n", - "\n", - "**Information Retrieval:**\n", - "- Search databases\n", - "- Query APIs\n", - "- Fetch user data\n", - "\n", - "**Data Storage:**\n", - "- Save preferences\n", - "- Store conversation facts\n", - "- Update user profiles\n", - "\n", - "**External Actions:**\n", - "- Send emails\n", - "- Create calendar events\n", - "- Make API calls\n", - "\n", - "**Computation:**\n", - "- Calculate values\n", - "- Process data\n", - "- Generate reports\n", - "\n", - "---\n", - "\n", - "### **Step 2: Build the `store_memory` Tool**\n", - "\n", - "Now let's build our first memory tool following these best practices.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "retrieve_memories_tool", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:43.780190Z", - "iopub.status.busy": "2025-11-01T00:27:43.780108Z", - "iopub.status.idle": "2025-11-01T00:27:43.876809Z", - "shell.execute_reply": "2025-11-01T00:27:43.876383Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🧠 Store Memory Test: Stored: User prefers online courses for testing\n" - ] - } - ], - "source": [ - "from typing import List, Optional\n", - "\n", - "from langchain_core.tools import tool\n", - "from pydantic import BaseModel, Field\n", - "\n", - "\n", - "class StoreMemoryInput(BaseModel):\n", - " \"\"\"Input schema for storing memories.\"\"\"\n", - "\n", - " text: str = Field(\n", - " description=\"The information to store. Should be clear, specific, and important for future conversations.\"\n", - " )\n", - " memory_type: str = Field(\n", - " default=\"semantic\",\n", - " description=\"Type of memory: 'semantic' for facts/preferences, 'episodic' for events/experiences\",\n", - " )\n", - " topics: List[str] = Field(\n", - " default=[],\n", - " description=\"List of topics/tags for this memory (e.g., ['preferences', 'courses', 'career'])\",\n", - " )\n", - "\n", - "\n", - "@tool(\"store_memory\", args_schema=StoreMemoryInput)\n", - "async def store_memory(\n", - " text: str, memory_type: str = \"semantic\", topics: List[str] = None\n", - ") -> str:\n", - " \"\"\"\n", - " Store important information in long-term memory.\n", - "\n", - " Use this tool when:\n", - " - User shares preferences, goals, or constraints\n", - " - Important facts emerge during conversation\n", - " - Information should persist across sessions\n", - " - Context that will be useful for future recommendations\n", - "\n", - " Examples:\n", - " - \"User prefers online courses due to work schedule\"\n", - " - \"User is Computer Science major interested in AI\"\n", - " - \"User completed CS101 with grade A\"\n", - "\n", - " Returns: Confirmation that memory was stored\n", - " \"\"\"\n", - " try:\n", - " # Create memory record\n", - " memory_record = ClientMemoryRecord(\n", - " text=text,\n", - " memory_type=memory_type,\n", - " topics=topics or [],\n", - " user_id=test_user_id,\n", - " )\n", - "\n", - " # Store in long-term memory\n", - " await memory_client.create_long_term_memory([memory_record])\n", - "\n", - " return f\"Stored: {text}\"\n", - " except Exception as e:\n", - " return f\"Error storing memory: {str(e)}\"\n", - "\n", - "\n", - "# Test the tool\n", - "test_result = await store_memory.ainvoke(\n", - " {\n", - " \"text\": \"User prefers online courses for testing\",\n", - " \"memory_type\": \"semantic\",\n", - " \"topics\": [\"preferences\", \"test\"],\n", - " }\n", - ")\n", - "print(f\"🧠 Store Memory Test: {test_result}\")" - ] - }, - { - "cell_type": "markdown", - "id": "memory_tools_demo", - "metadata": {}, - "source": [ - "### **Step 3: Build the `search_memories` Tool**\n", - "\n", - "This tool allows the LLM to search its long-term memory for relevant information.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "llm_memory_demo", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:43.878136Z", - "iopub.status.busy": "2025-11-01T00:27:43.878066Z", - "iopub.status.idle": "2025-11-01T00:27:44.123430Z", - "shell.execute_reply": "2025-11-01T00:27:44.122639Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🔍 Search Memories Test: - User prefers online courses for testing\n", - "- User is a Computer Science major interested in AI and machine learning. Prefers online courses due to part-time work.\n" - ] - } - ], - "source": [ - "class SearchMemoriesInput(BaseModel):\n", - " \"\"\"Input schema for searching memories.\"\"\"\n", - "\n", - " query: str = Field(\n", - " description=\"Search query to find relevant memories. Use keywords related to what you need to know.\"\n", - " )\n", - " limit: int = Field(\n", - " default=5, description=\"Maximum number of memories to return. Default is 5.\"\n", - " )\n", - "\n", - "\n", - "@tool(\"search_memories\", args_schema=SearchMemoriesInput)\n", - "async def search_memories(query: str, limit: int = 5) -> str:\n", - " \"\"\"\n", - " Search long-term memory for relevant information.\n", - "\n", - " Use this tool when:\n", - " - Need context about user's preferences or history\n", - " - User asks about past conversations\n", - " - Building personalized responses\n", - " - Need to recall what you know about the user\n", - "\n", - " Examples:\n", - " - query=\"course preferences\" → finds preferred course types\n", - " - query=\"completed courses\" → finds courses user has taken\n", - " - query=\"career goals\" → finds user's career interests\n", - "\n", - " Returns: Relevant memories or \"No memories found\"\n", - " \"\"\"\n", - " try:\n", - " # Search long-term memory\n", - " results = await memory_client.search_long_term_memory(\n", - " text=query, user_id=UserId(eq=test_user_id), limit=limit\n", - " )\n", - "\n", - " if not results or not results.memories:\n", - " return \"No memories found matching your query.\"\n", - "\n", - " # Format results\n", - " memory_texts = []\n", - " for memory in results.memories:\n", - " memory_texts.append(f\"- {memory.text}\")\n", - "\n", - " return \"\\n\".join(memory_texts)\n", - " except Exception as e:\n", - " return f\"Error searching memories: {str(e)}\"\n", - "\n", - "\n", - "# Test the tool\n", - "test_result = await search_memories.ainvoke({\"query\": \"preferences\", \"limit\": 5})\n", - "print(f\"🔍 Search Memories Test: {test_result}\")" - ] - }, - { - "cell_type": "markdown", - "id": "langgraph_intro", - "metadata": {}, - "source": [ - "### **Step 4: Build the `retrieve_memories` Tool**\n", - "\n", - "This tool allows the LLM to retrieve specific stored facts.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "passive_memory", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:44.125246Z", - "iopub.status.busy": "2025-11-01T00:27:44.125103Z", - "iopub.status.idle": "2025-11-01T00:27:44.331240Z", - "shell.execute_reply": "2025-11-01T00:27:44.330413Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "📋 Retrieve Memories Test: [preferences, test] User prefers online courses for testing\n", - "[preferences, academic, career] User is a Computer Science major interested in AI and machine learning. Prefers online courses due to part-time work.\n" - ] - } - ], - "source": [ - "class RetrieveMemoriesInput(BaseModel):\n", - " \"\"\"Input schema for retrieving specific memories.\"\"\"\n", - "\n", - " topics: List[str] = Field(\n", - " description=\"List of specific topics to retrieve (e.g., ['GPA', 'requirements', 'graduation'])\"\n", - " )\n", - " limit: int = Field(\n", - " default=3, description=\"Maximum number of memories to return. Default is 3.\"\n", - " )\n", - "\n", - "\n", - "@tool(\"retrieve_memories\", args_schema=RetrieveMemoriesInput)\n", - "async def retrieve_memories(topics: List[str], limit: int = 3) -> str:\n", - " \"\"\"\n", - " Retrieve specific stored facts by topic.\n", - "\n", - " Use this tool when:\n", - " - Need to recall exact details from past conversations\n", - " - User references something specific they mentioned before\n", - " - Verifying stored information\n", - " - Looking for facts about specific topics\n", - "\n", - " Examples:\n", - " - topics=[\"GPA\", \"requirements\"] → finds GPA-related memories\n", - " - topics=[\"completed\", \"courses\"] → finds completed course records\n", - " - topics=[\"career\", \"goals\"] → finds career-related memories\n", - "\n", - " Returns: Specific memories matching the topics\n", - " \"\"\"\n", - " try:\n", - " # Search for memories with specific topics\n", - " query = \" \".join(topics)\n", - " results = await memory_client.search_long_term_memory(\n", - " text=query, user_id=UserId(eq=test_user_id), limit=limit\n", - " )\n", - "\n", - " if not results or not results.memories:\n", - " return f\"No memories found for topics: {', '.join(topics)}\"\n", - "\n", - " # Format results with topics\n", - " memory_texts = []\n", - " for memory in results.memories:\n", - " topics_str = \", \".join(memory.topics) if memory.topics else \"general\"\n", - " memory_texts.append(f\"[{topics_str}] {memory.text}\")\n", - "\n", - " return \"\\n\".join(memory_texts)\n", - " except Exception as e:\n", - " return f\"Error retrieving memories: {str(e)}\"\n", - "\n", - "\n", - "# Test the tool\n", - "test_result = await retrieve_memories.ainvoke(\n", - " {\"topics\": [\"preferences\", \"test\"], \"limit\": 3}\n", - ")\n", - "print(f\"📋 Retrieve Memories Test: {test_result}\")" - ] - }, - { - "cell_type": "markdown", - "id": "active_memory", - "metadata": {}, - "source": [ - "### **Step 5: Test Memory Tools with LLM**\n", - "\n", - "Now let's see how an LLM uses these memory tools.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "when_to_use", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:44.333737Z", - "iopub.status.busy": "2025-11-01T00:27:44.333538Z", - "iopub.status.idle": "2025-11-01T00:27:47.222368Z", - "shell.execute_reply": "2025-11-01T00:27:47.221631Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🤖 LLM Response:\n", - " Tool calls: 1\n", - " Tool 1: store_memory\n", - " Args: {'text': 'User is a Computer Science major interested in AI and machine learning. Prefers online courses due to part-time work.', 'memory_type': 'semantic', 'topics': ['preferences', 'academic', 'career']}\n", - "\n", - "💬 Response: \n", - "\n", - "📝 Note: The response is empty because the LLM decided to call a tool instead of\n", - " generating text. This is expected behavior! The LLM is saying:\n", - " 'I need to store this information first, then I'll respond.'\n", - "\n", - " To get the final response, we would need to:\n", - " 1. Execute the tool call (store_memory)\n", - " 2. Send the tool result back to the LLM\n", - " 3. Get the LLM's final text response\n", - "\n", - " This multi-step process is exactly why we need LangGraph! 👇\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage, SystemMessage\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "# Initialize LLM with memory tools\n", - "llm = ChatOpenAI(model=os.getenv(\"OPENAI_MODEL\", \"gpt-4o\"), temperature=0)\n", - "memory_tools = [store_memory, search_memories, retrieve_memories]\n", - "llm_with_tools = llm.bind_tools(memory_tools)\n", - "\n", - "# System message for memory-aware agent\n", - "system_prompt = \"\"\"\n", - "You are a Redis University course advisor with memory tools.\n", - "\n", - "IMPORTANT: Use your memory tools strategically:\n", - "- When users share preferences, goals, or important facts → use store_memory\n", - "- When you need context about the user → use search_memories\n", - "- When users reference specific past information → use retrieve_memories\n", - "\n", - "Always explain what you're doing with memory to help users understand.\n", - "\"\"\"\n", - "\n", - "# Test conversation\n", - "messages = [\n", - " SystemMessage(content=system_prompt),\n", - " HumanMessage(\n", - " content=\"Hi! I'm a Computer Science major interested in AI and machine learning. I prefer online courses because I work part-time.\"\n", - " ),\n", - "]\n", - "\n", - "response = llm_with_tools.invoke(messages)\n", - "print(\"🤖 LLM Response:\")\n", - "print(f\" Tool calls: {len(response.tool_calls) if response.tool_calls else 0}\")\n", - "if response.tool_calls:\n", - " for i, tool_call in enumerate(response.tool_calls):\n", - " print(f\" Tool {i+1}: {tool_call['name']}\")\n", - " print(f\" Args: {tool_call['args']}\")\n", - "print(f\"\\n💬 Response: {response.content}\")\n", - "\n", - "# Explain the empty response\n", - "if response.tool_calls and not response.content:\n", - " print(\n", - " \"\\n📝 Note: The response is empty because the LLM decided to call a tool instead of\"\n", - " )\n", - " print(\" generating text. This is expected behavior! The LLM is saying:\")\n", - " print(\" 'I need to store this information first, then I'll respond.'\")\n", - " print(\"\\n To get the final response, we would need to:\")\n", - " print(\" 1. Execute the tool call (store_memory)\")\n", - " print(\" 2. Send the tool result back to the LLM\")\n", - " print(\" 3. Get the LLM's final text response\")\n", - " print(\"\\n This multi-step process is exactly why we need LangGraph! 👇\")" - ] - }, - { - "cell_type": "markdown", - "id": "ab98556b-21bd-4578-8f8f-f316e8fe31f4", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🔄 Complete Tool Execution Loop Example\n", - "\n", - "Let's manually complete the tool execution loop to see the full workflow. This will help you understand what LangGraph automates.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "90a7df9ffdf5bc", - "metadata": { - "execution": { - "iopub.execute_input": "2025-11-01T00:27:47.224544Z", - "iopub.status.busy": "2025-11-01T00:27:47.224342Z", - "iopub.status.idle": "2025-11-01T00:27:49.676939Z", - "shell.execute_reply": "2025-11-01T00:27:49.676143Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "COMPLETE TOOL EXECUTION LOOP - Manual Implementation\n", - "================================================================================\n", - "\n", - "👤 USER INPUT:\n", - "Hi! I'm a Computer Science major interested in AI and machine learning. I prefer online courses because I work part-time.\n", - "\n", - "================================================================================\n", - "STEP 1: LLM Analysis\n", - "================================================================================\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ LLM decided to call: store_memory\n", - " Arguments: {'text': 'User is a Computer Science major interested in AI and machine learning. Prefers online courses due to part-time work.', 'memory_type': 'semantic', 'topics': ['preferences', 'academic', 'career']}\n", - "\n", - "================================================================================\n", - "STEP 2: Tool Execution\n", - "================================================================================\n", - "✅ Tool executed successfully\n", - " Result: Stored: User is a Computer Science major interested in AI and machine learning. Prefers online courses due to part-time work.\n", - "\n", - "================================================================================\n", - "STEP 3: LLM Generates Final Response\n", - "================================================================================\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Final response generated\n", - "\n", - "🤖 AGENT RESPONSE:\n", - "Great! I've noted that you're a Computer Science major interested in AI and machine learning, and you prefer online courses because you work part-time. If you have any specific questions or need recommendations, feel free to ask!\n", - "\n", - "================================================================================\n", - "STEP 4: Verify Memory Storage\n", - "================================================================================\n", - "✅ Memory verification:\n", - "- User prefers online courses for testing\n", - "- User is a Computer Science major interested in AI and machine learning. Prefers online courses due to part-time work.\n", - "\n", - "================================================================================\n", - "COMPLETE! This is what LangGraph automates for you.\n", - "================================================================================\n" - ] - } - ], - "source": [ - "from langchain_core.messages import ToolMessage\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"COMPLETE TOOL EXECUTION LOOP - Manual Implementation\")\n", - "print(\"=\" * 80)\n", - "\n", - "# Step 1: User input\n", - "user_message = \"Hi! I'm a Computer Science major interested in AI and machine learning. I prefer online courses because I work part-time.\"\n", - "print(f\"\\n👤 USER INPUT:\\n{user_message}\")\n", - "\n", - "# Step 2: LLM decides to use tool\n", - "messages = [SystemMessage(content=system_prompt), HumanMessage(content=user_message)]\n", - "\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"STEP 1: LLM Analysis\")\n", - "print(\"=\" * 80)\n", - "response_1 = llm_with_tools.invoke(messages)\n", - "print(f\"✅ LLM decided to call: {response_1.tool_calls[0]['name']}\")\n", - "print(f\" Arguments: {response_1.tool_calls[0]['args']}\")\n", - "\n", - "# Step 3: Execute the tool\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"STEP 2: Tool Execution\")\n", - "print(\"=\" * 80)\n", - "tool_call = response_1.tool_calls[0]\n", - "tool_result = await store_memory.ainvoke(tool_call[\"args\"])\n", - "print(f\"✅ Tool executed successfully\")\n", - "print(f\" Result: {tool_result}\")\n", - "\n", - "# Step 4: Send tool result back to LLM\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"STEP 3: LLM Generates Final Response\")\n", - "print(\"=\" * 80)\n", - "messages.append(response_1) # Add the tool call message\n", - "messages.append(\n", - " ToolMessage(content=tool_result, tool_call_id=tool_call[\"id\"])\n", - ") # Add tool result\n", - "\n", - "response_2 = llm_with_tools.invoke(messages)\n", - "print(f\"✅ Final response generated\")\n", - "print(f\"\\n🤖 AGENT RESPONSE:\\n{response_2.content}\")\n", - "\n", - "# Step 5: Verify memory was stored\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"STEP 4: Verify Memory Storage\")\n", - "print(\"=\" * 80)\n", - "search_result = await search_memories.ainvoke({\"query\": \"preferences\", \"limit\": 3})\n", - "print(f\"✅ Memory verification:\")\n", - "print(f\"{search_result}\")\n", - "\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"COMPLETE! This is what LangGraph automates for you.\")\n", - "print(\"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "cf13debf42a9b4b7", - "metadata": {}, - "source": [ - "### **Key Takeaways from Manual Loop**\n", - "\n", - "**What we just did manually:**\n", - "\n", - "1. ✅ **Sent user input to LLM** → Got tool call decision\n", - "2. ✅ **Executed the tool** → Got result\n", - "3. ✅ **Sent result back to LLM** → Got final response\n", - "4. ✅ **Verified the action** → Confirmed memory stored\n", - "\n", - "**Why this is tedious:**\n", - "- 🔴 Multiple manual steps\n", - "- 🔴 Need to track message history\n", - "- 🔴 Handle tool call IDs\n", - "- 🔴 Manage state between calls\n", - "- 🔴 Complex error handling\n", - "\n", - "**What LangGraph does:**\n", - "- ✅ Automates all these steps\n", - "- ✅ Manages state automatically\n", - "- ✅ Handles tool execution loop\n", - "- ✅ Provides clear workflow visualization\n", - "- ✅ Makes it easy to add more tools and logic\n", - "\n", - "**Now you understand why we need LangGraph!** 👇\n" - ] - }, - { - "cell_type": "markdown", - "id": "a295f410390e0ecd", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🎨 Introduction to LangGraph\n", - "\n", - "Memory tools are powerful, but managing complex workflows manually gets complicated. **LangGraph** automates this process.\n", - "\n", - "### **What is LangGraph?**\n", - "\n", - "**LangGraph** is a framework for building stateful, multi-step agent workflows using graphs.\n", - "\n", - "### **Core Concepts**\n", - "\n", - "**1. State** - Shared data structure passed between nodes\n", - "- Contains messages, context, and intermediate results\n", - "- Automatically managed and updated\n", - "\n", - "**2. Nodes** - Functions that process state\n", - "- Examples: call LLM, execute tools, format responses\n", - "- Each node receives state and returns updated state\n", - "\n", - "**3. Edges** - Connections between nodes\n", - "- Can be conditional (if/else logic)\n", - "- Determine workflow flow\n", - "\n", - "**4. Graph** - Complete workflow from start to end\n", - "- Orchestrates the entire agent process\n", - "\n", - "### **Simple Memory-Enhanced Graph**\n", - "\n", - "```\n", - "START\n", - " ↓\n", - "[Load Memory] ← Get user context\n", - " ↓\n", - "[Agent Node] ← Decides what to do\n", - " ↓\n", - " ├─→ [Memory Tools] ← store/search/retrieve\n", - " │ ↓\n", - " │ [Agent Node] ← Processes memory results\n", - " │\n", - " └─→ [Respond] ← Generates final response\n", - " ↓\n", - "[Save Memory] ← Update conversation history\n", - " ↓\n", - " END\n", - "```\n", - "\n", - "### **Why LangGraph for Memory Tools?**\n", - "\n", - "**Without LangGraph:**\n", - "- Manual tool execution and state management\n", - "- Complex conditional logic\n", - "- Hard to visualize workflow\n", - "- Difficult to add new steps\n", - "\n", - "**With LangGraph:**\n", - "- ✅ Automatic tool execution\n", - "- ✅ Clear workflow visualization\n", - "- ✅ Easy to modify and extend\n", - "- ✅ Built-in state management\n", - "- ✅ Memory persistence across turns\n", - "\n", - "---\n", - "\n", - "## 🔄 Passive vs Active Memory: The Key Difference\n", - "\n", - "Let's compare the two approaches to understand why memory tools matter.\n" - ] - }, - { - "cell_type": "markdown", - "id": "d2a99956e8ff8d58", - "metadata": {}, - "source": [ - "### **Passive Memory (Section 3)**\n", - "\n", - "**How it works:**\n", - "- System automatically saves all conversations\n", - "- System automatically extracts facts\n", - "- LLM receives memory but can't control it\n", - "\n", - "**Example conversation:**\n", - "```\n", - "User: \"I'm interested in machine learning\"\n", - "Agent: \"Great! Here are some ML courses...\" \n", - "System: [Automatically saves: \"User interested in ML\"]\n", - "```\n", - "\n", - "**Pros:**\n", - "- ✅ Simple to implement\n", - "- ✅ No additional LLM calls\n", - "- ✅ Consistent memory storage\n", - "\n", - "**Cons:**\n", - "- ❌ LLM can't decide what's important\n", - "- ❌ No strategic memory management\n", - "- ❌ Can't search memories on demand\n" - ] - }, - { - "cell_type": "markdown", - "id": "9768498f-4e95-4217-ad20-93fea45524a2", - "metadata": {}, - "source": [ - "### **Active Memory (This Section)**\n", - "\n", - "**How it works:**\n", - "- LLM decides what to store\n", - "- LLM decides when to search memories\n", - "- LLM controls its own context construction\n", - "\n", - "**Example conversation:**\n", - "```\n", - "User: \"I'm interested in machine learning\"\n", - "Agent: [Thinks: \"This is important, I should remember this\"]\n", - "Agent: [Calls: store_memory(\"User interested in machine learning\")]\n", - "Agent: \"I'll remember your interest in ML. Here are some courses...\"\n", - "```\n", - "\n", - "**Pros:**\n", - "- ✅ Strategic memory management\n", - "- ✅ LLM controls what's important\n", - "- ✅ On-demand memory search\n", - "- ✅ Better context engineering\n", - "\n", - "**Cons:**\n", - "- ❌ More complex to implement\n", - "- ❌ Additional LLM calls (cost)\n", - "- ❌ Requires careful tool design\n" - ] - }, - { - "cell_type": "markdown", - "id": "a9e2011d-1696-4eb9-9bec-d1bbba9ef392", - "metadata": {}, - "source": [ - "### **When to Use Each Approach**\n", - "\n", - "**Use Passive Memory when:**\n", - "- Simple applications with predictable patterns\n", - "- Cost is a primary concern\n", - "- Memory needs are straightforward\n", - "- You want automatic memory management\n", - "\n", - "**Use Active Memory when:**\n", - "- Complex applications requiring strategic memory\n", - "- LLM needs to control its own context\n", - "- Dynamic memory management is important\n", - "- Building sophisticated agents\n", - "\n", - "**💡 Key Insight:** Active memory tools enable **intelligent context engineering** where the LLM becomes an active participant in managing its own knowledge.\n", - "\n", - "---\n", - "\n", - "## 🎯 Summary and Next Steps\n", - "\n", - "### **What You've Learned**\n", - "\n", - "**Memory Tools for Context Engineering:**\n", - "- `store_memory` - Save important information strategically\n", - "- `search_memories` - Find relevant context on demand\n", - "- `retrieve_memories` - Get specific facts by topic\n", - "\n", - "**LangGraph Fundamentals:**\n", - "- State management for complex workflows\n", - "- Nodes and edges for agent orchestration\n", - "- Automatic tool execution and state updates\n", - "\n", - "**Active vs Passive Memory:**\n", - "- Passive: System controls memory automatically\n", - "- Active: LLM controls its own memory strategically\n", - "\n", - "### **Context Engineering Connection**\n", - "\n", - "Memory tools transform the **four context types**:\n", - "\n", - "| Context Type | Section 3 (Passive) | Section 4 (Active) |\n", - "|-------------|---------------------|--------------------|\n", - "| **System** | Static prompt | Static prompt |\n", - "| **User** | Auto-extracted profile | LLM builds profile with `store_memory` |\n", - "| **Conversation** | Auto-saved history | LLM manages with `search_memories` |\n", - "| **Retrieved** | RAG search | Memory-enhanced RAG queries |\n", - "\n", - "### **Next: Building a Complete Agent**\n", - "\n", - "In **Notebook 2**, you'll combine everything:\n", - "- ✅ Memory tools (this notebook)\n", - "- ✅ Course search tools\n", - "- ✅ LangGraph orchestration\n", - "- ✅ Redis Agent Memory Server\n", - "\n", - "**Result:** A complete Redis University Course Advisor Agent that actively manages its own memory and context.\n", - "\n", - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "### **Memory Tools & Context Engineering**\n", - "- [Redis Agent Memory Server](https://github.com/redis/agent-memory-server) - Memory persistence\n", - "- [Agent Memory Client](https://pypi.org/project/agent-memory-client/) - Python client library\n", - "\n", - "### **LangGraph & Tool Calling**\n", - "- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/) - Official docs\n", - "- [LangChain Tools](https://python.langchain.com/docs/modules/tools/) - Tool creation guide\n", - "\n", - "### **Context Engineering Concepts**\n", - "- Review **Section 1** for context types fundamentals (System, User, Conversation, Retrieved)\n", - "- Review **Section 2** for RAG foundations (semantic search, vector embeddings, retrieval)\n", - "- Review **Section 3** for passive memory patterns (working memory, long-term memory, automatic extraction)\n", - "- Continue to **Section 4 Notebook 2** for complete agent implementation with all concepts integrated\n", - "\n", - "### **Academic Papers**\n", - "- [ReAct: Synergizing Reasoning and Acting in Language Models](https://arxiv.org/abs/2210.03629) - Reasoning + acting pattern\n", - "- [Toolformer: Language Models Can Teach Themselves to Use Tools](https://arxiv.org/abs/2302.04761) - Tool learning\n", - "- [MemGPT: Towards LLMs as Operating Systems](https://arxiv.org/abs/2310.08560) - Memory management for LLMs\n", - "- [Retrieval-Augmented Generation](https://arxiv.org/abs/2005.11401) - RAG foundations\n", - "\n", - "### **Agent Design Patterns**\n", - "- [Anthropic's Guide to Building Effective Agents](https://www.anthropic.com/research/building-effective-agents) - Best practices\n", - "- [LangChain Agent Patterns](https://python.langchain.com/docs/modules/agents/) - Different agent architectures\n", - "- [OpenAI Function Calling Guide](https://platform.openai.com/docs/guides/function-calling) - Tool calling fundamentals\n", - "\n", - "### **Production Resources**\n", - "- [LangChain Production Guide](https://python.langchain.com/docs/guides/productionization/) - Deploying agents\n", - "- [Redis Best Practices](https://redis.io/docs/manual/patterns/) - Production Redis patterns\n", - "- [Agent Memory Client](https://pypi.org/project/agent-memory-client/) - Python client for Agent Memory Server" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-4-tools-and-agents/02_building_course_advisor_agent.ipynb b/notebooks/section-4-tools-and-agents/02_building_course_advisor_agent.ipynb deleted file mode 100644 index 3c08919..0000000 --- a/notebooks/section-4-tools-and-agents/02_building_course_advisor_agent.ipynb +++ /dev/null @@ -1,2210 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "header", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# 🤖 Building a Course Advisor Agent\n", - "\n", - "**⏱️ Estimated Time:** 60-75 minutes\n", - "\n", - "## 🎯 Learning Objectives\n", - "\n", - "By the end of this notebook, you will:\n", - "\n", - "1. **Build** a complete LangGraph agent with tools and memory\n", - "2. **Implement** exactly 3 tools: memory storage, memory search, and course search\n", - "3. **Integrate** Redis Agent Memory Server for dual-memory architecture\n", - "4. **Visualize** the agent's decision-making graph\n", - "5. **Demonstrate** the progression from RAG (Section 3) to full agent\n", - "\n", - "---\n", - "\n", - "## 🔗 Bridge from Previous Sections\n", - "\n", - "### **Your Learning Journey:**\n", - "\n", - "**Section 1:** Context Types\n", - "- System, User, Conversation, Retrieved context\n", - "- How context shapes LLM responses\n", - "\n", - "**Section 2:** RAG Foundations\n", - "- Semantic search with vector embeddings\n", - "- Retrieving and presenting information\n", - "- Single-step retrieval → generation\n", - "\n", - "**Section 3:** Memory Architecture\n", - "- Working memory (conversation continuity)\n", - "- Long-term memory (persistent knowledge)\n", - "- Memory-enhanced RAG systems\n", - "\n", - "**Section 4 (Notebook 1):** Tool-Calling Basics\n", - "- What tools are and how LLMs use them\n", - "- LangGraph fundamentals (nodes, edges, state)\n", - "- Simple tool-calling examples\n", - "- Agents vs RAG comparison\n", - "\n", - "### **What We're Building Now:**\n", - "\n", - "**A Full Agent** that combines everything:\n", - "- ✅ **Tools** for actions (search courses, manage memory)\n", - "- ✅ **Memory** for personalization (working + long-term)\n", - "- ✅ **RAG** for course information (semantic search)\n", - "- ✅ **LangGraph** for orchestration (state management)\n", - "\n", - "**💡 Key Insight:** This agent is RAG + Memory + Tools + Decision-Making\n", - "\n", - "---\n", - "\n", - "## 📊 Agent Architecture\n", - "\n", - "### **The Complete Flow:**\n", - "\n", - "```\n", - "User Query\n", - " ↓\n", - "[Load Working Memory] ← Conversation history\n", - " ↓\n", - "[Agent Node] ← Decides what to do\n", - " ↓\n", - " ├─→ [search_courses] ← Find relevant courses\n", - " ├─→ [search_memories] ← Recall user preferences\n", - " ├─→ [store_memory] ← Save important facts\n", - " ↓\n", - "[Agent Node] ← Processes tool results\n", - " ↓\n", - "[Generate Response] ← Final answer\n", - " ↓\n", - "[Save Working Memory] ← Update conversation\n", - "```\n", - "\n", - "### **Our 3 Tools:**\n", - "\n", - "1. **`search_courses`** - Semantic search over course catalog\n", - " - When: Student asks about courses, topics, or recommendations\n", - " - Example: \"What machine learning courses are available?\"\n", - "\n", - "2. **`search_memories`** - Search long-term memory for user facts\n", - " - When: Need to recall preferences, goals, or past interactions\n", - " - Example: \"What courses did I say I was interested in?\"\n", - "\n", - "3. **`store_memory`** - Save important information to long-term memory\n", - " - When: User shares preferences, goals, or important facts\n", - " - Example: \"I'm interested in AI and want to work at a startup\"\n", - "\n", - "### **Memory Architecture:**\n", - "\n", - "| Memory Type | Purpose | Managed By | Lifespan |\n", - "|------------|---------|------------|----------|\n", - "| **Working Memory** | Conversation history | Agent Memory Server | Session |\n", - "| **Long-term Memory** | User preferences, facts | Agent Memory Server | Persistent |\n", - "| **Graph State** | Current execution state | LangGraph | Single turn |\n", - "\n", - "---\n", - "\n", - "## 📦 Setup and Environment\n", - "\n", - "### ⚠️ **CRITICAL: Prerequisites Required**\n", - "\n", - "**This notebook requires ALL services to be running. If any service is down, the agent will not work.**\n", - "\n", - "**Required Services:**\n", - "1. **Redis** - Vector storage and caching (port 6379)\n", - "2. **Agent Memory Server** - Memory management (port 8088)\n", - "3. **OpenAI API** - LLM functionality\n", - "\n", - "**🚀 Quick Setup (Run this first!):**\n", - "```bash\n", - "# Navigate to notebooks_v2 directory\n", - "cd ../../\n", - "\n", - "# Check if services are running\n", - "./check_setup.sh\n", - "\n", - "# If services are down, run setup\n", - "./setup_memory_server.sh\n", - "```\n", - "\n", - "**📖 Need help?** See `../SETUP_GUIDE.md` for detailed setup instructions.\n", - "\n", - "**🔍 Manual Check:**\n", - "- Redis: `redis-cli ping` should return `PONG`\n", - "- Memory Server: `curl http://localhost:8088/v1/health` should return `{\"status\":\"ok\"}`\n", - "- Environment: Create `.env` file in `reference-agent/` with your `OPENAI_API_KEY`\n" - ] - }, - { - "cell_type": "markdown", - "id": "install-packages", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "install", - "metadata": {}, - "source": [ - "### Automated Setup Check\n", - "\n", - "Let's run the setup script to ensure all services are running properly.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "import-libraries", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:51.825255Z", - "iopub.status.busy": "2025-10-31T23:57:51.825073Z", - "iopub.status.idle": "2025-10-31T23:57:52.103012Z", - "shell.execute_reply": "2025-10-31T23:57:52.102484Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Running automated setup check...\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🔧 Agent Memory Server Setup\n", - "===========================\n", - "📊 Checking Redis...\n", - "✅ Redis is running\n", - "📊 Checking Agent Memory Server...\n", - "🔍 Agent Memory Server container exists. Checking health...\n", - "✅ Agent Memory Server is running and healthy\n", - "✅ No Redis connection issues detected\n", - "\n", - "✅ Setup Complete!\n", - "=================\n", - "📊 Services Status:\n", - " • Redis: Running on port 6379\n", - " • Agent Memory Server: Running on port 8088\n", - "\n", - "🎯 You can now run the notebooks!\n", - "\n", - "\n", - "✅ All services are ready!\n" - ] - } - ], - "source": [ - "# Run the setup script to ensure Redis and Agent Memory Server are running\n", - "import subprocess\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "# Path to setup script\n", - "setup_script = Path(\"../../reference-agent/setup_agent_memory_server.py\")\n", - "\n", - "if setup_script.exists():\n", - " print(\"Running automated setup check...\\n\")\n", - " result = subprocess.run(\n", - " [sys.executable, str(setup_script)], capture_output=True, text=True\n", - " )\n", - " print(result.stdout)\n", - " if result.returncode != 0:\n", - " print(\"⚠️ Setup check failed. Please review the output above.\")\n", - " print(result.stderr)\n", - " else:\n", - " print(\"\\n✅ All services are ready!\")\n", - "else:\n", - " print(\"⚠️ Setup script not found. Please ensure services are running manually.\")" - ] - }, - { - "cell_type": "markdown", - "id": "imports", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "load-env", - "metadata": {}, - "source": [ - "### Install Dependencies\n", - "\n", - "If you haven't already installed the reference-agent package, uncomment and run the following:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "env-setup", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:52.104763Z", - "iopub.status.busy": "2025-10-31T23:57:52.104657Z", - "iopub.status.idle": "2025-10-31T23:57:52.106517Z", - "shell.execute_reply": "2025-10-31T23:57:52.106037Z" - } - }, - "outputs": [], - "source": [ - "# Uncomment to install reference-agent package\n", - "# %pip install -q -e ../../reference-agent\n", - "\n", - "# Uncomment to install agent-memory-client\n", - "# %pip install -q agent-memory-client" - ] - }, - { - "cell_type": "markdown", - "id": "check-services", - "metadata": {}, - "source": [ - "### Import Libraries\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "service-check", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:52.107702Z", - "iopub.status.busy": "2025-10-31T23:57:52.107645Z", - "iopub.status.idle": "2025-10-31T23:57:53.822487Z", - "shell.execute_reply": "2025-10-31T23:57:53.821994Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Libraries imported successfully!\n" - ] - } - ], - "source": [ - "import json\n", - "\n", - "# Core libraries\n", - "import os\n", - "import sys\n", - "from datetime import datetime\n", - "from typing import Annotated, Any, Dict, List, Optional\n", - "\n", - "# Redis and Agent Memory\n", - "from agent_memory_client import MemoryAPIClient, MemoryClientConfig\n", - "from agent_memory_client.models import MemoryMessage, WorkingMemory\n", - "from dotenv import load_dotenv\n", - "\n", - "# LangChain and LangGraph\n", - "from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage\n", - "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n", - "from langgraph.graph import END, StateGraph\n", - "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode\n", - "from pydantic import BaseModel, Field\n", - "\n", - "# Add reference-agent to path for course utilities\n", - "sys.path.insert(0, os.path.abspath(\"../../reference-agent\"))\n", - "from redis_context_course.course_manager import CourseManager\n", - "from redis_context_course.models import CourseFormat, DifficultyLevel, StudentProfile\n", - "\n", - "print(\"✅ Libraries imported successfully!\")" - ] - }, - { - "cell_type": "markdown", - "id": "init-components", - "metadata": {}, - "source": [ - "### Load Environment Variables\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "init-course-manager", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.823677Z", - "iopub.status.busy": "2025-10-31T23:57:53.823553Z", - "iopub.status.idle": "2025-10-31T23:57:53.826253Z", - "shell.execute_reply": "2025-10-31T23:57:53.825901Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment configured successfully!\n", - " OpenAI API Key: ********************wTMA\n", - " Redis URL: redis://localhost:6379\n", - " Agent Memory URL: http://localhost:8088\n" - ] - } - ], - "source": [ - "# Load environment variables\n", - "load_dotenv(\"../../reference-agent/.env\")\n", - "\n", - "# Get configuration\n", - "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n", - "REDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379\")\n", - "AGENT_MEMORY_URL = os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8088\")\n", - "\n", - "# Verify OpenAI API key\n", - "if not OPENAI_API_KEY:\n", - " raise ValueError(\n", - " \"\"\"\n", - " ⚠️ OPENAI_API_KEY not found!\n", - "\n", - " Please create a .env file in the reference-agent directory:\n", - " 1. cd ../../reference-agent\n", - " 2. cp .env.example .env\n", - " 3. Edit .env and add your OpenAI API key\n", - " \"\"\"\n", - " )\n", - "\n", - "print(\"✅ Environment configured successfully!\")\n", - "print(f\" OpenAI API Key: {'*' * 20}{OPENAI_API_KEY[-4:]}\")\n", - "print(f\" Redis URL: {REDIS_URL}\")\n", - "print(f\" Agent Memory URL: {AGENT_MEMORY_URL}\")" - ] - }, - { - "cell_type": "markdown", - "id": "course-manager", - "metadata": {}, - "source": [ - "### Check Required Services\n", - "\n", - "Let's verify that Redis and the Agent Memory Server are running.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "init-llm", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.827385Z", - "iopub.status.busy": "2025-10-31T23:57:53.827318Z", - "iopub.status.idle": "2025-10-31T23:57:53.839615Z", - "shell.execute_reply": "2025-10-31T23:57:53.839213Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Redis is running\n", - "✅ Agent Memory Server is running\n", - "\n", - "✅ All services are ready!\n" - ] - } - ], - "source": [ - "import redis\n", - "import requests\n", - "\n", - "# Check Redis\n", - "try:\n", - " redis_client = redis.from_url(REDIS_URL)\n", - " redis_client.ping()\n", - " print(\"✅ Redis is running\")\n", - " REDIS_AVAILABLE = True\n", - "except Exception as e:\n", - " print(f\"❌ Redis is not available: {e}\")\n", - " print(\" Please start Redis using Docker:\")\n", - " print(\" docker run -d -p 6379:6379 redis/redis-stack:latest\")\n", - " REDIS_AVAILABLE = False\n", - "\n", - "# Check Agent Memory Server\n", - "try:\n", - " response = requests.get(f\"{AGENT_MEMORY_URL}/v1/health\", timeout=2)\n", - " if response.status_code == 200:\n", - " print(\"✅ Agent Memory Server is running\")\n", - " MEMORY_SERVER_AVAILABLE = True\n", - " else:\n", - " print(f\"⚠️ Agent Memory Server returned status {response.status_code}\")\n", - " MEMORY_SERVER_AVAILABLE = False\n", - "except Exception as e:\n", - " print(f\"❌ Agent Memory Server is not available: {e}\")\n", - " print(\" Please start the Agent Memory Server:\")\n", - " print(\" cd ../../reference-agent && python setup_agent_memory_server.py\")\n", - " MEMORY_SERVER_AVAILABLE = False\n", - "\n", - "if not (REDIS_AVAILABLE and MEMORY_SERVER_AVAILABLE):\n", - " print(\"\\n⚠️ Some services are not available. Please start them before continuing.\")\n", - "else:\n", - " print(\"\\n✅ All services are ready!\")" - ] - }, - { - "cell_type": "markdown", - "id": "llm-init", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🔧 Initialize Components\n", - "\n", - "Now let's initialize the components we'll use to build our agent.\n" - ] - }, - { - "cell_type": "markdown", - "id": "init-memory", - "metadata": {}, - "source": [ - "### Initialize Course Manager\n", - "\n", - "The `CourseManager` handles course storage and semantic search, just like in Section 2.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "memory-init", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.840793Z", - "iopub.status.busy": "2025-10-31T23:57:53.840727Z", - "iopub.status.idle": "2025-10-31T23:57:53.933415Z", - "shell.execute_reply": "2025-10-31T23:57:53.933012Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "19:57:53 redisvl.index.index INFO Index already exists, not overwriting.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Course Manager initialized\n", - " Ready to search and retrieve courses\n" - ] - } - ], - "source": [ - "# Initialize Course Manager\n", - "course_manager = CourseManager()\n", - "\n", - "print(\"✅ Course Manager initialized\")\n", - "print(\" Ready to search and retrieve courses\")" - ] - }, - { - "cell_type": "markdown", - "id": "student-profile", - "metadata": {}, - "source": [ - "### Initialize LLM\n", - "\n", - "We'll use GPT-4o with temperature=0.0 for consistent, deterministic responses.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "create-student", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.934684Z", - "iopub.status.busy": "2025-10-31T23:57:53.934605Z", - "iopub.status.idle": "2025-10-31T23:57:53.943986Z", - "shell.execute_reply": "2025-10-31T23:57:53.943698Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ LLM initialized\n", - " Model: gpt-4o\n", - " Temperature: 0.0 (deterministic)\n" - ] - } - ], - "source": [ - "# Initialize LLM\n", - "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0.0)\n", - "\n", - "print(\"✅ LLM initialized\")\n", - "print(\" Model: gpt-4o\")\n", - "print(\" Temperature: 0.0 (deterministic)\")" - ] - }, - { - "cell_type": "markdown", - "id": "tools-section", - "metadata": {}, - "source": [ - "### Initialize Memory Client\n", - "\n", - "The memory client handles both working memory (conversation history) and long-term memory (persistent facts).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "tool-1", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.945184Z", - "iopub.status.busy": "2025-10-31T23:57:53.945115Z", - "iopub.status.idle": "2025-10-31T23:57:53.950020Z", - "shell.execute_reply": "2025-10-31T23:57:53.949643Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Memory Client initialized\n", - " Base URL: http://localhost:8088\n", - " Namespace: redis_university\n", - " Ready for working memory and long-term memory operations\n" - ] - } - ], - "source": [ - "# Initialize Memory Client\n", - "config = MemoryClientConfig(\n", - " base_url=AGENT_MEMORY_URL, default_namespace=\"redis_university\"\n", - ")\n", - "memory_client = MemoryAPIClient(config=config)\n", - "\n", - "print(\"✅ Memory Client initialized\")\n", - "print(f\" Base URL: {config.base_url}\")\n", - "print(f\" Namespace: {config.default_namespace}\")\n", - "print(\" Ready for working memory and long-term memory operations\")" - ] - }, - { - "cell_type": "markdown", - "id": "search-courses-tool", - "metadata": {}, - "source": [ - "### Create Sample Student Profile\n", - "\n", - "We'll create a sample student to use throughout our demos.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "tool-2", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.951077Z", - "iopub.status.busy": "2025-10-31T23:57:53.951016Z", - "iopub.status.idle": "2025-10-31T23:57:53.953293Z", - "shell.execute_reply": "2025-10-31T23:57:53.952950Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Student profile created\n", - " Name: Sarah Chen\n", - " Student ID: student_sarah_001\n", - " Session ID: session_student_sarah_001_20251031_195753\n", - " Major: Computer Science\n", - " Interests: machine learning, data science, algorithms\n" - ] - } - ], - "source": [ - "# Create sample student profile\n", - "STUDENT_ID = \"student_sarah_001\"\n", - "SESSION_ID = f\"session_{STUDENT_ID}_{datetime.now().strftime('%Y%m%d_%H%M%S')}\"\n", - "\n", - "sarah = StudentProfile(\n", - " name=\"Sarah Chen\",\n", - " email=\"sarah.chen@university.edu\",\n", - " major=\"Computer Science\",\n", - " year=2,\n", - " interests=[\"machine learning\", \"data science\", \"algorithms\"],\n", - " completed_courses=[\"Introduction to Programming\", \"Data Structures\"],\n", - " current_courses=[\"Linear Algebra\"],\n", - " preferred_format=CourseFormat.ONLINE,\n", - " preferred_difficulty=DifficultyLevel.INTERMEDIATE,\n", - ")\n", - "\n", - "print(\"✅ Student profile created\")\n", - "print(f\" Name: {sarah.name}\")\n", - "print(f\" Student ID: {STUDENT_ID}\")\n", - "print(f\" Session ID: {SESSION_ID}\")\n", - "print(f\" Major: {sarah.major}\")\n", - "print(f\" Interests: {', '.join(sarah.interests)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "search-memories-tool", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🛠️ Part 1: Define the Agent's Tools\n", - "\n", - "Let's build our 3 tools step by step. Each tool will have:\n", - "- Clear input schema (what parameters it accepts)\n", - "- Descriptive docstring (tells the LLM when to use it)\n", - "- Implementation (the actual logic)\n", - "\n", - "**Remember:** The LLM only sees the tool name, description, and parameters—not the implementation!\n" - ] - }, - { - "cell_type": "markdown", - "id": "tool-3", - "metadata": {}, - "source": [ - "### Tool 1: `search_courses`\n", - "\n", - "This tool searches the course catalog using semantic search.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "store-memory-tool", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.954314Z", - "iopub.status.busy": "2025-10-31T23:57:53.954256Z", - "iopub.status.idle": "2025-10-31T23:57:53.957045Z", - "shell.execute_reply": "2025-10-31T23:57:53.956679Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Tool 1 defined: search_courses\n", - " Purpose: Search course catalog with semantic search\n", - " Parameters: query (str), limit (int)\n" - ] - } - ], - "source": [ - "# Define input schema\n", - "\n", - "\n", - "class SearchCoursesInput(BaseModel):\n", - " \"\"\"Input schema for searching courses.\"\"\"\n", - "\n", - " query: str = Field(\n", - " description=\"Natural language search query. Can be topics (e.g., 'machine learning'), \"\n", - " \"characteristics (e.g., 'online courses'), or general questions \"\n", - " \"(e.g., 'beginner programming courses')\"\n", - " )\n", - " limit: int = Field(\n", - " default=5,\n", - " description=\"Maximum number of results to return. Default is 5. \"\n", - " \"Use 3 for quick answers, 10 for comprehensive results.\",\n", - " )\n", - "\n", - "\n", - "# Define the tool\n", - "\n", - "\n", - "@tool(\"search_courses\", args_schema=SearchCoursesInput)\n", - "async def search_courses(query: str, limit: int = 5) -> str:\n", - " \"\"\"\n", - " Search for courses using semantic search based on topics, descriptions, or characteristics.\n", - "\n", - " Use this tool when students ask about:\n", - " - Topics or subjects: \"machine learning courses\", \"database courses\"\n", - " - Course characteristics: \"online courses\", \"beginner courses\", \"3-credit courses\"\n", - " - General exploration: \"what courses are available in AI?\"\n", - "\n", - " The search uses semantic matching, so natural language queries work well.\n", - "\n", - " Returns: Formatted list of matching courses with details.\n", - " \"\"\"\n", - " results = await course_manager.search_courses(query, limit=limit)\n", - "\n", - " if not results:\n", - " return \"No courses found matching your query.\"\n", - "\n", - " output = []\n", - " for course in results:\n", - " output.append(\n", - " f\"{course.course_code}: {course.title}\\n\"\n", - " f\" Credits: {course.credits} | {course.format.value} | {course.difficulty_level.value}\\n\"\n", - " f\" {course.description[:150]}...\"\n", - " )\n", - "\n", - " return \"\\n\\n\".join(output)\n", - "\n", - "\n", - "print(\"✅ Tool 1 defined: search_courses\")\n", - "print(\" Purpose: Search course catalog with semantic search\")\n", - "print(\" Parameters: query (str), limit (int)\")" - ] - }, - { - "cell_type": "markdown", - "id": "tools-summary", - "metadata": {}, - "source": [ - "### Tool 2: `search_memories`\n", - "\n", - "This tool searches long-term memory for user preferences and facts.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "list-tools", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.958090Z", - "iopub.status.busy": "2025-10-31T23:57:53.958029Z", - "iopub.status.idle": "2025-10-31T23:57:53.960900Z", - "shell.execute_reply": "2025-10-31T23:57:53.960462Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Tool 2 defined: search_memories\n", - " Purpose: Search long-term memory for user facts\n", - " Parameters: query (str), limit (int)\n" - ] - } - ], - "source": [ - "# Define input schema\n", - "\n", - "\n", - "class SearchMemoriesInput(BaseModel):\n", - " \"\"\"Input schema for searching memories.\"\"\"\n", - "\n", - " query: str = Field(\n", - " description=\"Natural language query to search for in user's long-term memory. \"\n", - " \"Examples: 'career goals', 'course preferences', 'learning style'\"\n", - " )\n", - " limit: int = Field(\n", - " default=5, description=\"Maximum number of memories to return. Default is 5.\"\n", - " )\n", - "\n", - "\n", - "# Define the tool\n", - "\n", - "\n", - "@tool(\"search_memories\", args_schema=SearchMemoriesInput)\n", - "async def search_memories(query: str, limit: int = 5) -> str:\n", - " \"\"\"\n", - " Search the user's long-term memory for relevant facts, preferences, and past interactions.\n", - "\n", - " Use this tool when you need to:\n", - " - Recall user preferences: \"What format does the user prefer?\"\n", - " - Remember past goals: \"What career path is the user interested in?\"\n", - " - Find previous interactions: \"What courses did we discuss before?\"\n", - " - Personalize recommendations: \"What are the user's interests?\"\n", - "\n", - " The search uses semantic matching to find relevant memories.\n", - "\n", - " Returns: List of relevant memories with content and metadata.\n", - " \"\"\"\n", - " try:\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " # Search long-term memory\n", - " results = await memory_client.search_long_term_memory(\n", - " text=query, user_id=UserId(eq=STUDENT_ID), limit=limit\n", - " )\n", - "\n", - " if not results.memories or len(results.memories) == 0:\n", - " return \"No relevant memories found.\"\n", - "\n", - " output = []\n", - " for i, memory in enumerate(results.memories, 1):\n", - " output.append(f\"{i}. {memory.text}\")\n", - " if memory.topics:\n", - " output.append(f\" Topics: {', '.join(memory.topics)}\")\n", - "\n", - " return \"\\n\".join(output)\n", - " except Exception as e:\n", - " return f\"Error searching memories: {str(e)}\"\n", - "\n", - "\n", - "print(\"✅ Tool 2 defined: search_memories\")\n", - "print(\" Purpose: Search long-term memory for user facts\")\n", - "print(\" Parameters: query (str), limit (int)\")" - ] - }, - { - "cell_type": "markdown", - "id": "agent-state", - "metadata": {}, - "source": [ - "### Tool 3: `store_memory`\n", - "\n", - "This tool saves important information to long-term memory.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "define-state", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.962062Z", - "iopub.status.busy": "2025-10-31T23:57:53.961995Z", - "iopub.status.idle": "2025-10-31T23:57:53.964832Z", - "shell.execute_reply": "2025-10-31T23:57:53.964534Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Tool 3 defined: store_memory\n", - " Purpose: Save important facts to long-term memory\n", - " Parameters: text (str), memory_type (str), topics (List[str])\n" - ] - } - ], - "source": [ - "# Define input schema\n", - "\n", - "\n", - "class StoreMemoryInput(BaseModel):\n", - " \"\"\"Input schema for storing memories.\"\"\"\n", - "\n", - " text: str = Field(\n", - " description=\"The information to store. Should be a clear, factual statement. \"\n", - " \"Examples: 'User prefers online courses', 'User's career goal is AI research'\"\n", - " )\n", - " memory_type: str = Field(\n", - " default=\"semantic\",\n", - " description=\"Type of memory: 'semantic' (facts/preferences), 'episodic' (events/interactions). \"\n", - " \"Default is 'semantic'.\",\n", - " )\n", - " topics: List[str] = Field(\n", - " default=[],\n", - " description=\"Optional tags to categorize the memory, such as ['preferences', 'courses']\",\n", - " )\n", - "\n", - "\n", - "# Define the tool\n", - "\n", - "\n", - "@tool(\"store_memory\", args_schema=StoreMemoryInput)\n", - "async def store_memory(\n", - " text: str, memory_type: str = \"semantic\", topics: List[str] = []\n", - ") -> str:\n", - " \"\"\"\n", - " Store important information to the user's long-term memory.\n", - "\n", - " Use this tool when the user shares:\n", - " - Preferences: \"I prefer online courses\", \"I like hands-on projects\"\n", - " - Goals: \"I want to work in AI\", \"I'm preparing for grad school\"\n", - " - Important facts: \"I have a part-time job\", \"I'm interested in startups\"\n", - " - Constraints: \"I can only take 2 courses per semester\"\n", - "\n", - " Do NOT store:\n", - " - Temporary information (use conversation context instead)\n", - " - Course details (already in course catalog)\n", - " - General questions\n", - "\n", - " Returns: Confirmation message.\n", - " \"\"\"\n", - " try:\n", - " from agent_memory_client.models import ClientMemoryRecord\n", - "\n", - " # Create memory record\n", - " memory = ClientMemoryRecord(\n", - " text=text, user_id=STUDENT_ID, memory_type=memory_type, topics=topics or []\n", - " )\n", - "\n", - " # Store in long-term memory\n", - " await memory_client.create_long_term_memory([memory])\n", - " return f\"✅ Stored to long-term memory: {text}\"\n", - " except Exception as e:\n", - " return f\"Error storing memory: {str(e)}\"\n", - "\n", - "\n", - "print(\"✅ Tool 3 defined: store_memory\")\n", - "print(\" Purpose: Save important facts to long-term memory\")\n", - "print(\" Parameters: text (str), memory_type (str), topics (List[str])\")" - ] - }, - { - "cell_type": "markdown", - "id": "graph-nodes", - "metadata": {}, - "source": [ - "### Tools Summary\n", - "\n", - "Let's review our 3 tools:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "load-memory-node", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.966158Z", - "iopub.status.busy": "2025-10-31T23:57:53.966078Z", - "iopub.status.idle": "2025-10-31T23:57:53.968399Z", - "shell.execute_reply": "2025-10-31T23:57:53.968046Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🛠️ AGENT TOOLS SUMMARY\n", - "================================================================================\n", - "\n", - "1. search_courses\n", - " Description: Search for courses using semantic search based on topics, descriptions, or characteristics\n", - " Parameters: query, limit\n", - "\n", - "2. search_memories\n", - " Description: Search the user's long-term memory for relevant facts, preferences, and past interactions\n", - " Parameters: query, limit\n", - "\n", - "3. store_memory\n", - " Description: Store important information to the user's long-term memory\n", - " Parameters: text, memory_type, topics\n", - "\n", - "================================================================================\n" - ] - } - ], - "source": [ - "# Collect all tools\n", - "tools = [search_courses, search_memories, store_memory]\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"🛠️ AGENT TOOLS SUMMARY\")\n", - "print(\"=\" * 80)\n", - "for i, tool in enumerate(tools, 1):\n", - " print(f\"\\n{i}. {tool.name}\")\n", - " print(f\" Description: {tool.description.split('.')[0]}\")\n", - " print(f\" Parameters: {', '.join(tool.args_schema.model_fields.keys())}\")\n", - "print(\"\\n\" + \"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "agent-node", - "metadata": {}, - "source": "\n" - }, - { - "cell_type": "markdown", - "id": "save-memory-node", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.969443Z", - "iopub.status.busy": "2025-10-31T23:57:53.969382Z", - "iopub.status.idle": "2025-10-31T23:57:53.971457Z", - "shell.execute_reply": "2025-10-31T23:57:53.971109Z" - } - }, - "source": [ - "## 🧠 Memory Extraction in This Agent\n", - "\n", - "Understanding how this agent creates and manages long-term memories.\n" - ] - }, - { - "cell_type": "markdown", - "id": "routing-logic", - "metadata": {}, - "source": [ - "### How This Agent Uses Memory\n", - "\n", - "Our agent has 3 tools, and 2 of them interact with memory:\n", - "\n", - "1. **`store_memory`** - Saves facts to long-term memory\n", - "2. **`search_memories`** - Retrieves facts from long-term memory\n", - "3. **`search_courses`** - Searches course catalog (not memory-related)\n", - "\n", - "**Question:** When the agent calls `store_memory`, how does the Agent Memory Server decide what to extract and how to structure it?\n", - "\n", - "**Answer:** Memory Extraction Strategies (covered in Section 3, Notebook 1)\n" - ] - }, - { - "cell_type": "markdown", - "id": "should-continue", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.972503Z", - "iopub.status.busy": "2025-10-31T23:57:53.972440Z", - "iopub.status.idle": "2025-10-31T23:57:53.974986Z", - "shell.execute_reply": "2025-10-31T23:57:53.974616Z" - } - }, - "source": [ - "### Current Configuration: Discrete Strategy (Default)\n", - "\n", - "**This agent uses the DISCRETE strategy** (default) because:\n", - "\n", - "✅ **Individual facts are searchable**\n", - "- \"User's major is Computer Science\"\n", - "- \"User interested in machine learning\"\n", - "- \"User completed RU101\"\n", - "\n", - "✅ **Facts are independently useful**\n", - "- Agent can search for specific facts\n", - "- Each fact has its own relevance score\n", - "- No need to parse summaries\n", - "\n", - "✅ **Good for Q&A interactions**\n", - "- Student: \"What courses did I say I was interested in?\"\n", - "- Agent searches discrete facts: \"User interested in ML\", \"User interested in AI\"\n" - ] - }, - { - "cell_type": "markdown", - "id": "build-graph", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.975927Z", - "iopub.status.busy": "2025-10-31T23:57:53.975854Z", - "iopub.status.idle": "2025-10-31T23:57:53.977825Z", - "shell.execute_reply": "2025-10-31T23:57:53.977580Z" - } - }, - "source": [ - "### Example: Discrete Strategy in Action\n", - "\n", - "**Conversation:**\n", - "```\n", - "User: \"I'm a CS major interested in ML. I prefer online courses.\"\n", - "Agent: [Calls store_memory tool]\n", - "```\n", - "\n", - "**What Gets Stored (Discrete Strategy):**\n", - "```json\n", - "[\n", - " {\"text\": \"User's major is Computer Science\", \"type\": \"semantic\"},\n", - " {\"text\": \"User interested in machine learning\", \"type\": \"semantic\"},\n", - " {\"text\": \"User prefers online courses\", \"type\": \"semantic\"}\n", - "]\n", - "```\n", - "\n", - "**Later:**\n", - "```\n", - "User: \"What courses match my interests?\"\n", - "Agent: [Calls search_memories tool]\n", - " → Finds: \"User interested in machine learning\"\n", - " → Finds: \"User prefers online courses\"\n", - " [Calls search_courses with these preferences]\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "id": "construct-graph", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.978903Z", - "iopub.status.busy": "2025-10-31T23:57:53.978835Z", - "iopub.status.idle": "2025-10-31T23:57:53.981202Z", - "shell.execute_reply": "2025-10-31T23:57:53.980864Z" - } - }, - "source": [ - "### When Would Summary Strategy Be Better?\n", - "\n", - "**Summary strategy** would be beneficial for:\n", - "\n", - "**Scenario 1: Long Advising Sessions**\n", - "```\n", - "User has 30-minute conversation discussing:\n", - "- Academic goals\n", - "- Career aspirations\n", - "- Course preferences\n", - "- Schedule constraints\n", - "- Graduation timeline\n", - "```\n", - "\n", - "**Discrete Strategy:** Extracts 20+ individual facts\n", - "**Summary Strategy:** Creates 1-2 comprehensive summaries preserving context\n", - "\n", - "**Scenario 2: Session Notes**\n", - "```\n", - "Agent: \"Let me summarize our conversation today...\"\n", - "[Retrieves summary memory instead of reconstructing from discrete facts]\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "id": "visualize-graph", - "metadata": {}, - "source": [ - "### Configuration Example (Not Used in This Notebook)\n", - "\n", - "If you wanted to use summary strategy instead:\n", - "\n", - "```python\n", - "from agent_memory_client.models import MemoryStrategyConfig\n", - "\n", - "# Configure summary strategy\n", - "summary_strategy = MemoryStrategyConfig(\n", - " strategy=\"summary\",\n", - " config={\"max_summary_length\": 500}\n", - ")\n", - "\n", - "# Apply when creating working memory\n", - "await memory_client.set_working_memory(\n", - " session_id=session_id,\n", - " messages=messages,\n", - " long_term_memory_strategy=summary_strategy # ← Use summary instead of discrete\n", - ")\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "id": "show-graph", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.982174Z", - "iopub.status.busy": "2025-10-31T23:57:53.982118Z", - "iopub.status.idle": "2025-10-31T23:57:53.983908Z", - "shell.execute_reply": "2025-10-31T23:57:53.983535Z" - } - }, - "source": [ - "### Why We Stick with Discrete (Default)\n", - "\n", - "For this course advisor agent:\n", - "- ✅ Questions are specific (\"What are prerequisites for RU301?\")\n", - "- ✅ Facts are independently useful\n", - "- ✅ Search works better with discrete facts\n", - "- ✅ No configuration needed (default behavior)\n", - "\n", - "**In production**, you might:\n", - "- Use **discrete** for most interactions (default)\n", - "- Use **summary** for end-of-session notes\n", - "- Use **preferences** during student onboarding\n", - "- Use **custom** for specialized academic domains\n" - ] - }, - { - "cell_type": "markdown", - "id": "demo-section", - "metadata": {}, - "source": [ - "### 🔗 Connection to Section 3\n", - "\n", - "In **Section 3, Notebook 1**, we introduced memory extraction strategies conceptually.\n", - "\n", - "In **Section 3, Notebook 2**, we demonstrated the difference between discrete and summary strategies with hands-on examples.\n", - "\n", - "**Now in Section 4**, we see how a production agent uses the discrete strategy (default) for course advising.\n", - "\n", - "**Key Takeaway:** The Agent Memory Server's memory extraction strategies give you flexibility in HOW memories are created, but for most agent interactions (like this course advisor), the default discrete strategy works best.\n" - ] - }, - { - "cell_type": "markdown", - "id": "run-agent-helper", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.984807Z", - "iopub.status.busy": "2025-10-31T23:57:53.984751Z", - "iopub.status.idle": "2025-10-31T23:57:53.990038Z", - "shell.execute_reply": "2025-10-31T23:57:53.989670Z" - } - }, - "source": [ - "### 📚 Learn More\n", - "\n", - "- [Memory Extraction Strategies Documentation](https://redis.github.io/agent-memory-server/memory-extraction-strategies/)\n", - "- [Section 3, Notebook 1](../section-3-memory-systems-for-context-engineering/01_working_and_longterm_memory.ipynb) - Theory foundation\n", - "- [Section 3, Notebook 2](../section-3-memory-systems-for-context-engineering/02_combining_memory_with_retrieved_context.ipynb) - Hands-on comparison demo\n", - "\n", - "---\n", - "\n", - "## 🎨 Part 2: Define the Agent State\n", - "\n", - "In LangGraph, **state** is the shared data structure that flows through the graph. Each node can read from and write to the state.\n", - "\n", - "### What Goes in State?\n", - "\n", - "- **messages**: Conversation history (automatically managed by LangGraph)\n", - "- **student_id**: Who we're helping\n", - "- **session_id**: Current conversation session\n", - "- **context**: Additional context (memories, preferences, etc.)\n", - "\n", - "**Note:** We use `Annotated[List[BaseMessage], add_messages]` for messages. The `add_messages` reducer automatically handles message deduplication and ordering.\n" - ] - }, - { - "cell_type": "code", - "id": "demo-1", - "metadata": {}, - "source": [ - "# Define the agent state\n", - "\n", - "\n", - "class AgentState(BaseModel):\n", - " \"\"\"State for the course advisor agent.\"\"\"\n", - "\n", - " messages: Annotated[List[BaseMessage], add_messages]\n", - " student_id: str\n", - " session_id: str\n", - " context: Dict[str, Any] = {}\n", - "\n", - "\n", - "print(\"✅ Agent state defined\")\n", - "print(\" Fields: messages, student_id, session_id, context\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "demo-search", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.991081Z", - "iopub.status.busy": "2025-10-31T23:57:53.991018Z", - "iopub.status.idle": "2025-10-31T23:57:54.095976Z", - "shell.execute_reply": "2025-10-31T23:57:54.095530Z" - } - }, - "source": [ - "---\n", - "\n", - "## 🔗 Part 3: Build the Agent Graph\n", - "\n", - "Now we'll build the LangGraph workflow. Our graph will have:\n", - "\n", - "1. **load_memory** - Load working memory (conversation history)\n", - "2. **agent** - LLM decides what to do (call tools or respond)\n", - "3. **tools** - Execute tool calls\n", - "4. **save_memory** - Save updated conversation to working memory\n", - "\n", - "### Step 1: Define Node Functions\n", - "\n", - "Each node is a function that takes state and returns updated state.\n" - ] - }, - { - "cell_type": "code", - "id": "demo-2", - "metadata": {}, - "source": [ - "# Node 1: Load working memory\n", - "\n", - "\n", - "async def load_memory(state: AgentState) -> AgentState:\n", - " \"\"\"\n", - " Load conversation history from working memory.\n", - "\n", - " This gives the agent context about previous interactions in this session.\n", - " \"\"\"\n", - " try:\n", - " # Get or create working memory for this session\n", - " _, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=state.session_id, user_id=state.student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " if working_memory and working_memory.messages:\n", - " # Convert stored messages to LangChain message objects\n", - " loaded_messages = []\n", - " for msg in working_memory.messages:\n", - " if msg.role == \"user\":\n", - " loaded_messages.append(HumanMessage(content=msg.content))\n", - " elif msg.role == \"assistant\":\n", - " loaded_messages.append(AIMessage(content=msg.content))\n", - "\n", - " # Add loaded messages to state (prepend to current messages)\n", - " state.messages = loaded_messages + state.messages\n", - " state.context[\"memory_loaded\"] = True\n", - " print(f\" Loaded {len(loaded_messages)} messages from working memory\")\n", - " else:\n", - " state.context[\"memory_loaded\"] = False\n", - " print(\" No previous conversation found (new session)\")\n", - " except Exception as e:\n", - " print(f\" Warning: Could not load memory: {e}\")\n", - " state.context[\"memory_loaded\"] = False\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 1 defined: load_memory\")\n", - "print(\" Purpose: Load conversation history from working memory\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "demo-store", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:54.097563Z", - "iopub.status.busy": "2025-10-31T23:57:54.097461Z", - "iopub.status.idle": "2025-10-31T23:57:54.100763Z", - "shell.execute_reply": "2025-10-31T23:57:54.100208Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Helper function defined: run_agent\n" - ] - } - ], - "source": [ - "# Node 2: Agent (LLM with tools)\n", - "\n", - "\n", - "async def agent_node(state: AgentState) -> AgentState:\n", - " \"\"\"\n", - " The agent decides what to do: call tools or respond to the user.\n", - "\n", - " This is where the LLM reasoning happens.\n", - " \"\"\"\n", - " # Create system message with instructions\n", - " system_message = SystemMessage(\n", - " content=\"\"\"\n", - "You are a helpful Redis University course advisor assistant.\n", - "\n", - "Your role:\n", - "- Help students find courses that match their interests and goals\n", - "- Remember student preferences and use them for personalized recommendations\n", - "- Store important information about students for future conversations\n", - "\n", - "Guidelines:\n", - "- Use search_courses to find relevant courses\n", - "- Use search_memories to recall student preferences and past interactions\n", - "- Use store_memory when students share important preferences, goals, or constraints\n", - "- Be conversational and helpful\n", - "- Provide specific course recommendations with details\n", - "\"\"\"\n", - " )\n", - "\n", - " # Bind tools to LLM\n", - " llm_with_tools = llm.bind_tools(tools)\n", - "\n", - " # Call LLM with system message + conversation history\n", - " messages = [system_message] + state.messages\n", - " response = await llm_with_tools.ainvoke(messages)\n", - "\n", - " # Add response to state\n", - " state.messages.append(response)\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 2 defined: agent_node\")\n", - "print(\" Purpose: LLM decides whether to call tools or respond\")" - ] - }, - { - "cell_type": "code", - "id": "demo-3", - "metadata": {}, - "source": [ - "# Node 3: Save working memory\n", - "\n", - "\n", - "async def save_memory(state: AgentState) -> AgentState:\n", - " \"\"\"\n", - " Save the updated conversation to working memory.\n", - "\n", - " This ensures continuity across conversation turns.\n", - " \"\"\"\n", - " try:\n", - " # Get or create working memory\n", - " _, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=state.session_id, user_id=state.student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " # Clear existing messages and add current conversation\n", - " working_memory.messages = []\n", - " for msg in state.messages:\n", - " if isinstance(msg, HumanMessage):\n", - " working_memory.messages.append(\n", - " MemoryMessage(role=\"user\", content=msg.content)\n", - " )\n", - " elif isinstance(msg, AIMessage):\n", - " # Only store text content, not tool calls\n", - " if msg.content:\n", - " working_memory.messages.append(\n", - " MemoryMessage(role=\"assistant\", content=msg.content)\n", - " )\n", - "\n", - " # Save to working memory\n", - " await memory_client.put_working_memory(\n", - " session_id=state.session_id,\n", - " memory=working_memory,\n", - " user_id=state.student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " print(f\" Saved {len(working_memory.messages)} messages to working memory\")\n", - " except Exception as e:\n", - " print(f\" Warning: Could not save memory: {e}\")\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 3 defined: save_memory\")\n", - "print(\" Purpose: Save conversation to working memory\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "demo-recall", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:54.102049Z", - "iopub.status.busy": "2025-10-31T23:57:54.101962Z", - "iopub.status.idle": "2025-10-31T23:57:58.356458Z", - "shell.execute_reply": "2025-10-31T23:57:58.355667Z" - } - }, - "source": [ - "### Step 2: Define Routing Logic\n", - "\n", - "We need a function to decide: should we call tools or end the conversation?\n" - ] - }, - { - "cell_type": "code", - "id": "demo-4", - "metadata": {}, - "source": [ - "# Routing function\n", - "\n", - "\n", - "def should_continue(state: AgentState) -> str:\n", - " \"\"\"\n", - " Determine if we should continue to tools or end.\n", - "\n", - " If the last message has tool calls, route to tools.\n", - " Otherwise, we're done.\n", - " \"\"\"\n", - " last_message = state.messages[-1]\n", - "\n", - " # Check if there are tool calls\n", - " if hasattr(last_message, \"tool_calls\") and last_message.tool_calls:\n", - " return \"tools\"\n", - " else:\n", - " return \"save_memory\"\n", - "\n", - "\n", - "print(\"✅ Routing logic defined: should_continue\")\n", - "print(\" Routes to 'tools' if LLM wants to call tools, otherwise to 'save_memory'\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "demo-personalized", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:58.358447Z", - "iopub.status.busy": "2025-10-31T23:57:58.358312Z", - "iopub.status.idle": "2025-10-31T23:58:04.410189Z", - "shell.execute_reply": "2025-10-31T23:58:04.409512Z" - } - }, - "source": [ - "### Step 3: Build the Graph\n", - "\n", - "Now we assemble all the pieces into a LangGraph workflow.\n" - ] - }, - { - "cell_type": "code", - "id": "inspect-memory", - "metadata": {}, - "source": [ - "# Create the graph\n", - "workflow = StateGraph(AgentState)\n", - "\n", - "# Add nodes\n", - "workflow.add_node(\"load_memory\", load_memory)\n", - "workflow.add_node(\"agent\", agent_node)\n", - "workflow.add_node(\"tools\", ToolNode(tools))\n", - "workflow.add_node(\"save_memory\", save_memory)\n", - "\n", - "# Define edges\n", - "workflow.set_entry_point(\"load_memory\")\n", - "workflow.add_edge(\"load_memory\", \"agent\")\n", - "workflow.add_conditional_edges(\n", - " \"agent\", should_continue, {\"tools\": \"tools\", \"save_memory\": \"save_memory\"}\n", - ")\n", - "workflow.add_edge(\"tools\", \"agent\") # After tools, go back to agent\n", - "workflow.add_edge(\"save_memory\", END)\n", - "\n", - "# Compile the graph\n", - "agent_graph = workflow.compile()\n", - "\n", - "print(\"✅ Agent graph built and compiled!\")\n", - "print(\"\\n📊 Graph structure:\")\n", - "print(\" START → load_memory → agent → [tools → agent]* → save_memory → END\")\n", - "print(\"\\n * The agent can call tools multiple times before responding\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "check-memories", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:58:04.411898Z", - "iopub.status.busy": "2025-10-31T23:58:04.411768Z", - "iopub.status.idle": "2025-10-31T23:58:06.565467Z", - "shell.execute_reply": "2025-10-31T23:58:06.564738Z" - } - }, - "source": [ - "### Step 4: Visualize the Graph\n", - "\n", - "Let's see what our agent workflow looks like!\n" - ] - }, - { - "cell_type": "code", - "id": "comparison", - "metadata": {}, - "source": [ - "# Try to visualize the graph\n", - "try:\n", - " from IPython.display import Image, display\n", - "\n", - " # Generate graph visualization\n", - " graph_image = agent_graph.get_graph().draw_mermaid_png()\n", - " display(Image(graph_image))\n", - " print(\"\\n✅ Graph visualization displayed above\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not display graph visualization: {e}\")\n", - " print(\"\\nGraph structure (text):\")\n", - " print(\n", - " \"\"\"\n", - " ┌─────────────┐\n", - " │ START │\n", - " └──────┬──────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ load_memory │\n", - " └──────┬──────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ agent │ ◄─────┐\n", - " └──────┬──────┘ │\n", - " │ │\n", - " ┌────┴────┐ │\n", - " │ │ │\n", - " ▼ ▼ │\n", - " [tools] [respond] │\n", - " │ │\n", - " └───────────────────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ save_memory │\n", - " └──────┬──────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ END │\n", - " └─────────────┘\n", - " \"\"\"\n", - " )" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "architecture-recap", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:58:06.567416Z", - "iopub.status.busy": "2025-10-31T23:58:06.567279Z", - "iopub.status.idle": "2025-10-31T23:58:11.047325Z", - "shell.execute_reply": "2025-10-31T23:58:11.046775Z" - } - }, - "source": [ - "---\n", - "\n", - "## 🎬 Part 4: Demo the Agent\n", - "\n", - "Now let's see our agent in action! We'll have a conversation with the agent and watch it:\n", - "- Search for courses\n", - "- Store memories about preferences\n", - "- Recall information from previous interactions\n", - "\n", - "### Helper Function: Run Agent\n" - ] - }, - { - "cell_type": "code", - "id": "key-takeaways", - "metadata": {}, - "source": [ - "async def run_agent(user_message: str, verbose: bool = True) -> str:\n", - " \"\"\"\n", - " Run the agent with a user message.\n", - "\n", - " Args:\n", - " user_message: The user's input\n", - " verbose: Whether to print detailed execution info\n", - "\n", - " Returns:\n", - " The agent's response\n", - " \"\"\"\n", - " if verbose:\n", - " print(\"=\" * 80)\n", - " print(f\"👤 USER: {user_message}\")\n", - " print(\"=\" * 80)\n", - "\n", - " # Create initial state\n", - " initial_state = AgentState(\n", - " messages=[HumanMessage(content=user_message)],\n", - " student_id=STUDENT_ID,\n", - " session_id=SESSION_ID,\n", - " context={},\n", - " )\n", - "\n", - " # Run the graph\n", - " if verbose:\n", - " print(\"\\n🤖 AGENT EXECUTION:\")\n", - "\n", - " final_state = await agent_graph.ainvoke(initial_state)\n", - "\n", - " # Extract the final response\n", - " final_message = final_state[\"messages\"][-1]\n", - " response = (\n", - " final_message.content\n", - " if hasattr(final_message, \"content\")\n", - " else str(final_message)\n", - " )\n", - "\n", - " if verbose:\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(f\"🤖 ASSISTANT: {response}\")\n", - " print(\"=\" * 80)\n", - "\n", - " return response\n", - "\n", - "\n", - "print(\"✅ Helper function defined: run_agent\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "next-steps", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:58:11.049386Z", - "iopub.status.busy": "2025-10-31T23:58:11.049237Z", - "iopub.status.idle": "2025-10-31T23:58:11.464715Z", - "shell.execute_reply": "2025-10-31T23:58:11.464089Z" - } - }, - "source": [ - "### Demo 1: Search Courses\n", - "\n", - "Let's ask the agent to find machine learning courses.\n" - ] - }, - { - "cell_type": "code", - "id": "conclusion", - "metadata": {}, - "source": [ - "# Demo 1: Search for courses\n", - "response1 = await run_agent(\n", - " \"What machine learning courses are available? I'm interested in intermediate level courses.\"\n", - ")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "a8c8b43a1a04fff3", - "metadata": {}, - "source": [ - "### Demo 2: Store Preferences\n", - "\n", - "Now let's share some preferences and watch the agent store them.\n" - ] - }, - { - "cell_type": "code", - "id": "97d4b563a3a30240", - "metadata": {}, - "source": [ - "# Demo 2: Store preferences\n", - "response2 = await run_agent(\n", - " \"I prefer online courses because I have a part-time job. \"\n", - " \"Also, I'm really interested in AI and want to work at a startup after graduation.\"\n", - ")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "c2fc05bfee7ece66", - "metadata": {}, - "source": [ - "### Demo 3: Recall Memories\n", - "\n", - "Let's ask the agent to recall what it knows about us.\n" - ] - }, - { - "cell_type": "code", - "id": "437746891b606882", - "metadata": {}, - "source": [ - "# Demo 3: Recall memories\n", - "response3 = await run_agent(\"What do you remember about my preferences and goals?\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "8d495052317c67bb", - "metadata": {}, - "source": [ - "### Demo 4: Personalized Recommendations\n", - "\n", - "Now let's ask for recommendations and see if the agent uses our stored preferences.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Demo 4: Personalized recommendations\n", - "response4 = await run_agent(\n", - " \"Can you recommend some courses for next semester based on what you know about me?\"\n", - ")" - ], - "id": "3eb0f6ddeb45a9f9" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Inspect Stored Memories\n", - "\n", - "Let's look at what's actually stored in long-term memory.\n" - ], - "id": "17dd61ca397db6be" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Check what's in long-term memory\n", - "try:\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " results = await memory_client.search_long_term_memory(\n", - " text=\"preferences goals interests\", user_id=UserId(eq=STUDENT_ID), limit=10\n", - " )\n", - "\n", - " print(\"=\" * 80)\n", - " print(\"💾 LONG-TERM MEMORY CONTENTS\")\n", - " print(\"=\" * 80)\n", - "\n", - " if results.memories and len(results.memories) > 0:\n", - " for i, memory in enumerate(results.memories, 1):\n", - " print(f\"\\n{i}. [{memory.memory_type}] {memory.text}\")\n", - " if memory.topics:\n", - " print(f\" Topics: {', '.join(memory.topics)}\")\n", - " if memory.created_at:\n", - " print(f\" Created: {memory.created_at}\")\n", - " else:\n", - " print(\"\\nNo memories found.\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - "except Exception as e:\n", - " print(f\"Error retrieving memories: {e}\")" - ], - "id": "19a91887b957f48c" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 📊 Part 5: RAG vs Agent Comparison\n", - "\n", - "Let's compare what we've built across the sections:\n", - "\n", - "### **Section 2: Basic RAG**\n", - "```python\n", - "# Simple flow\n", - "query → search_courses() → generate_response()\n", - "```\n", - "- ✅ Can retrieve course information\n", - "- ❌ No memory of previous interactions\n", - "- ❌ Can't store user preferences\n", - "- ❌ Single-step only\n", - "\n", - "### **Section 3: Memory-Enhanced RAG**\n", - "```python\n", - "# With memory\n", - "load_memory() → search_courses() → generate_response() → save_memory()\n", - "```\n", - "- ✅ Remembers conversation history\n", - "- ✅ Can reference previous messages\n", - "- ⚠️ Limited to predefined flow\n", - "- ❌ Can't decide when to store memories\n", - "\n", - "### **Section 4: Full Agent (This Notebook)**\n", - "```python\n", - "# Agent with tools and decision-making\n", - "load_memory() → agent_decides() → [search_courses | search_memories | store_memory]* → save_memory()\n", - "```\n", - "- ✅ Remembers conversation history\n", - "- ✅ Decides when to search courses\n", - "- ✅ Decides when to store memories\n", - "- ✅ Decides when to recall memories\n", - "- ✅ Can chain multiple operations\n", - "- ✅ Adaptive to user needs\n", - "\n", - "### **Key Differences:**\n", - "\n", - "| Feature | RAG | Memory-RAG | Agent |\n", - "|---------|-----|------------|-------|\n", - "| **Retrieval** | ✅ | ✅ | ✅ |\n", - "| **Conversation Memory** | ❌ | ✅ | ✅ |\n", - "| **Long-term Memory** | ❌ | ⚠️ (manual) | ✅ (automatic) |\n", - "| **Decision Making** | ❌ | ❌ | ✅ |\n", - "| **Multi-step Reasoning** | ❌ | ❌ | ✅ |\n", - "| **Tool Selection** | ❌ | ❌ | ✅ |\n", - "| **Complexity** | Low | Medium | High |\n", - "| **Latency** | Low | Medium | Higher |\n", - "| **Cost** | Low | Medium | Higher |\n", - "\n", - "**💡 Key Insight:** Agents add decision-making and multi-step reasoning to RAG systems.\n" - ], - "id": "fd45b11038775302" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🏗️ Architecture Recap\n", - "\n", - "### **What We Built:**\n", - "\n", - "A complete course advisor agent with:\n", - "\n", - "**1. Tools (3 total)**\n", - "- `search_courses` - Semantic search over course catalog\n", - "- `search_memories` - Recall user preferences and facts\n", - "- `store_memory` - Save important information\n", - "\n", - "**2. Memory Architecture**\n", - "- **Working Memory** - Conversation history (session-scoped)\n", - "- **Long-term Memory** - User preferences and facts (persistent)\n", - "- **Graph State** - Current execution state (turn-scoped)\n", - "\n", - "**3. LangGraph Workflow**\n", - "- **Nodes**: load_memory, agent, tools, save_memory\n", - "- **Edges**: Conditional routing based on LLM decisions\n", - "- **State**: Shared data structure flowing through the graph\n", - "\n", - "**4. Integration Points**\n", - "- **Redis** - Course catalog storage and vector search\n", - "- **Agent Memory Server** - Working and long-term memory\n", - "- **OpenAI** - LLM for reasoning and tool selection\n", - "- **LangGraph** - Workflow orchestration\n", - "\n", - "### **The Complete Context Engineering Stack:**\n", - "\n", - "```\n", - "┌─────────────────────────────────────────────────────────┐\n", - "│ AGENT LAYER │\n", - "│ (LangGraph orchestration + tool selection) │\n", - "└────────────────────┬────────────────────────────────────┘\n", - " │\n", - " ┌────────────┼────────────┐\n", - " │ │ │\n", - " ▼ ▼ ▼\n", - " ┌────────┐ ┌─────────┐ ┌─────────┐\n", - " │ Tools │ │ Memory │ │ RAG │\n", - " └────────┘ └─────────┘ └─────────┘\n", - " │ │ │\n", - " └────────────┼────────────┘\n", - " │\n", - " ▼\n", - " ┌─────────────────┐\n", - " │ Redis Stack │\n", - " │ (Storage + │\n", - " │ Vector Search)│\n", - " └─────────────────┘\n", - "```\n" - ], - "id": "d4a533d945ca605e" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🎓 Key Takeaways\n", - "\n", - "### **1. Agents = RAG + Tools + Decision-Making**\n", - "- RAG retrieves information\n", - "- Tools enable actions\n", - "- Agents decide when to use each\n", - "\n", - "### **2. Memory is Critical for Personalization**\n", - "- Working memory enables conversation continuity\n", - "- Long-term memory enables personalization\n", - "- Agents can decide when to store/recall memories\n", - "\n", - "### **3. LangGraph Simplifies Complex Workflows**\n", - "- State management is automatic\n", - "- Conditional routing is declarative\n", - "- Visualization helps debugging\n", - "\n", - "### **4. Tool Design Matters**\n", - "- Clear descriptions guide LLM selection\n", - "- Well-defined schemas prevent errors\n", - "- Focused tools are better than Swiss Army knives\n", - "\n", - "### **5. Trade-offs to Consider**\n", - "- **Complexity**: Agents are more complex than RAG\n", - "- **Latency**: Multiple tool calls add latency\n", - "- **Cost**: More LLM calls = higher cost\n", - "- **Value**: Worth it for complex, multi-step tasks\n", - "\n", - "### **6. When to Use Agents vs RAG**\n", - "\n", - "**Use RAG when:**\n", - "- Simple question answering\n", - "- Single-step retrieval\n", - "- Low latency required\n", - "- Predictable workflows\n", - "\n", - "**Use Agents when:**\n", - "- Multi-step reasoning needed\n", - "- Actions beyond retrieval\n", - "- Personalization required\n", - "- Complex decision-making\n" - ], - "id": "c4654c5a2c4e5323" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🚀 Next Steps and Extensions\n", - "\n", - "### **Ideas to Extend This Agent:**\n", - "\n", - "1. **Add More Tools**\n", - " - `check_prerequisites` - Verify if student meets course requirements\n", - " - `get_course_details` - Get detailed info about a specific course\n", - " - `create_schedule` - Build a semester schedule\n", - " - `check_conflicts` - Detect time conflicts\n", - "\n", - "2. **Enhance Memory**\n", - " - Automatic memory extraction from conversations\n", - " - Memory summarization for long conversations\n", - " - Memory importance scoring\n", - " - Memory expiration policies\n", - "\n", - "3. **Improve Personalization**\n", - " - Learning style detection\n", - " - Career path recommendations\n", - " - Skill gap analysis\n", - " - Progress tracking\n", - "\n", - "4. **Add Guardrails**\n", - " - Input validation\n", - " - Output filtering\n", - " - Rate limiting\n", - " - Error handling\n", - "\n", - "5. **Production Considerations**\n", - " - Authentication and authorization\n", - " - Logging and monitoring\n", - " - Caching for performance\n", - " - Fallback strategies\n", - "\n", - "### **Reference Implementation:**\n", - "\n", - "Check out `reference-agent/` for a full production implementation with:\n", - "- 7 tools (vs our 3)\n", - "- Advanced memory management\n", - "- Semantic tool selection\n", - "- Comprehensive error handling\n", - "- CLI interface\n", - "- Full test suite\n" - ], - "id": "346d2737598bfd31" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🎉 Congratulations!\n", - "\n", - "You've completed the Context Engineering course! You've learned:\n", - "\n", - "**Section 1:** Context Types\n", - "- System, User, Conversation, Retrieved context\n", - "- How context shapes LLM behavior\n", - "\n", - "**Section 2:** RAG Foundations\n", - "- Semantic search with vector embeddings\n", - "- Context assembly and generation\n", - "- Building a course search system\n", - "\n", - "**Section 3:** Memory Architecture\n", - "- Working memory for conversation continuity\n", - "- Long-term memory for persistent knowledge\n", - "- Memory-enhanced RAG systems\n", - "\n", - "**🔬 Research Foundation:** Throughout this course, you've learned techniques validated by Context Rot research - prioritizing relevance over quantity, filtering distractors, and structuring context for optimal LLM performance. ([Context Rot paper](https://research.trychroma.com/context-rot))\n", - "\n", - "**Section 4:** Agents and Tools\n", - "- Tool calling fundamentals\n", - "- LangGraph workflow orchestration\n", - "- Building a complete course advisor agent\n", - "- Agents vs RAG trade-offs\n", - "\n", - "### **You Can Now:**\n", - "- ✅ Design effective context strategies\n", - "- ✅ Build RAG systems with Redis\n", - "- ✅ Implement dual-memory architectures\n", - "- ✅ Create agents with tools and decision-making\n", - "- ✅ Choose the right approach for your use case\n", - "\n", - "### **Keep Learning:**\n", - "- Explore the reference-agent implementation\n", - "- Experiment with different tools\n", - "- Try different LLMs and embeddings\n", - "- Build your own agents!\n", - "\n", - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "\n", - "- [Agent Memory Server Documentation](https://github.com/redis/agent-memory-server) - Production-ready memory management\n", - "- [Agent Memory Client](https://pypi.org/project/agent-memory-client/) - Python client for Agent Memory Server\n", - "- [RedisVL Documentation](https://redisvl.com/) - Redis Vector Library\n", - "- [Retrieval-Augmented Generation Paper](https://arxiv.org/abs/2005.11401) - Original RAG research\n", - "- [LangChain RAG Tutorial](https://python.langchain.com/docs/use_cases/question_answering/) - Building RAG systems\n", - "- [LangGraph Tutorials](https://langchain-ai.github.io/langgraph/tutorials/) - Building agents with LangGraph\n", - "- [Agent Architectures](https://python.langchain.com/docs/modules/agents/) - Different agent patterns\n", - "- [ReAct: Synergizing Reasoning and Acting](https://arxiv.org/abs/2210.03629) - Reasoning + acting in LLMs\n", - "- [Anthropic's Guide to Building Effective Agents](https://www.anthropic.com/research/building-effective-agents) - Agent design patterns\n", - "\n", - "---\n", - "\n", - "**Thank you for completing this course! 🙏**\n" - ], - "id": "6a1c7e21740d4240" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "439770b03604fe49" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-4-tools-and-agents/03_agent_with_memory_compression.ipynb b/notebooks/section-4-tools-and-agents/03_agent_with_memory_compression.ipynb deleted file mode 100644 index f7fb1f7..0000000 --- a/notebooks/section-4-tools-and-agents/03_agent_with_memory_compression.ipynb +++ /dev/null @@ -1,2901 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "header", - "metadata": {}, - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# 🤖 Agent with Memory Compression\n", - "\n", - "**⏱️ Estimated Time:** 90-120 minutes\n", - "\n", - "**📝 Note:** This is an enhanced version of the course advisor agent that includes working memory compression demonstrations. For the standard version without compression, see `02_building_course_advisor_agent.ipynb`.\n", - "\n", - "## 🎯 Learning Objectives\n", - "\n", - "By the end of this notebook, you will:\n", - "\n", - "1. **Build** a complete LangGraph agent with tools and memory\n", - "2. **Implement** exactly 3 tools: memory storage, memory search, and course search\n", - "3. **Integrate** Redis Agent Memory Server for dual-memory architecture\n", - "4. **Visualize** the agent's decision-making graph\n", - "5. **Demonstrate** the progression from RAG (Section 3) to full agent\n", - "\n", - "---\n", - "\n", - "## 🔗 Bridge from Previous Sections\n", - "\n", - "### **Your Learning Journey:**\n", - "\n", - "**Section 1:** Context Types\n", - "- System, User, Conversation, Retrieved context\n", - "- How context shapes LLM responses\n", - "\n", - "**Section 2:** RAG Foundations\n", - "- Semantic search with vector embeddings\n", - "- Retrieving and presenting information\n", - "- Single-step retrieval → generation\n", - "\n", - "**Section 3:** Memory Architecture\n", - "- Working memory (conversation continuity)\n", - "- Long-term memory (persistent knowledge)\n", - "- Memory-enhanced RAG systems\n", - "\n", - "**Section 4 (Notebook 1):** Tool-Calling Basics\n", - "- What tools are and how LLMs use them\n", - "- LangGraph fundamentals (nodes, edges, state)\n", - "- Simple tool-calling examples\n", - "- Agents vs RAG comparison\n", - "\n", - "### **What We're Building Now:**\n", - "\n", - "**A Full Agent** that combines everything:\n", - "- ✅ **Tools** for actions (search courses, manage memory)\n", - "- ✅ **Memory** for personalization (working + long-term)\n", - "- ✅ **RAG** for course information (semantic search)\n", - "- ✅ **LangGraph** for orchestration (state management)\n", - "\n", - "**💡 Key Insight:** This agent is RAG + Memory + Tools + Decision-Making\n", - "\n", - "---\n", - "\n", - "## 📊 Agent Architecture\n", - "\n", - "### **The Complete Flow:**\n", - "\n", - "```\n", - "User Query\n", - " ↓\n", - "[Load Working Memory] ← Conversation history\n", - " ↓\n", - "[Agent Node] ← Decides what to do\n", - " ↓\n", - " ├─→ [search_courses] ← Find relevant courses\n", - " ├─→ [search_memories] ← Recall user preferences\n", - " ├─→ [store_memory] ← Save important facts\n", - " ↓\n", - "[Agent Node] ← Processes tool results\n", - " ↓\n", - "[Generate Response] ← Final answer\n", - " ↓\n", - "[Save Working Memory] ← Update conversation\n", - "```\n", - "\n", - "### **Our 3 Tools:**\n", - "\n", - "1. **`search_courses`** - Semantic search over course catalog\n", - " - When: Student asks about courses, topics, or recommendations\n", - " - Example: \"What machine learning courses are available?\"\n", - "\n", - "2. **`search_memories`** - Search long-term memory for user facts\n", - " - When: Need to recall preferences, goals, or past interactions\n", - " - Example: \"What courses did I say I was interested in?\"\n", - "\n", - "3. **`store_memory`** - Save important information to long-term memory\n", - " - When: User shares preferences, goals, or important facts\n", - " - Example: \"I'm interested in AI and want to work at a startup\"\n", - "\n", - "### **Memory Architecture:**\n", - "\n", - "| Memory Type | Purpose | Managed By | Lifespan |\n", - "|------------|---------|------------|----------|\n", - "| **Working Memory** | Conversation history | Agent Memory Server | Session |\n", - "| **Long-term Memory** | User preferences, facts | Agent Memory Server | Persistent |\n", - "| **Graph State** | Current execution state | LangGraph | Single turn |\n", - "\n", - "---\n", - "\n", - "## 📦 Setup and Environment\n", - "\n", - "### ⚠️ **CRITICAL: Prerequisites Required**\n", - "\n", - "**This notebook requires ALL services to be running. If any service is down, the agent will not work.**\n", - "\n", - "**Required Services:**\n", - "1. **Redis** - Vector storage and caching (port 6379)\n", - "2. **Agent Memory Server** - Memory management (port 8088)\n", - "3. **OpenAI API** - LLM functionality\n", - "\n", - "**🚀 Quick Setup (Run this first!):**\n", - "```bash\n", - "# Navigate to notebooks_v2 directory\n", - "cd ../../\n", - "\n", - "# Check if services are running\n", - "./check_setup.sh\n", - "\n", - "# If services are down, run setup\n", - "./setup_memory_server.sh\n", - "```\n", - "\n", - "**📖 Need help?** See `../SETUP_GUIDE.md` for detailed setup instructions.\n", - "\n", - "**🔍 Manual Check:**\n", - "- Redis: `redis-cli ping` should return `PONG`\n", - "- Memory Server: `curl http://localhost:8088/v1/health` should return `{\"status\":\"ok\"}`\n", - "- Environment: Create `.env` file in `reference-agent/` with your `OPENAI_API_KEY`\n" - ] - }, - { - "cell_type": "markdown", - "id": "install-packages", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "install", - "metadata": {}, - "source": [ - "### Automated Setup Check\n", - "\n", - "Let's run the setup script to ensure all services are running properly.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "import-libraries", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:51.825255Z", - "iopub.status.busy": "2025-10-31T23:57:51.825073Z", - "iopub.status.idle": "2025-10-31T23:57:52.103012Z", - "shell.execute_reply": "2025-10-31T23:57:52.102484Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Running automated setup check...\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "🔧 Agent Memory Server Setup\n", - "===========================\n", - "📊 Checking Redis...\n", - "✅ Redis is running\n", - "📊 Checking Agent Memory Server...\n", - "🔍 Agent Memory Server container exists. Checking health...\n", - "✅ Agent Memory Server is running and healthy\n", - "✅ No Redis connection issues detected\n", - "\n", - "✅ Setup Complete!\n", - "=================\n", - "📊 Services Status:\n", - " • Redis: Running on port 6379\n", - " • Agent Memory Server: Running on port 8088\n", - "\n", - "🎯 You can now run the notebooks!\n", - "\n", - "\n", - "✅ All services are ready!\n" - ] - } - ], - "source": [ - "# Run the setup script to ensure Redis and Agent Memory Server are running\n", - "import subprocess\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "# Path to setup script\n", - "setup_script = Path(\"../../reference-agent/setup_agent_memory_server.py\")\n", - "\n", - "if setup_script.exists():\n", - " print(\"Running automated setup check...\\n\")\n", - " result = subprocess.run(\n", - " [sys.executable, str(setup_script)], capture_output=True, text=True\n", - " )\n", - " print(result.stdout)\n", - " if result.returncode != 0:\n", - " print(\"⚠️ Setup check failed. Please review the output above.\")\n", - " print(result.stderr)\n", - " else:\n", - " print(\"\\n✅ All services are ready!\")\n", - "else:\n", - " print(\"⚠️ Setup script not found. Please ensure services are running manually.\")" - ] - }, - { - "cell_type": "markdown", - "id": "imports", - "metadata": {}, - "source": [ - "---\n" - ] - }, - { - "cell_type": "markdown", - "id": "load-env", - "metadata": {}, - "source": [ - "### Install Dependencies\n", - "\n", - "If you haven't already installed the reference-agent package, uncomment and run the following:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "env-setup", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:52.104763Z", - "iopub.status.busy": "2025-10-31T23:57:52.104657Z", - "iopub.status.idle": "2025-10-31T23:57:52.106517Z", - "shell.execute_reply": "2025-10-31T23:57:52.106037Z" - } - }, - "outputs": [], - "source": [ - "# Uncomment to install reference-agent package\n", - "# %pip install -q -e ../../reference-agent\n", - "\n", - "# Uncomment to install agent-memory-client\n", - "# %pip install -q agent-memory-client" - ] - }, - { - "cell_type": "markdown", - "id": "check-services", - "metadata": {}, - "source": [ - "### Import Libraries\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "service-check", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:52.107702Z", - "iopub.status.busy": "2025-10-31T23:57:52.107645Z", - "iopub.status.idle": "2025-10-31T23:57:53.822487Z", - "shell.execute_reply": "2025-10-31T23:57:53.821994Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Libraries imported successfully!\n" - ] - } - ], - "source": [ - "import json\n", - "\n", - "# Core libraries\n", - "import os\n", - "import sys\n", - "from datetime import datetime\n", - "from typing import Annotated, Any, Dict, List, Optional\n", - "\n", - "# Redis and Agent Memory\n", - "from agent_memory_client import MemoryAPIClient, MemoryClientConfig\n", - "from agent_memory_client.models import MemoryMessage, WorkingMemory\n", - "from dotenv import load_dotenv\n", - "\n", - "# LangChain and LangGraph\n", - "from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage\n", - "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n", - "from langgraph.graph import END, StateGraph\n", - "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode\n", - "from pydantic import BaseModel, Field\n", - "\n", - "# Add reference-agent to path for course utilities\n", - "sys.path.insert(0, os.path.abspath(\"../../reference-agent\"))\n", - "from redis_context_course.course_manager import CourseManager\n", - "from redis_context_course.models import CourseFormat, DifficultyLevel, StudentProfile\n", - "\n", - "print(\"✅ Libraries imported successfully!\")" - ] - }, - { - "cell_type": "markdown", - "id": "init-components", - "metadata": {}, - "source": [ - "### Load Environment Variables\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "init-course-manager", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.823677Z", - "iopub.status.busy": "2025-10-31T23:57:53.823553Z", - "iopub.status.idle": "2025-10-31T23:57:53.826253Z", - "shell.execute_reply": "2025-10-31T23:57:53.825901Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Environment configured successfully!\n", - " OpenAI API Key: ********************wTMA\n", - " Redis URL: redis://localhost:6379\n", - " Agent Memory URL: http://localhost:8088\n" - ] - } - ], - "source": [ - "# Load environment variables\n", - "load_dotenv(\"../../reference-agent/.env\")\n", - "\n", - "# Get configuration\n", - "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n", - "REDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379\")\n", - "AGENT_MEMORY_URL = os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8088\")\n", - "\n", - "# Verify OpenAI API key\n", - "if not OPENAI_API_KEY:\n", - " raise ValueError(\n", - " \"\"\"\n", - " ⚠️ OPENAI_API_KEY not found!\n", - "\n", - " Please create a .env file in the reference-agent directory:\n", - " 1. cd ../../reference-agent\n", - " 2. cp .env.example .env\n", - " 3. Edit .env and add your OpenAI API key\n", - " \"\"\"\n", - " )\n", - "\n", - "print(\"✅ Environment configured successfully!\")\n", - "print(f\" OpenAI API Key: {'*' * 20}{OPENAI_API_KEY[-4:]}\")\n", - "print(f\" Redis URL: {REDIS_URL}\")\n", - "print(f\" Agent Memory URL: {AGENT_MEMORY_URL}\")" - ] - }, - { - "cell_type": "markdown", - "id": "course-manager", - "metadata": {}, - "source": [ - "### Check Required Services\n", - "\n", - "Let's verify that Redis and the Agent Memory Server are running.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "init-llm", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.827385Z", - "iopub.status.busy": "2025-10-31T23:57:53.827318Z", - "iopub.status.idle": "2025-10-31T23:57:53.839615Z", - "shell.execute_reply": "2025-10-31T23:57:53.839213Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Redis is running\n", - "✅ Agent Memory Server is running\n", - "\n", - "✅ All services are ready!\n" - ] - } - ], - "source": [ - "import redis\n", - "import requests\n", - "\n", - "# Check Redis\n", - "try:\n", - " redis_client = redis.from_url(REDIS_URL)\n", - " redis_client.ping()\n", - " print(\"✅ Redis is running\")\n", - " REDIS_AVAILABLE = True\n", - "except Exception as e:\n", - " print(f\"❌ Redis is not available: {e}\")\n", - " print(\" Please start Redis using Docker:\")\n", - " print(\" docker run -d -p 6379:6379 redis/redis-stack:latest\")\n", - " REDIS_AVAILABLE = False\n", - "\n", - "# Check Agent Memory Server\n", - "try:\n", - " response = requests.get(f\"{AGENT_MEMORY_URL}/v1/health\", timeout=2)\n", - " if response.status_code == 200:\n", - " print(\"✅ Agent Memory Server is running\")\n", - " MEMORY_SERVER_AVAILABLE = True\n", - " else:\n", - " print(f\"⚠️ Agent Memory Server returned status {response.status_code}\")\n", - " MEMORY_SERVER_AVAILABLE = False\n", - "except Exception as e:\n", - " print(f\"❌ Agent Memory Server is not available: {e}\")\n", - " print(\" Please start the Agent Memory Server:\")\n", - " print(\" cd ../../reference-agent && python setup_agent_memory_server.py\")\n", - " MEMORY_SERVER_AVAILABLE = False\n", - "\n", - "if not (REDIS_AVAILABLE and MEMORY_SERVER_AVAILABLE):\n", - " print(\"\\n⚠️ Some services are not available. Please start them before continuing.\")\n", - "else:\n", - " print(\"\\n✅ All services are ready!\")" - ] - }, - { - "cell_type": "markdown", - "id": "llm-init", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🔧 Initialize Components\n", - "\n", - "Now let's initialize the components we'll use to build our agent.\n" - ] - }, - { - "cell_type": "markdown", - "id": "init-memory", - "metadata": {}, - "source": [ - "### Initialize Course Manager\n", - "\n", - "The `CourseManager` handles course storage and semantic search, just like in Section 2.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "memory-init", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.840793Z", - "iopub.status.busy": "2025-10-31T23:57:53.840727Z", - "iopub.status.idle": "2025-10-31T23:57:53.933415Z", - "shell.execute_reply": "2025-10-31T23:57:53.933012Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "19:57:53 redisvl.index.index INFO Index already exists, not overwriting.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Course Manager initialized\n", - " Ready to search and retrieve courses\n" - ] - } - ], - "source": [ - "# Initialize Course Manager\n", - "course_manager = CourseManager()\n", - "\n", - "print(\"✅ Course Manager initialized\")\n", - "print(\" Ready to search and retrieve courses\")" - ] - }, - { - "cell_type": "markdown", - "id": "student-profile", - "metadata": {}, - "source": [ - "### Initialize LLM\n", - "\n", - "We'll use GPT-4o with temperature=0.0 for consistent, deterministic responses.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "create-student", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.934684Z", - "iopub.status.busy": "2025-10-31T23:57:53.934605Z", - "iopub.status.idle": "2025-10-31T23:57:53.943986Z", - "shell.execute_reply": "2025-10-31T23:57:53.943698Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ LLM initialized\n", - " Model: gpt-4o\n", - " Temperature: 0.0 (deterministic)\n" - ] - } - ], - "source": [ - "# Initialize LLM\n", - "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0.0)\n", - "\n", - "print(\"✅ LLM initialized\")\n", - "print(\" Model: gpt-4o\")\n", - "print(\" Temperature: 0.0 (deterministic)\")" - ] - }, - { - "cell_type": "markdown", - "id": "tools-section", - "metadata": {}, - "source": [ - "### Initialize Memory Client\n", - "\n", - "The memory client handles both working memory (conversation history) and long-term memory (persistent facts).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "tool-1", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.945184Z", - "iopub.status.busy": "2025-10-31T23:57:53.945115Z", - "iopub.status.idle": "2025-10-31T23:57:53.950020Z", - "shell.execute_reply": "2025-10-31T23:57:53.949643Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Memory Client initialized\n", - " Base URL: http://localhost:8088\n", - " Namespace: redis_university\n", - " Ready for working memory and long-term memory operations\n" - ] - } - ], - "source": [ - "# Initialize Memory Client\n", - "config = MemoryClientConfig(\n", - " base_url=AGENT_MEMORY_URL, default_namespace=\"redis_university\"\n", - ")\n", - "memory_client = MemoryAPIClient(config=config)\n", - "\n", - "print(\"✅ Memory Client initialized\")\n", - "print(f\" Base URL: {config.base_url}\")\n", - "print(f\" Namespace: {config.default_namespace}\")\n", - "print(\" Ready for working memory and long-term memory operations\")" - ] - }, - { - "cell_type": "markdown", - "id": "search-courses-tool", - "metadata": {}, - "source": [ - "### Create Sample Student Profile\n", - "\n", - "We'll create a sample student to use throughout our demos.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "tool-2", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.951077Z", - "iopub.status.busy": "2025-10-31T23:57:53.951016Z", - "iopub.status.idle": "2025-10-31T23:57:53.953293Z", - "shell.execute_reply": "2025-10-31T23:57:53.952950Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Student profile created\n", - " Name: Sarah Chen\n", - " Student ID: student_sarah_001\n", - " Session ID: session_student_sarah_001_20251031_195753\n", - " Major: Computer Science\n", - " Interests: machine learning, data science, algorithms\n" - ] - } - ], - "source": [ - "# Create sample student profile\n", - "STUDENT_ID = \"student_sarah_001\"\n", - "SESSION_ID = f\"session_{STUDENT_ID}_{datetime.now().strftime('%Y%m%d_%H%M%S')}\"\n", - "\n", - "sarah = StudentProfile(\n", - " name=\"Sarah Chen\",\n", - " email=\"sarah.chen@university.edu\",\n", - " major=\"Computer Science\",\n", - " year=2,\n", - " interests=[\"machine learning\", \"data science\", \"algorithms\"],\n", - " completed_courses=[\"Introduction to Programming\", \"Data Structures\"],\n", - " current_courses=[\"Linear Algebra\"],\n", - " preferred_format=CourseFormat.ONLINE,\n", - " preferred_difficulty=DifficultyLevel.INTERMEDIATE,\n", - ")\n", - "\n", - "print(\"✅ Student profile created\")\n", - "print(f\" Name: {sarah.name}\")\n", - "print(f\" Student ID: {STUDENT_ID}\")\n", - "print(f\" Session ID: {SESSION_ID}\")\n", - "print(f\" Major: {sarah.major}\")\n", - "print(f\" Interests: {', '.join(sarah.interests)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "search-memories-tool", - "metadata": {}, - "source": [ - "---\n", - "\n", - "## 🛠️ Part 1: Define the Agent's Tools\n", - "\n", - "Let's build our 3 tools step by step. Each tool will have:\n", - "- Clear input schema (what parameters it accepts)\n", - "- Descriptive docstring (tells the LLM when to use it)\n", - "- Implementation (the actual logic)\n", - "\n", - "**Remember:** The LLM only sees the tool name, description, and parameters—not the implementation!\n" - ] - }, - { - "cell_type": "markdown", - "id": "tool-3", - "metadata": {}, - "source": [ - "### Tool 1: `search_courses`\n", - "\n", - "This tool searches the course catalog using semantic search.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "store-memory-tool", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.954314Z", - "iopub.status.busy": "2025-10-31T23:57:53.954256Z", - "iopub.status.idle": "2025-10-31T23:57:53.957045Z", - "shell.execute_reply": "2025-10-31T23:57:53.956679Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Tool 1 defined: search_courses\n", - " Purpose: Search course catalog with semantic search\n", - " Parameters: query (str), limit (int)\n" - ] - } - ], - "source": [ - "# Define input schema\n", - "\n", - "\n", - "class SearchCoursesInput(BaseModel):\n", - " \"\"\"Input schema for searching courses.\"\"\"\n", - "\n", - " query: str = Field(\n", - " description=\"Natural language search query. Can be topics (e.g., 'machine learning'), \"\n", - " \"characteristics (e.g., 'online courses'), or general questions \"\n", - " \"(e.g., 'beginner programming courses')\"\n", - " )\n", - " limit: int = Field(\n", - " default=5,\n", - " description=\"Maximum number of results to return. Default is 5. \"\n", - " \"Use 3 for quick answers, 10 for comprehensive results.\",\n", - " )\n", - "\n", - "\n", - "# Define the tool\n", - "\n", - "\n", - "@tool(\"search_courses\", args_schema=SearchCoursesInput)\n", - "async def search_courses(query: str, limit: int = 5) -> str:\n", - " \"\"\"\n", - " Search for courses using semantic search based on topics, descriptions, or characteristics.\n", - "\n", - " Use this tool when students ask about:\n", - " - Topics or subjects: \"machine learning courses\", \"database courses\"\n", - " - Course characteristics: \"online courses\", \"beginner courses\", \"3-credit courses\"\n", - " - General exploration: \"what courses are available in AI?\"\n", - "\n", - " The search uses semantic matching, so natural language queries work well.\n", - "\n", - " Returns: Formatted list of matching courses with details.\n", - " \"\"\"\n", - " results = await course_manager.search_courses(query, limit=limit)\n", - "\n", - " if not results:\n", - " return \"No courses found matching your query.\"\n", - "\n", - " output = []\n", - " for course in results:\n", - " output.append(\n", - " f\"{course.course_code}: {course.title}\\n\"\n", - " f\" Credits: {course.credits} | {course.format.value} | {course.difficulty_level.value}\\n\"\n", - " f\" {course.description[:150]}...\"\n", - " )\n", - "\n", - " return \"\\n\\n\".join(output)\n", - "\n", - "\n", - "print(\"✅ Tool 1 defined: search_courses\")\n", - "print(\" Purpose: Search course catalog with semantic search\")\n", - "print(\" Parameters: query (str), limit (int)\")" - ] - }, - { - "cell_type": "markdown", - "id": "tools-summary", - "metadata": {}, - "source": [ - "### Tool 2: `search_memories`\n", - "\n", - "This tool searches long-term memory for user preferences and facts.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "list-tools", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.958090Z", - "iopub.status.busy": "2025-10-31T23:57:53.958029Z", - "iopub.status.idle": "2025-10-31T23:57:53.960900Z", - "shell.execute_reply": "2025-10-31T23:57:53.960462Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Tool 2 defined: search_memories\n", - " Purpose: Search long-term memory for user facts\n", - " Parameters: query (str), limit (int)\n" - ] - } - ], - "source": [ - "# Define input schema\n", - "\n", - "\n", - "class SearchMemoriesInput(BaseModel):\n", - " \"\"\"Input schema for searching memories.\"\"\"\n", - "\n", - " query: str = Field(\n", - " description=\"Natural language query to search for in user's long-term memory. \"\n", - " \"Examples: 'career goals', 'course preferences', 'learning style'\"\n", - " )\n", - " limit: int = Field(\n", - " default=5, description=\"Maximum number of memories to return. Default is 5.\"\n", - " )\n", - "\n", - "\n", - "# Define the tool\n", - "\n", - "\n", - "@tool(\"search_memories\", args_schema=SearchMemoriesInput)\n", - "async def search_memories(query: str, limit: int = 5) -> str:\n", - " \"\"\"\n", - " Search the user's long-term memory for relevant facts, preferences, and past interactions.\n", - "\n", - " Use this tool when you need to:\n", - " - Recall user preferences: \"What format does the user prefer?\"\n", - " - Remember past goals: \"What career path is the user interested in?\"\n", - " - Find previous interactions: \"What courses did we discuss before?\"\n", - " - Personalize recommendations: \"What are the user's interests?\"\n", - "\n", - " The search uses semantic matching to find relevant memories.\n", - "\n", - " Returns: List of relevant memories with content and metadata.\n", - " \"\"\"\n", - " try:\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " # Search long-term memory\n", - " results = await memory_client.search_long_term_memory(\n", - " text=query, user_id=UserId(eq=STUDENT_ID), limit=limit\n", - " )\n", - "\n", - " if not results.memories or len(results.memories) == 0:\n", - " return \"No relevant memories found.\"\n", - "\n", - " output = []\n", - " for i, memory in enumerate(results.memories, 1):\n", - " output.append(f\"{i}. {memory.text}\")\n", - " if memory.topics:\n", - " output.append(f\" Topics: {', '.join(memory.topics)}\")\n", - "\n", - " return \"\\n\".join(output)\n", - " except Exception as e:\n", - " return f\"Error searching memories: {str(e)}\"\n", - "\n", - "\n", - "print(\"✅ Tool 2 defined: search_memories\")\n", - "print(\" Purpose: Search long-term memory for user facts\")\n", - "print(\" Parameters: query (str), limit (int)\")" - ] - }, - { - "cell_type": "markdown", - "id": "agent-state", - "metadata": {}, - "source": [ - "### Tool 3: `store_memory`\n", - "\n", - "This tool saves important information to long-term memory.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "define-state", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.962062Z", - "iopub.status.busy": "2025-10-31T23:57:53.961995Z", - "iopub.status.idle": "2025-10-31T23:57:53.964832Z", - "shell.execute_reply": "2025-10-31T23:57:53.964534Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Tool 3 defined: store_memory\n", - " Purpose: Save important facts to long-term memory\n", - " Parameters: text (str), memory_type (str), topics (List[str])\n" - ] - } - ], - "source": [ - "# Define input schema\n", - "\n", - "\n", - "class StoreMemoryInput(BaseModel):\n", - " \"\"\"Input schema for storing memories.\"\"\"\n", - "\n", - " text: str = Field(\n", - " description=\"The information to store. Should be a clear, factual statement. \"\n", - " \"Examples: 'User prefers online courses', 'User's career goal is AI research'\"\n", - " )\n", - " memory_type: str = Field(\n", - " default=\"semantic\",\n", - " description=\"Type of memory: 'semantic' (facts/preferences), 'episodic' (events/interactions). \"\n", - " \"Default is 'semantic'.\",\n", - " )\n", - " topics: List[str] = Field(\n", - " default=[],\n", - " description=\"Optional tags to categorize the memory, such as ['preferences', 'courses']\",\n", - " )\n", - "\n", - "\n", - "# Define the tool\n", - "\n", - "\n", - "@tool(\"store_memory\", args_schema=StoreMemoryInput)\n", - "async def store_memory(\n", - " text: str, memory_type: str = \"semantic\", topics: List[str] = []\n", - ") -> str:\n", - " \"\"\"\n", - " Store important information to the user's long-term memory.\n", - "\n", - " Use this tool when the user shares:\n", - " - Preferences: \"I prefer online courses\", \"I like hands-on projects\"\n", - " - Goals: \"I want to work in AI\", \"I'm preparing for grad school\"\n", - " - Important facts: \"I have a part-time job\", \"I'm interested in startups\"\n", - " - Constraints: \"I can only take 2 courses per semester\"\n", - "\n", - " Do NOT store:\n", - " - Temporary information (use conversation context instead)\n", - " - Course details (already in course catalog)\n", - " - General questions\n", - "\n", - " Returns: Confirmation message.\n", - " \"\"\"\n", - " try:\n", - " from agent_memory_client.models import ClientMemoryRecord\n", - "\n", - " # Create memory record\n", - " memory = ClientMemoryRecord(\n", - " text=text, user_id=STUDENT_ID, memory_type=memory_type, topics=topics or []\n", - " )\n", - "\n", - " # Store in long-term memory\n", - " await memory_client.create_long_term_memory([memory])\n", - " return f\"✅ Stored to long-term memory: {text}\"\n", - " except Exception as e:\n", - " return f\"Error storing memory: {str(e)}\"\n", - "\n", - "\n", - "print(\"✅ Tool 3 defined: store_memory\")\n", - "print(\" Purpose: Save important facts to long-term memory\")\n", - "print(\" Parameters: text (str), memory_type (str), topics (List[str])\")" - ] - }, - { - "cell_type": "markdown", - "id": "graph-nodes", - "metadata": {}, - "source": [ - "### Tools Summary\n", - "\n", - "Let's review our 3 tools:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "load-memory-node", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.966158Z", - "iopub.status.busy": "2025-10-31T23:57:53.966078Z", - "iopub.status.idle": "2025-10-31T23:57:53.968399Z", - "shell.execute_reply": "2025-10-31T23:57:53.968046Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================================================================\n", - "🛠️ AGENT TOOLS SUMMARY\n", - "================================================================================\n", - "\n", - "1. search_courses\n", - " Description: Search for courses using semantic search based on topics, descriptions, or characteristics\n", - " Parameters: query, limit\n", - "\n", - "2. search_memories\n", - " Description: Search the user's long-term memory for relevant facts, preferences, and past interactions\n", - " Parameters: query, limit\n", - "\n", - "3. store_memory\n", - " Description: Store important information to the user's long-term memory\n", - " Parameters: text, memory_type, topics\n", - "\n", - "================================================================================\n" - ] - } - ], - "source": [ - "# Collect all tools\n", - "tools = [search_courses, search_memories, store_memory]\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"🛠️ AGENT TOOLS SUMMARY\")\n", - "print(\"=\" * 80)\n", - "for i, tool in enumerate(tools, 1):\n", - " print(f\"\\n{i}. {tool.name}\")\n", - " print(f\" Description: {tool.description.split('.')[0]}\")\n", - " print(f\" Parameters: {', '.join(tool.args_schema.model_fields.keys())}\")\n", - "print(\"\\n\" + \"=\" * 80)" - ] - }, - { - "cell_type": "markdown", - "id": "agent-node", - "metadata": {}, - "source": "\n" - }, - { - "cell_type": "markdown", - "id": "save-memory-node", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.969443Z", - "iopub.status.busy": "2025-10-31T23:57:53.969382Z", - "iopub.status.idle": "2025-10-31T23:57:53.971457Z", - "shell.execute_reply": "2025-10-31T23:57:53.971109Z" - } - }, - "source": [ - "## 🧠 Memory Extraction in This Agent\n", - "\n", - "Understanding how this agent creates and manages long-term memories.\n" - ] - }, - { - "cell_type": "markdown", - "id": "routing-logic", - "metadata": {}, - "source": [ - "### How This Agent Uses Memory\n", - "\n", - "Our agent has 3 tools, and 2 of them interact with memory:\n", - "\n", - "1. **`store_memory`** - Saves facts to long-term memory\n", - "2. **`search_memories`** - Retrieves facts from long-term memory\n", - "3. **`search_courses`** - Searches course catalog (not memory-related)\n", - "\n", - "**Question:** When the agent calls `store_memory`, how does the Agent Memory Server decide what to extract and how to structure it?\n", - "\n", - "**Answer:** Memory Extraction Strategies (covered in Section 3, Notebook 1)\n" - ] - }, - { - "cell_type": "markdown", - "id": "should-continue", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.972503Z", - "iopub.status.busy": "2025-10-31T23:57:53.972440Z", - "iopub.status.idle": "2025-10-31T23:57:53.974986Z", - "shell.execute_reply": "2025-10-31T23:57:53.974616Z" - } - }, - "source": [ - "### Current Configuration: Discrete Strategy (Default)\n", - "\n", - "**This agent uses the DISCRETE strategy** (default) because:\n", - "\n", - "✅ **Individual facts are searchable**\n", - "- \"User's major is Computer Science\"\n", - "- \"User interested in machine learning\"\n", - "- \"User completed RU101\"\n", - "\n", - "✅ **Facts are independently useful**\n", - "- Agent can search for specific facts\n", - "- Each fact has its own relevance score\n", - "- No need to parse summaries\n", - "\n", - "✅ **Good for Q&A interactions**\n", - "- Student: \"What courses did I say I was interested in?\"\n", - "- Agent searches discrete facts: \"User interested in ML\", \"User interested in AI\"\n" - ] - }, - { - "cell_type": "markdown", - "id": "build-graph", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.975927Z", - "iopub.status.busy": "2025-10-31T23:57:53.975854Z", - "iopub.status.idle": "2025-10-31T23:57:53.977825Z", - "shell.execute_reply": "2025-10-31T23:57:53.977580Z" - } - }, - "source": [ - "### Example: Discrete Strategy in Action\n", - "\n", - "**Conversation:**\n", - "```\n", - "User: \"I'm a CS major interested in ML. I prefer online courses.\"\n", - "Agent: [Calls store_memory tool]\n", - "```\n", - "\n", - "**What Gets Stored (Discrete Strategy):**\n", - "```json\n", - "[\n", - " {\"text\": \"User's major is Computer Science\", \"type\": \"semantic\"},\n", - " {\"text\": \"User interested in machine learning\", \"type\": \"semantic\"},\n", - " {\"text\": \"User prefers online courses\", \"type\": \"semantic\"}\n", - "]\n", - "```\n", - "\n", - "**Later:**\n", - "```\n", - "User: \"What courses match my interests?\"\n", - "Agent: [Calls search_memories tool]\n", - " → Finds: \"User interested in machine learning\"\n", - " → Finds: \"User prefers online courses\"\n", - " [Calls search_courses with these preferences]\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "id": "construct-graph", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.978903Z", - "iopub.status.busy": "2025-10-31T23:57:53.978835Z", - "iopub.status.idle": "2025-10-31T23:57:53.981202Z", - "shell.execute_reply": "2025-10-31T23:57:53.980864Z" - } - }, - "source": [ - "### When Would Summary Strategy Be Better?\n", - "\n", - "**Summary strategy** would be beneficial for:\n", - "\n", - "**Scenario 1: Long Advising Sessions**\n", - "```\n", - "User has 30-minute conversation discussing:\n", - "- Academic goals\n", - "- Career aspirations\n", - "- Course preferences\n", - "- Schedule constraints\n", - "- Graduation timeline\n", - "```\n", - "\n", - "**Discrete Strategy:** Extracts 20+ individual facts\n", - "**Summary Strategy:** Creates 1-2 comprehensive summaries preserving context\n", - "\n", - "**Scenario 2: Session Notes**\n", - "```\n", - "Agent: \"Let me summarize our conversation today...\"\n", - "[Retrieves summary memory instead of reconstructing from discrete facts]\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "id": "visualize-graph", - "metadata": {}, - "source": [ - "### Configuration Example (Not Used in This Notebook)\n", - "\n", - "If you wanted to use summary strategy instead:\n", - "\n", - "```python\n", - "from agent_memory_client.models import MemoryStrategyConfig\n", - "\n", - "# Configure summary strategy\n", - "summary_strategy = MemoryStrategyConfig(\n", - " strategy=\"summary\",\n", - " config={\"max_summary_length\": 500}\n", - ")\n", - "\n", - "# Apply when creating working memory\n", - "await memory_client.set_working_memory(\n", - " session_id=session_id,\n", - " messages=messages,\n", - " long_term_memory_strategy=summary_strategy # ← Use summary instead of discrete\n", - ")\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "id": "show-graph", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.982174Z", - "iopub.status.busy": "2025-10-31T23:57:53.982118Z", - "iopub.status.idle": "2025-10-31T23:57:53.983908Z", - "shell.execute_reply": "2025-10-31T23:57:53.983535Z" - } - }, - "source": [ - "### Why We Stick with Discrete (Default)\n", - "\n", - "For this course advisor agent:\n", - "- ✅ Questions are specific (\"What are prerequisites for RU301?\")\n", - "- ✅ Facts are independently useful\n", - "- ✅ Search works better with discrete facts\n", - "- ✅ No configuration needed (default behavior)\n", - "\n", - "**In production**, you might:\n", - "- Use **discrete** for most interactions (default)\n", - "- Use **summary** for end-of-session notes\n", - "- Use **preferences** during student onboarding\n", - "- Use **custom** for specialized academic domains\n" - ] - }, - { - "cell_type": "markdown", - "id": "demo-section", - "metadata": {}, - "source": [ - "### 🔗 Connection to Section 3\n", - "\n", - "In **Section 3, Notebook 1**, we introduced memory extraction strategies conceptually.\n", - "\n", - "In **Section 3, Notebook 2**, we demonstrated the difference between discrete and summary strategies with hands-on examples.\n", - "\n", - "**Now in Section 4**, we see how a production agent uses the discrete strategy (default) for course advising.\n", - "\n", - "**Key Takeaway:** The Agent Memory Server's memory extraction strategies give you flexibility in HOW memories are created, but for most agent interactions (like this course advisor), the default discrete strategy works best.\n" - ] - }, - { - "cell_type": "markdown", - "id": "run-agent-helper", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.984807Z", - "iopub.status.busy": "2025-10-31T23:57:53.984751Z", - "iopub.status.idle": "2025-10-31T23:57:53.990038Z", - "shell.execute_reply": "2025-10-31T23:57:53.989670Z" - } - }, - "source": [ - "### 📚 Learn More\n", - "\n", - "- [Memory Extraction Strategies Documentation](https://redis.github.io/agent-memory-server/memory-extraction-strategies/)\n", - "- [Section 3, Notebook 1](../section-3-memory-systems-for-context-engineering/01_working_and_longterm_memory.ipynb) - Theory foundation\n", - "- [Section 3, Notebook 2](../section-3-memory-systems-for-context-engineering/02_combining_memory_with_retrieved_context.ipynb) - Hands-on comparison demo\n", - "\n", - "---\n", - "\n", - "## 🎨 Part 2: Define the Agent State\n", - "\n", - "In LangGraph, **state** is the shared data structure that flows through the graph. Each node can read from and write to the state.\n", - "\n", - "### What Goes in State?\n", - "\n", - "- **messages**: Conversation history (automatically managed by LangGraph)\n", - "- **student_id**: Who we're helping\n", - "- **session_id**: Current conversation session\n", - "- **context**: Additional context (memories, preferences, etc.)\n", - "\n", - "**Note:** We use `Annotated[List[BaseMessage], add_messages]` for messages. The `add_messages` reducer automatically handles message deduplication and ordering.\n" - ] - }, - { - "cell_type": "code", - "id": "demo-1", - "metadata": {}, - "source": [ - "# Define the agent state\n", - "\n", - "\n", - "class AgentState(BaseModel):\n", - " \"\"\"State for the course advisor agent.\"\"\"\n", - "\n", - " messages: Annotated[List[BaseMessage], add_messages]\n", - " student_id: str\n", - " session_id: str\n", - " context: Dict[str, Any] = {}\n", - "\n", - "\n", - "print(\"✅ Agent state defined\")\n", - "print(\" Fields: messages, student_id, session_id, context\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "demo-search", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:53.991081Z", - "iopub.status.busy": "2025-10-31T23:57:53.991018Z", - "iopub.status.idle": "2025-10-31T23:57:54.095976Z", - "shell.execute_reply": "2025-10-31T23:57:54.095530Z" - } - }, - "source": [ - "---\n", - "\n", - "## 🔗 Part 3: Build the Agent Graph\n", - "\n", - "Now we'll build the LangGraph workflow. Our graph will have:\n", - "\n", - "1. **load_memory** - Load working memory (conversation history)\n", - "2. **agent** - LLM decides what to do (call tools or respond)\n", - "3. **tools** - Execute tool calls\n", - "4. **save_memory** - Save updated conversation to working memory\n", - "\n", - "### Step 1: Define Node Functions\n", - "\n", - "Each node is a function that takes state and returns updated state.\n" - ] - }, - { - "cell_type": "code", - "id": "demo-2", - "metadata": {}, - "source": [ - "# Node 1: Load working memory\n", - "\n", - "\n", - "async def load_memory(state: AgentState) -> AgentState:\n", - " \"\"\"\n", - " Load conversation history from working memory.\n", - "\n", - " This gives the agent context about previous interactions in this session.\n", - " \"\"\"\n", - " try:\n", - " # Get or create working memory for this session\n", - " _, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=state.session_id, user_id=state.student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " if working_memory and working_memory.messages:\n", - " # Convert stored messages to LangChain message objects\n", - " loaded_messages = []\n", - " for msg in working_memory.messages:\n", - " if msg.role == \"user\":\n", - " loaded_messages.append(HumanMessage(content=msg.content))\n", - " elif msg.role == \"assistant\":\n", - " loaded_messages.append(AIMessage(content=msg.content))\n", - "\n", - " # Add loaded messages to state (prepend to current messages)\n", - " state.messages = loaded_messages + state.messages\n", - " state.context[\"memory_loaded\"] = True\n", - " print(f\" Loaded {len(loaded_messages)} messages from working memory\")\n", - " else:\n", - " state.context[\"memory_loaded\"] = False\n", - " print(\" No previous conversation found (new session)\")\n", - " except Exception as e:\n", - " print(f\" Warning: Could not load memory: {e}\")\n", - " state.context[\"memory_loaded\"] = False\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 1 defined: load_memory\")\n", - "print(\" Purpose: Load conversation history from working memory\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "demo-store", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:54.097563Z", - "iopub.status.busy": "2025-10-31T23:57:54.097461Z", - "iopub.status.idle": "2025-10-31T23:57:54.100763Z", - "shell.execute_reply": "2025-10-31T23:57:54.100208Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Helper function defined: run_agent\n" - ] - } - ], - "source": [ - "# Node 2: Agent (LLM with tools)\n", - "\n", - "\n", - "async def agent_node(state: AgentState) -> AgentState:\n", - " \"\"\"\n", - " The agent decides what to do: call tools or respond to the user.\n", - "\n", - " This is where the LLM reasoning happens.\n", - " \"\"\"\n", - " # Create system message with instructions\n", - " system_message = SystemMessage(\n", - " content=\"\"\"\n", - "You are a helpful Redis University course advisor assistant.\n", - "\n", - "Your role:\n", - "- Help students find courses that match their interests and goals\n", - "- Remember student preferences and use them for personalized recommendations\n", - "- Store important information about students for future conversations\n", - "\n", - "Guidelines:\n", - "- Use search_courses to find relevant courses\n", - "- Use search_memories to recall student preferences and past interactions\n", - "- Use store_memory when students share important preferences, goals, or constraints\n", - "- Be conversational and helpful\n", - "- Provide specific course recommendations with details\n", - "\"\"\"\n", - " )\n", - "\n", - " # Bind tools to LLM\n", - " llm_with_tools = llm.bind_tools(tools)\n", - "\n", - " # Call LLM with system message + conversation history\n", - " messages = [system_message] + state.messages\n", - " response = await llm_with_tools.ainvoke(messages)\n", - "\n", - " # Add response to state\n", - " state.messages.append(response)\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 2 defined: agent_node\")\n", - "print(\" Purpose: LLM decides whether to call tools or respond\")" - ] - }, - { - "cell_type": "code", - "id": "demo-3", - "metadata": {}, - "source": [ - "# Node 3: Save working memory\n", - "\n", - "\n", - "async def save_memory(state: AgentState) -> AgentState:\n", - " \"\"\"\n", - " Save the updated conversation to working memory.\n", - "\n", - " This ensures continuity across conversation turns.\n", - " \"\"\"\n", - " try:\n", - " # Get or create working memory\n", - " _, working_memory = await memory_client.get_or_create_working_memory(\n", - " session_id=state.session_id, user_id=state.student_id, model_name=\"gpt-4o\"\n", - " )\n", - "\n", - " # Clear existing messages and add current conversation\n", - " working_memory.messages = []\n", - " for msg in state.messages:\n", - " if isinstance(msg, HumanMessage):\n", - " working_memory.messages.append(\n", - " MemoryMessage(role=\"user\", content=msg.content)\n", - " )\n", - " elif isinstance(msg, AIMessage):\n", - " # Only store text content, not tool calls\n", - " if msg.content:\n", - " working_memory.messages.append(\n", - " MemoryMessage(role=\"assistant\", content=msg.content)\n", - " )\n", - "\n", - " # Save to working memory\n", - " await memory_client.put_working_memory(\n", - " session_id=state.session_id,\n", - " memory=working_memory,\n", - " user_id=state.student_id,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " print(f\" Saved {len(working_memory.messages)} messages to working memory\")\n", - " except Exception as e:\n", - " print(f\" Warning: Could not save memory: {e}\")\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 3 defined: save_memory\")\n", - "print(\" Purpose: Save conversation to working memory\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "demo-recall", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:54.102049Z", - "iopub.status.busy": "2025-10-31T23:57:54.101962Z", - "iopub.status.idle": "2025-10-31T23:57:58.356458Z", - "shell.execute_reply": "2025-10-31T23:57:58.355667Z" - } - }, - "source": [ - "### Step 2: Define Routing Logic\n", - "\n", - "We need a function to decide: should we call tools or end the conversation?\n" - ] - }, - { - "cell_type": "code", - "id": "demo-4", - "metadata": {}, - "source": [ - "# Routing function\n", - "\n", - "\n", - "def should_continue(state: AgentState) -> str:\n", - " \"\"\"\n", - " Determine if we should continue to tools or end.\n", - "\n", - " If the last message has tool calls, route to tools.\n", - " Otherwise, we're done.\n", - " \"\"\"\n", - " last_message = state.messages[-1]\n", - "\n", - " # Check if there are tool calls\n", - " if hasattr(last_message, \"tool_calls\") and last_message.tool_calls:\n", - " return \"tools\"\n", - " else:\n", - " return \"save_memory\"\n", - "\n", - "\n", - "print(\"✅ Routing logic defined: should_continue\")\n", - "print(\" Routes to 'tools' if LLM wants to call tools, otherwise to 'save_memory'\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "demo-personalized", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:57:58.358447Z", - "iopub.status.busy": "2025-10-31T23:57:58.358312Z", - "iopub.status.idle": "2025-10-31T23:58:04.410189Z", - "shell.execute_reply": "2025-10-31T23:58:04.409512Z" - } - }, - "source": [ - "### Step 3: Build the Graph\n", - "\n", - "Now we assemble all the pieces into a LangGraph workflow.\n" - ] - }, - { - "cell_type": "code", - "id": "inspect-memory", - "metadata": {}, - "source": [ - "# Create the graph\n", - "workflow = StateGraph(AgentState)\n", - "\n", - "# Add nodes\n", - "workflow.add_node(\"load_memory\", load_memory)\n", - "workflow.add_node(\"agent\", agent_node)\n", - "workflow.add_node(\"tools\", ToolNode(tools))\n", - "workflow.add_node(\"save_memory\", save_memory)\n", - "\n", - "# Define edges\n", - "workflow.set_entry_point(\"load_memory\")\n", - "workflow.add_edge(\"load_memory\", \"agent\")\n", - "workflow.add_conditional_edges(\n", - " \"agent\", should_continue, {\"tools\": \"tools\", \"save_memory\": \"save_memory\"}\n", - ")\n", - "workflow.add_edge(\"tools\", \"agent\") # After tools, go back to agent\n", - "workflow.add_edge(\"save_memory\", END)\n", - "\n", - "# Compile the graph\n", - "agent_graph = workflow.compile()\n", - "\n", - "print(\"✅ Agent graph built and compiled!\")\n", - "print(\"\\n📊 Graph structure:\")\n", - "print(\" START → load_memory → agent → [tools → agent]* → save_memory → END\")\n", - "print(\"\\n * The agent can call tools multiple times before responding\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "check-memories", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:58:04.411898Z", - "iopub.status.busy": "2025-10-31T23:58:04.411768Z", - "iopub.status.idle": "2025-10-31T23:58:06.565467Z", - "shell.execute_reply": "2025-10-31T23:58:06.564738Z" - } - }, - "source": [ - "### Step 4: Visualize the Graph\n", - "\n", - "Let's see what our agent workflow looks like!\n" - ] - }, - { - "cell_type": "code", - "id": "comparison", - "metadata": {}, - "source": [ - "# Try to visualize the graph\n", - "try:\n", - " from IPython.display import Image, display\n", - "\n", - " # Generate graph visualization\n", - " graph_image = agent_graph.get_graph().draw_mermaid_png()\n", - " display(Image(graph_image))\n", - " print(\"\\n✅ Graph visualization displayed above\")\n", - "except Exception as e:\n", - " print(f\"⚠️ Could not display graph visualization: {e}\")\n", - " print(\"\\nGraph structure (text):\")\n", - " print(\n", - " \"\"\"\n", - " ┌─────────────┐\n", - " │ START │\n", - " └──────┬──────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ load_memory │\n", - " └──────┬──────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ agent │ ◄─────┐\n", - " └──────┬──────┘ │\n", - " │ │\n", - " ┌────┴────┐ │\n", - " │ │ │\n", - " ▼ ▼ │\n", - " [tools] [respond] │\n", - " │ │\n", - " └───────────────────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ save_memory │\n", - " └──────┬──────┘\n", - " │\n", - " ▼\n", - " ┌─────────────┐\n", - " │ END │\n", - " └─────────────┘\n", - " \"\"\"\n", - " )" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "architecture-recap", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:58:06.567416Z", - "iopub.status.busy": "2025-10-31T23:58:06.567279Z", - "iopub.status.idle": "2025-10-31T23:58:11.047325Z", - "shell.execute_reply": "2025-10-31T23:58:11.046775Z" - } - }, - "source": [ - "---\n", - "\n", - "## 🎬 Part 4: Demo the Agent\n", - "\n", - "Now let's see our agent in action! We'll have a conversation with the agent and watch it:\n", - "- Search for courses\n", - "- Store memories about preferences\n", - "- Recall information from previous interactions\n", - "\n", - "### Helper Function: Run Agent\n" - ] - }, - { - "cell_type": "code", - "id": "key-takeaways", - "metadata": {}, - "source": [ - "async def run_agent(user_message: str, verbose: bool = True) -> str:\n", - " \"\"\"\n", - " Run the agent with a user message.\n", - "\n", - " Args:\n", - " user_message: The user's input\n", - " verbose: Whether to print detailed execution info\n", - "\n", - " Returns:\n", - " The agent's response\n", - " \"\"\"\n", - " if verbose:\n", - " print(\"=\" * 80)\n", - " print(f\"👤 USER: {user_message}\")\n", - " print(\"=\" * 80)\n", - "\n", - " # Create initial state\n", - " initial_state = AgentState(\n", - " messages=[HumanMessage(content=user_message)],\n", - " student_id=STUDENT_ID,\n", - " session_id=SESSION_ID,\n", - " context={},\n", - " )\n", - "\n", - " # Run the graph\n", - " if verbose:\n", - " print(\"\\n🤖 AGENT EXECUTION:\")\n", - "\n", - " final_state = await agent_graph.ainvoke(initial_state)\n", - "\n", - " # Extract the final response\n", - " final_message = final_state[\"messages\"][-1]\n", - " response = (\n", - " final_message.content\n", - " if hasattr(final_message, \"content\")\n", - " else str(final_message)\n", - " )\n", - "\n", - " if verbose:\n", - " print(\"\\n\" + \"=\" * 80)\n", - " print(f\"🤖 ASSISTANT: {response}\")\n", - " print(\"=\" * 80)\n", - "\n", - " return response\n", - "\n", - "\n", - "print(\"✅ Helper function defined: run_agent\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "next-steps", - "metadata": { - "execution": { - "iopub.execute_input": "2025-10-31T23:58:11.049386Z", - "iopub.status.busy": "2025-10-31T23:58:11.049237Z", - "iopub.status.idle": "2025-10-31T23:58:11.464715Z", - "shell.execute_reply": "2025-10-31T23:58:11.464089Z" - } - }, - "source": [ - "### Demo 1: Search Courses\n", - "\n", - "Let's ask the agent to find machine learning courses.\n" - ] - }, - { - "cell_type": "code", - "id": "conclusion", - "metadata": {}, - "source": [ - "# Demo 1: Search for courses\n", - "response1 = await run_agent(\n", - " \"What machine learning courses are available? I'm interested in intermediate level courses.\"\n", - ")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "a8c8b43a1a04fff3", - "metadata": {}, - "source": [ - "### Demo 2: Store Preferences\n", - "\n", - "Now let's share some preferences and watch the agent store them.\n" - ] - }, - { - "cell_type": "code", - "id": "97d4b563a3a30240", - "metadata": {}, - "source": [ - "# Demo 2: Store preferences\n", - "response2 = await run_agent(\n", - " \"I prefer online courses because I have a part-time job. \"\n", - " \"Also, I'm really interested in AI and want to work at a startup after graduation.\"\n", - ")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "c2fc05bfee7ece66", - "metadata": {}, - "source": [ - "### Demo 3: Recall Memories\n", - "\n", - "Let's ask the agent to recall what it knows about us.\n" - ] - }, - { - "cell_type": "code", - "id": "437746891b606882", - "metadata": {}, - "source": [ - "# Demo 3: Recall memories\n", - "response3 = await run_agent(\"What do you remember about my preferences and goals?\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "id": "8d495052317c67bb", - "metadata": {}, - "source": [ - "### Demo 4: Personalized Recommendations\n", - "\n", - "Now let's ask for recommendations and see if the agent uses our stored preferences.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Demo 4: Personalized recommendations\n", - "response4 = await run_agent(\n", - " \"Can you recommend some courses for next semester based on what you know about me?\"\n", - ")" - ], - "id": "3eb0f6ddeb45a9f9" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Inspect Stored Memories\n", - "\n", - "Let's look at what's actually stored in long-term memory.\n" - ], - "id": "17dd61ca397db6be" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Check what's in long-term memory\n", - "try:\n", - " from agent_memory_client.filters import UserId\n", - "\n", - " results = await memory_client.search_long_term_memory(\n", - " text=\"preferences goals interests\", user_id=UserId(eq=STUDENT_ID), limit=10\n", - " )\n", - "\n", - " print(\"=\" * 80)\n", - " print(\"💾 LONG-TERM MEMORY CONTENTS\")\n", - " print(\"=\" * 80)\n", - "\n", - " if results.memories and len(results.memories) > 0:\n", - " for i, memory in enumerate(results.memories, 1):\n", - " print(f\"\\n{i}. [{memory.memory_type}] {memory.text}\")\n", - " if memory.topics:\n", - " print(f\" Topics: {', '.join(memory.topics)}\")\n", - " if memory.created_at:\n", - " print(f\" Created: {memory.created_at}\")\n", - " else:\n", - " print(\"\\nNo memories found.\")\n", - "\n", - " print(\"\\n\" + \"=\" * 80)\n", - "except Exception as e:\n", - " print(f\"Error retrieving memories: {e}\")" - ], - "id": "19a91887b957f48c" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 📊 Part 5: RAG vs Agent Comparison\n", - "\n", - "Let's compare what we've built across the sections:\n", - "\n", - "### **Section 2: Basic RAG**\n", - "```python\n", - "# Simple flow\n", - "query → search_courses() → generate_response()\n", - "```\n", - "- ✅ Can retrieve course information\n", - "- ❌ No memory of previous interactions\n", - "- ❌ Can't store user preferences\n", - "- ❌ Single-step only\n", - "\n", - "### **Section 3: Memory-Enhanced RAG**\n", - "```python\n", - "# With memory\n", - "load_memory() → search_courses() → generate_response() → save_memory()\n", - "```\n", - "- ✅ Remembers conversation history\n", - "- ✅ Can reference previous messages\n", - "- ⚠️ Limited to predefined flow\n", - "- ❌ Can't decide when to store memories\n", - "\n", - "### **Section 4: Full Agent (This Notebook)**\n", - "```python\n", - "# Agent with tools and decision-making\n", - "load_memory() → agent_decides() → [search_courses | search_memories | store_memory]* → save_memory()\n", - "```\n", - "- ✅ Remembers conversation history\n", - "- ✅ Decides when to search courses\n", - "- ✅ Decides when to store memories\n", - "- ✅ Decides when to recall memories\n", - "- ✅ Can chain multiple operations\n", - "- ✅ Adaptive to user needs\n", - "\n", - "### **Key Differences:**\n", - "\n", - "| Feature | RAG | Memory-RAG | Agent |\n", - "|---------|-----|------------|-------|\n", - "| **Retrieval** | ✅ | ✅ | ✅ |\n", - "| **Conversation Memory** | ❌ | ✅ | ✅ |\n", - "| **Long-term Memory** | ❌ | ⚠️ (manual) | ✅ (automatic) |\n", - "| **Decision Making** | ❌ | ❌ | ✅ |\n", - "| **Multi-step Reasoning** | ❌ | ❌ | ✅ |\n", - "| **Tool Selection** | ❌ | ❌ | ✅ |\n", - "| **Complexity** | Low | Medium | High |\n", - "| **Latency** | Low | Medium | Higher |\n", - "| **Cost** | Low | Medium | Higher |\n", - "\n", - "**💡 Key Insight:** Agents add decision-making and multi-step reasoning to RAG systems.\n" - ], - "id": "fd45b11038775302" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🏗️ Architecture Recap\n", - "\n", - "### **What We Built:**\n", - "\n", - "A complete course advisor agent with:\n", - "\n", - "**1. Tools (3 total)**\n", - "- `search_courses` - Semantic search over course catalog\n", - "- `search_memories` - Recall user preferences and facts\n", - "- `store_memory` - Save important information\n", - "\n", - "**2. Memory Architecture**\n", - "- **Working Memory** - Conversation history (session-scoped)\n", - "- **Long-term Memory** - User preferences and facts (persistent)\n", - "- **Graph State** - Current execution state (turn-scoped)\n", - "\n", - "**3. LangGraph Workflow**\n", - "- **Nodes**: load_memory, agent, tools, save_memory\n", - "- **Edges**: Conditional routing based on LLM decisions\n", - "- **State**: Shared data structure flowing through the graph\n", - "\n", - "**4. Integration Points**\n", - "- **Redis** - Course catalog storage and vector search\n", - "- **Agent Memory Server** - Working and long-term memory\n", - "- **OpenAI** - LLM for reasoning and tool selection\n", - "- **LangGraph** - Workflow orchestration\n", - "\n", - "### **The Complete Context Engineering Stack:**\n", - "\n", - "```\n", - "┌─────────────────────────────────────────────────────────┐\n", - "│ AGENT LAYER │\n", - "│ (LangGraph orchestration + tool selection) │\n", - "└────────────────────┬────────────────────────────────────┘\n", - " │\n", - " ┌────────────┼────────────┐\n", - " │ │ │\n", - " ▼ ▼ ▼\n", - " ┌────────┐ ┌─────────┐ ┌─────────┐\n", - " │ Tools │ │ Memory │ │ RAG │\n", - " └────────┘ └─────────┘ └─────────┘\n", - " │ │ │\n", - " └────────────┼────────────┘\n", - " │\n", - " ▼\n", - " ┌─────────────────┐\n", - " │ Redis Stack │\n", - " │ (Storage + │\n", - " │ Vector Search)│\n", - " └─────────────────┘\n", - "```\n", - "\n", - "\n" - ], - "id": "d4a533d945ca605e" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🔧 Part 6: Working Memory Compression for Long Conversations\n", - "\n", - "Now that we have a working agent, let's address a production challenge: **What happens when conversations get very long?**\n" - ], - "id": "c4654c5a2c4e5323" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### 🔗 Connection to Section 3, Notebook 3\n", - "\n", - "In **Section 3, Notebook 3**, we learned about working memory compression strategies:\n", - "- **Truncation** - Keep only recent N messages (fast, simple)\n", - "- **Priority-Based** - Score messages by importance (balanced)\n", - "- **Summarization** - LLM creates intelligent summaries (high quality)\n", - "\n", - "**In this section**, we'll demonstrate these strategies in our production agent to show how they handle long conversations.\n" - ], - "id": "346d2737598bfd31" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### The Problem: Unbounded Conversation Growth\n", - "\n", - "Every conversation turn adds messages to working memory:\n", - "\n", - "```\n", - "Turn 1: System (500) + Messages (200) = 700 tokens ✅\n", - "Turn 10: System (500) + Messages (2,000) = 2,500 tokens ✅\n", - "Turn 30: System (500) + Messages (6,000) = 6,500 tokens ⚠️\n", - "Turn 50: System (500) + Messages (10,000) = 10,500 tokens ⚠️\n", - "Turn 100: System (500) + Messages (20,000) = 20,500 tokens ❌\n", - "```\n", - "\n", - "**Without compression:**\n", - "- 💰 Costs grow quadratically (each turn includes all previous messages)\n", - "- ⏱️ Latency increases with context size\n", - "- 🚫 Eventually hit token limits (128K for GPT-4o)\n", - "- 📉 Context rot: LLMs struggle with very long contexts\n", - "\n", - "**Solution:** Compress working memory while preserving important information.\n" - ], - "id": "6a1c7e21740d4240" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Implementation: Three Compression Strategies\n", - "\n", - "Let's implement the strategies from Section 3, Notebook 3.\n" - ], - "id": "439770b03604fe49" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "from dataclasses import dataclass\n", - "from enum import Enum\n", - "from typing import Dict, List, Tuple\n", - "\n", - "import tiktoken\n", - "\n", - "# Token counting utility\n", - "\n", - "\n", - "def count_tokens(text: str, model: str = \"gpt-4o\") -> int:\n", - " \"\"\"Count tokens in text using tiktoken.\"\"\"\n", - " try:\n", - " encoding = tiktoken.encoding_for_model(model)\n", - " return len(encoding.encode(text))\n", - " except Exception:\n", - " # Fallback: rough estimate\n", - " return len(text) // 4\n", - "\n", - "\n", - "@dataclass\n", - "class ConversationMessage:\n", - " \"\"\"Represents a conversation message with metadata.\"\"\"\n", - "\n", - " role: str\n", - " content: str\n", - " token_count: int = 0\n", - "\n", - " def __post_init__(self):\n", - " if self.token_count == 0:\n", - " self.token_count = count_tokens(self.content)\n", - "\n", - "\n", - "print(\"✅ Token counting utilities defined\")" - ], - "id": "821ce9b3f3abe835" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "#### Strategy 1: Truncation (Fast, Simple)\n", - "\n", - "Keep only the most recent N messages within token budget.\n", - "\n", - "**Pros:** Fast, no LLM calls, predictable\n", - "**Cons:** Loses all old context, no intelligence\n" - ], - "id": "f1d1881df6ca55de" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "class TruncationStrategy:\n", - " \"\"\"Keep only the most recent messages within token budget.\"\"\"\n", - "\n", - " def compress(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Keep most recent messages within token budget.\"\"\"\n", - " compressed = []\n", - " total_tokens = 0\n", - "\n", - " # Work backwards from most recent\n", - " for msg in reversed(messages):\n", - " if total_tokens + msg.token_count <= max_tokens:\n", - " compressed.insert(0, msg)\n", - " total_tokens += msg.token_count\n", - " else:\n", - " break\n", - "\n", - " return compressed\n", - "\n", - "\n", - "print(\"✅ Truncation strategy implemented\")" - ], - "id": "1df1a0aa4aabfb41" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "#### Strategy 2: Priority-Based (Balanced)\n", - "\n", - "Score messages by importance and keep highest-scoring ones.\n", - "\n", - "**Pros:** Preserves important context, no LLM calls\n", - "**Cons:** Requires good scoring logic, may lose temporal flow\n" - ], - "id": "3dcc2d1ef45c9d33" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "class PriorityBasedStrategy:\n", - " \"\"\"Score messages by importance and keep highest-scoring.\"\"\"\n", - "\n", - " def _score_message(self, msg: ConversationMessage, index: int, total: int) -> float:\n", - " \"\"\"\n", - " Score message importance.\n", - "\n", - " Higher scores for:\n", - " - Recent messages (recency bias)\n", - " - Longer messages (more information)\n", - " - User messages (user intent)\n", - " - Messages with keywords (course names, preferences)\n", - " \"\"\"\n", - " score = 0.0\n", - "\n", - " # Recency: Recent messages get higher scores\n", - " recency_score = index / total\n", - " score += recency_score * 50\n", - "\n", - " # Length: Longer messages likely have more info\n", - " length_score = min(msg.token_count / 100, 1.0)\n", - " score += length_score * 20\n", - "\n", - " # Role: User messages are important (capture intent)\n", - " if msg.role == \"user\":\n", - " score += 15\n", - "\n", - " # Keywords: Messages with important terms\n", - " keywords = [\"course\", \"RU\", \"prefer\", \"interested\", \"goal\", \"major\", \"graduate\"]\n", - " keyword_count = sum(1 for kw in keywords if kw.lower() in msg.content.lower())\n", - " score += keyword_count * 5\n", - "\n", - " return score\n", - "\n", - " def compress(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Keep highest-scoring messages within token budget.\"\"\"\n", - " # Score all messages\n", - " scored = [\n", - " (self._score_message(msg, i, len(messages)), i, msg)\n", - " for i, msg in enumerate(messages)\n", - " ]\n", - "\n", - " # Sort by score (descending)\n", - " scored.sort(reverse=True, key=lambda x: x[0])\n", - "\n", - " # Select messages within budget\n", - " selected = []\n", - " total_tokens = 0\n", - "\n", - " for score, idx, msg in scored:\n", - " if total_tokens + msg.token_count <= max_tokens:\n", - " selected.append((idx, msg))\n", - " total_tokens += msg.token_count\n", - "\n", - " # Sort by original order to maintain conversation flow\n", - " selected.sort(key=lambda x: x[0])\n", - "\n", - " return [msg for idx, msg in selected]\n", - "\n", - "\n", - "print(\"✅ Priority-based strategy implemented\")" - ], - "id": "edc2ffeac82e03ba" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "#### Strategy 3: Summarization (High Quality)\n", - "\n", - "Use LLM to create intelligent summaries of old messages, keep recent ones.\n", - "\n", - "**Pros:** Preserves meaning, high quality, intelligent compression\n", - "**Cons:** Slower, costs tokens, requires LLM call\n" - ], - "id": "7a8408f151375688" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "class SummarizationStrategy:\n", - " \"\"\"Use LLM to create intelligent summaries.\"\"\"\n", - "\n", - " def __init__(self, llm: ChatOpenAI, keep_recent: int = 4):\n", - " self.llm = llm\n", - " self.keep_recent = keep_recent\n", - "\n", - " self.summarization_prompt = \"\"\"You are summarizing a conversation between a student and a course advisor.\n", - "\n", - "Create a concise summary that preserves:\n", - "1. Key decisions made\n", - "2. Important requirements or prerequisites discussed\n", - "3. Student's goals, preferences, and constraints\n", - "4. Specific courses mentioned and recommendations given\n", - "5. Any problems or issues that need follow-up\n", - "\n", - "Format as bullet points. Be specific and actionable.\n", - "\n", - "Conversation:\n", - "{conversation}\n", - "\n", - "Summary:\"\"\"\n", - "\n", - " async def compress_async(\n", - " self, messages: List[ConversationMessage], max_tokens: int\n", - " ) -> List[ConversationMessage]:\n", - " \"\"\"Compress using summarization (async).\"\"\"\n", - " if len(messages) <= self.keep_recent:\n", - " return messages\n", - "\n", - " # Split into old (to summarize) and recent (to keep)\n", - " old_messages = messages[: -self.keep_recent]\n", - " recent_messages = messages[-self.keep_recent :]\n", - "\n", - " # Format old messages for summarization\n", - " conversation_text = \"\\n\".join(\n", - " [f\"{msg.role.title()}: {msg.content}\" for msg in old_messages]\n", - " )\n", - "\n", - " # Generate summary using LLM\n", - " prompt = self.summarization_prompt.format(conversation=conversation_text)\n", - " response = await self.llm.ainvoke([HumanMessage(content=prompt)])\n", - "\n", - " summary_content = f\"[CONVERSATION SUMMARY]\\n{response.content}\"\n", - "\n", - " # Create summary message\n", - " summary_msg = ConversationMessage(role=\"system\", content=summary_content)\n", - "\n", - " # Return summary + recent messages\n", - " return [summary_msg] + recent_messages\n", - "\n", - "\n", - "print(\"✅ Summarization strategy implemented\")" - ], - "id": "33dd8c677f8c24ba", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Demo: Simulating a Long Conversation\n", - "\n", - "Let's create a realistic 30-turn conversation to demonstrate compression needs.\n" - ], - "id": "225f1520b9ed27e1" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Simulate a long advising conversation (30 turns = 60 messages)\n", - "long_conversation_turns = [\n", - " (\n", - " \"I'm interested in machine learning courses\",\n", - " \"Great! Let me help you find ML courses.\",\n", - " ),\n", - " (\"What are the prerequisites?\", \"You'll need data structures and linear algebra.\"),\n", - " (\"I've completed CS201 Data Structures\", \"Perfect! That's one prerequisite done.\"),\n", - " (\"Do I need calculus?\", \"Yes, MATH301 Linear Algebra is required.\"),\n", - " (\"I'm taking that next semester\", \"Excellent planning!\"),\n", - " (\"What ML courses do you recommend?\", \"RU330 and RU401 are great for ML.\"),\n", - " (\"Tell me about RU330\", \"RU330 covers trading engines with ML applications.\"),\n", - " (\"Is it available online?\", \"Yes, RU330 is available in online format.\"),\n", - " (\n", - " \"What about RU401?\",\n", - " \"RU401 focuses on running Redis at scale with vector search.\",\n", - " ),\n", - " (\n", - " \"That sounds perfect for AI\",\n", - " \"Absolutely! Vector search is key for AI applications.\",\n", - " ),\n", - " (\n", - " \"I prefer online courses\",\n", - " \"I'll note that preference for future recommendations.\",\n", - " ),\n", - " (\"I work part-time\", \"Online courses are great for working students.\"),\n", - " (\"When should I take RU330?\", \"After completing your prerequisites.\"),\n", - " (\"Can I take both together?\", \"Yes, if you have time. Both are 3-credit courses.\"),\n", - " (\"What's the workload like?\", \"Expect 6-8 hours per week for each course.\"),\n", - " (\"I'm also interested in databases\", \"RU301 covers querying and indexing.\"),\n", - " (\"Is that a prerequisite for RU401?\", \"No, but it's helpful background knowledge.\"),\n", - " (\"What order should I take them?\", \"RU301 first, then RU330, then RU401.\"),\n", - " (\"That's a good progression\", \"Yes, it builds your skills systematically.\"),\n", - " (\"I want to graduate in Spring 2026\", \"Let's plan your course schedule.\"),\n", - " (\"I can take 2 courses per semester\", \"That's manageable with work.\"),\n", - " (\"Fall 2025: RU301 and what else?\", \"Maybe RU330 if prerequisites are done.\"),\n", - " (\"Spring 2026: RU401?\", \"Yes, that completes your ML track.\"),\n", - " (\"Are there any capstone projects?\", \"RU401 includes a vector search project.\"),\n", - " (\"That sounds challenging\", \"It's practical and portfolio-worthy.\"),\n", - " (\"I'm interested in tech startups\", \"These courses are perfect for startup roles.\"),\n", - " (\"Do you have career resources?\", \"We have career services and job boards.\"),\n", - " (\"Can I get internship help?\", \"Yes, our career center helps with internships.\"),\n", - " (\"This has been very helpful\", \"I'm glad I could help plan your path!\"),\n", - " (\"I'll start with RU301 next semester\", \"Excellent choice! Good luck!\"),\n", - "]\n", - "\n", - "# Convert to ConversationMessage objects\n", - "long_conversation = []\n", - "for user_msg, assistant_msg in long_conversation_turns:\n", - " long_conversation.append(ConversationMessage(role=\"user\", content=user_msg))\n", - " long_conversation.append(\n", - " ConversationMessage(role=\"assistant\", content=assistant_msg)\n", - " )\n", - "\n", - "# Calculate statistics\n", - "total_messages = len(long_conversation)\n", - "total_tokens = sum(msg.token_count for msg in long_conversation)\n", - "avg_tokens_per_msg = total_tokens / total_messages\n", - "\n", - "print(\"📊 Long Conversation Statistics\")\n", - "print(\"=\" * 80)\n", - "print(f\"Total turns: {len(long_conversation_turns)}\")\n", - "print(f\"Total messages: {total_messages}\")\n", - "print(f\"Total tokens: {total_tokens:,}\")\n", - "print(f\"Average tokens per message: {avg_tokens_per_msg:.1f}\")\n", - "print(f\"\\n⚠️ This conversation is getting expensive!\")\n", - "print(\n", - " f\" Cost per query (at $0.0025/1K tokens): ${(total_tokens / 1000) * 0.0025:.4f}\"\n", - ")\n", - "print(f\" Over 1,000 conversations: ${((total_tokens / 1000) * 0.0025) * 1000:.2f}\")" - ], - "id": "cccf2fb420c9025a", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Comparison: Testing All Three Strategies\n", - "\n", - "Let's compress this conversation using all three strategies and compare results.\n" - ], - "id": "dcfc2ebd5306f8cb" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Set compression budget\n", - "max_tokens = 1000 # Target: compress from ~1,500 tokens to ~1,000 tokens\n", - "\n", - "print(\"🔬 Compression Strategy Comparison\")\n", - "print(\"=\" * 80)\n", - "print(f\"Original: {total_messages} messages, {total_tokens:,} tokens\")\n", - "print(f\"Target: {max_tokens:,} tokens (compression needed!)\\n\")\n", - "\n", - "# Strategy 1: Truncation\n", - "truncation = TruncationStrategy()\n", - "truncated = truncation.compress(long_conversation, max_tokens)\n", - "truncated_tokens = sum(msg.token_count for msg in truncated)\n", - "\n", - "print(\"1️⃣ TRUNCATION STRATEGY\")\n", - "print(f\" Result: {len(truncated)} messages, {truncated_tokens:,} tokens\")\n", - "print(\n", - " f\" Savings: {total_tokens - truncated_tokens:,} tokens ({((total_tokens - truncated_tokens) / total_tokens * 100):.1f}%)\"\n", - ")\n", - "print(f\" Kept: Most recent {len(truncated)} messages\")\n", - "print(f\" Lost: First {total_messages - len(truncated)} messages (all early context)\")\n", - "\n", - "# Strategy 2: Priority-Based\n", - "priority = PriorityBasedStrategy()\n", - "prioritized = priority.compress(long_conversation, max_tokens)\n", - "prioritized_tokens = sum(msg.token_count for msg in prioritized)\n", - "\n", - "print(f\"\\n2️⃣ PRIORITY-BASED STRATEGY\")\n", - "print(f\" Result: {len(prioritized)} messages, {prioritized_tokens:,} tokens\")\n", - "print(\n", - " f\" Savings: {total_tokens - prioritized_tokens:,} tokens ({((total_tokens - prioritized_tokens) / total_tokens * 100):.1f}%)\"\n", - ")\n", - "print(f\" Kept: {len(prioritized)} highest-scoring messages\")\n", - "print(f\" Preserved: Important context from throughout conversation\")\n", - "\n", - "# Show which messages were kept (by index)\n", - "kept_indices = []\n", - "for msg in prioritized:\n", - " for i, orig_msg in enumerate(long_conversation):\n", - " if msg.content == orig_msg.content and msg.role == orig_msg.role:\n", - " kept_indices.append(i)\n", - " break\n", - "print(\n", - " f\" Message indices kept: {sorted(set(kept_indices))[:10]}... (showing first 10)\"\n", - ")\n", - "\n", - "# Strategy 3: Summarization\n", - "summarization = SummarizationStrategy(llm=llm, keep_recent=4)\n", - "summarized = await summarization.compress_async(long_conversation, max_tokens)\n", - "summarized_tokens = sum(msg.token_count for msg in summarized)\n", - "\n", - "print(f\"\\n3️⃣ SUMMARIZATION STRATEGY\")\n", - "print(f\" Result: {len(summarized)} messages, {summarized_tokens:,} tokens\")\n", - "print(\n", - " f\" Savings: {total_tokens - summarized_tokens:,} tokens ({((total_tokens - summarized_tokens) / total_tokens * 100):.1f}%)\"\n", - ")\n", - "print(f\" Structure: 1 summary + {len(summarized) - 1} recent messages\")\n", - "print(f\" Preserved: Meaning of all {total_messages - 4} old messages in summary\")\n", - "\n", - "# Show summary preview\n", - "summary_msg = summarized[0]\n", - "print(f\"\\n Summary preview:\")\n", - "summary_lines = summary_msg.content.split(\"\\n\")[:5]\n", - "for line in summary_lines:\n", - " print(f\" {line}\")\n", - "if len(summary_msg.content.split(\"\\n\")) > 5:\n", - " print(f\" ... ({len(summary_msg.content.split('\\n')) - 5} more lines)\")" - ], - "id": "58fab84b7f0fb661", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Comparison Table\n", - "id": "b5874671e946a4d8" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Create comparison table\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"📊 COMPRESSION STRATEGY COMPARISON TABLE\")\n", - "print(\"=\" * 80)\n", - "print(\n", - " f\"{'Strategy':<20} {'Messages':<12} {'Tokens':<12} {'Savings':<15} {'Quality':<10} {'Speed'}\"\n", - ")\n", - "print(\"-\" * 80)\n", - "\n", - "strategies_data = [\n", - " (\"Original\", total_messages, total_tokens, \"0 (0%)\", \"N/A\", \"N/A\"),\n", - " (\n", - " \"Truncation\",\n", - " len(truncated),\n", - " truncated_tokens,\n", - " f\"{total_tokens - truncated_tokens} ({((total_tokens - truncated_tokens) / total_tokens * 100):.0f}%)\",\n", - " \"Low\",\n", - " \"Fast\",\n", - " ),\n", - " (\n", - " \"Priority-Based\",\n", - " len(prioritized),\n", - " prioritized_tokens,\n", - " f\"{total_tokens - prioritized_tokens} ({((total_tokens - prioritized_tokens) / total_tokens * 100):.0f}%)\",\n", - " \"Medium\",\n", - " \"Fast\",\n", - " ),\n", - " (\n", - " \"Summarization\",\n", - " len(summarized),\n", - " summarized_tokens,\n", - " f\"{total_tokens - summarized_tokens} ({((total_tokens - summarized_tokens) / total_tokens * 100):.0f}%)\",\n", - " \"High\",\n", - " \"Slow\",\n", - " ),\n", - "]\n", - "\n", - "for name, msgs, tokens, savings, quality, speed in strategies_data:\n", - " print(f\"{name:<20} {msgs:<12} {tokens:<12} {savings:<15} {quality:<10} {speed}\")\n", - "\n", - "print(\"\\n💡 Key Insights:\")\n", - "print(\" • Truncation: Fastest but loses all early context\")\n", - "print(\" • Priority-Based: Good balance, preserves important messages\")\n", - "print(\" • Summarization: Best quality, preserves meaning of entire conversation\")\n", - "print(\" • Choose based on your quality/speed/cost requirements\")" - ], - "id": "c55826be685cfa3d", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Agent Memory Server's Automatic Compression\n", - "\n", - "The Agent Memory Server provides automatic compression through the `WINDOW_SIZE` configuration.\n", - "\n", - "**How it works:**\n", - "1. You set `WINDOW_SIZE` in environment variables (e.g., `WINDOW_SIZE=20`)\n", - "2. When working memory exceeds this threshold, automatic compression triggers\n", - "3. Server uses summarization strategy (similar to our Strategy 3)\n", - "4. Old messages are summarized, recent messages are kept\n", - "5. Your application retrieves compressed memory transparently\n", - "\n", - "**Configuration Example:**\n", - "\n", - "```bash\n", - "# In .env file\n", - "WINDOW_SIZE=20 # Trigger compression after 20 messages\n", - "LONG_TERM_MEMORY=true # Enable long-term memory\n", - "REDIS_URL=redis://localhost:6379\n", - "```\n", - "\n", - "**In production:**\n", - "- ✅ Automatic compression (no manual intervention)\n", - "- ✅ Configurable thresholds\n", - "- ✅ Background processing (async workers)\n", - "- ✅ Transparent to your application\n" - ], - "id": "3df8a7dfed12ad73" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### When to Use Each Strategy\n", - "\n", - "**Use Truncation when:**\n", - "- ✅ Speed is critical (real-time chat)\n", - "- ✅ Recent context is all that matters\n", - "- ✅ Cost-sensitive (no LLM calls)\n", - "- ✅ Simple implementation needed\n", - "\n", - "**Use Priority-Based when:**\n", - "- ✅ Need balance between speed and quality\n", - "- ✅ Important context scattered throughout conversation\n", - "- ✅ No LLM calls allowed (cost/latency constraints)\n", - "- ✅ Custom scoring logic available\n", - "\n", - "**Use Summarization when:**\n", - "- ✅ Quality is critical (preserve all important info)\n", - "- ✅ Long conversations (30+ turns)\n", - "- ✅ Can afford LLM call latency\n", - "- ✅ Comprehensive context needed\n", - "\n", - "**Use Agent Memory Server when:**\n", - "- ✅ Production deployment\n", - "- ✅ Want automatic management\n", - "- ✅ Need scalability\n", - "- ✅ Prefer transparent operation\n" - ], - "id": "b25ca6d346ac38f3" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Production Recommendations\n", - "\n", - "**For most applications:**\n", - "```python\n", - "# Use Agent Memory Server with automatic compression\n", - "# Configuration in .env:\n", - "# WINDOW_SIZE=20\n", - "# LONG_TERM_MEMORY=true\n", - "```\n", - "\n", - "**For high-volume, cost-sensitive:**\n", - "```python\n", - "# Use priority-based compression manually\n", - "priority = PriorityBasedStrategy()\n", - "compressed = priority.compress(messages, max_tokens=2000)\n", - "```\n", - "\n", - "**For critical conversations:**\n", - "```python\n", - "# Use summarization with human review\n", - "summarization = SummarizationStrategy(llm=llm, keep_recent=6)\n", - "compressed = await summarization.compress_async(messages, max_tokens=3000)\n", - "# Store full conversation separately for audit\n", - "```\n", - "\n", - "**For real-time chat:**\n", - "```python\n", - "# Use truncation for speed\n", - "truncation = TruncationStrategy()\n", - "compressed = truncation.compress(messages, max_tokens=1500)\n", - "```\n" - ], - "id": "f85886cdfd7b8c63" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### 🔗 Connection Back to Section 3\n", - "\n", - "**Section 3, Notebook 3** taught the theory:\n", - "- Why compression is needed (token limits, cost, performance)\n", - "- Three compression strategies (truncation, priority, summarization)\n", - "- Decision framework for choosing strategies\n", - "- Agent Memory Server configuration\n", - "\n", - "**This section** demonstrated the practice:\n", - "- ✅ Implemented all three strategies in working code\n", - "- ✅ Tested with realistic 30-turn conversation\n", - "- ✅ Compared results with metrics\n", - "- ✅ Showed when to use each strategy\n", - "- ✅ Connected to Agent Memory Server's automatic features\n", - "\n", - "**Key Takeaway:** You now understand both the theory (Section 3) and practice (Section 4) of working memory compression for production agents!\n", - "\n", - "\n", - "\n" - ], - "id": "953e03c75beccdb4" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🎓 Key Takeaways\n", - "\n", - "### **1. Agents = RAG + Tools + Decision-Making**\n", - "- RAG retrieves information\n", - "- Tools enable actions\n", - "- Agents decide when to use each\n", - "\n", - "### **2. Memory is Critical for Personalization**\n", - "- Working memory enables conversation continuity\n", - "- Long-term memory enables personalization\n", - "- Agents can decide when to store/recall memories\n", - "\n", - "### **3. LangGraph Simplifies Complex Workflows**\n", - "- State management is automatic\n", - "- Conditional routing is declarative\n", - "- Visualization helps debugging\n", - "\n", - "### **4. Tool Design Matters**\n", - "- Clear descriptions guide LLM selection\n", - "- Well-defined schemas prevent errors\n", - "- Focused tools are better than Swiss Army knives\n", - "\n", - "### **5. Trade-offs to Consider**\n", - "- **Complexity**: Agents are more complex than RAG\n", - "- **Latency**: Multiple tool calls add latency\n", - "- **Cost**: More LLM calls = higher cost\n", - "- **Value**: Worth it for complex, multi-step tasks\n", - "\n", - "### **6. When to Use Agents vs RAG**\n", - "\n", - "**Use RAG when:**\n", - "- Simple question answering\n", - "- Single-step retrieval\n", - "- Low latency required\n", - "- Predictable workflows\n", - "\n", - "**Use Agents when:**\n", - "- Multi-step reasoning needed\n", - "- Actions beyond retrieval\n", - "- Personalization required\n", - "- Complex decision-making\n" - ], - "id": "6064fff959e6e811" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🚀 What's Next?\n", - "\n", - "### **Continue to Notebook 4: Semantic Tool Selection**\n", - "\n", - "In the next notebook, you'll learn how to scale your agent from 3 to 5+ tools using semantic tool selection:\n", - "\n", - "**What You'll Learn:**\n", - "- Understanding tool token cost and scaling challenges\n", - "- Comparing tool selection strategies (static, pre-filtered, semantic)\n", - "- Implementing RedisVL Semantic Router for intelligent tool routing\n", - "- Building an enhanced agent with dynamic tool selection\n", - "- Measuring performance improvements (60% token reduction!)\n", - "\n", - "**What You'll Build:**\n", - "- Add 2 new tools: `check_prerequisites` and `compare_courses`\n", - "- Implement semantic tool selection with RedisVL\n", - "- Scale to 100+ tools without token explosion\n", - "- Make informed decisions about tool selection strategies\n", - "\n", - "**Continue your journey:** Open `04_semantic_tool_selection.ipynb` to learn how to scale your agent! 🚀\n" - ], - "id": "ca5250d8cbfa9772" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 💡 Ideas to Extend This Agent (After Completing Section 4)\n", - "\n", - "### **Additional Tools:**\n", - "1. **Course Management**\n", - " - `get_course_details` - Get detailed info about a specific course\n", - " - `create_schedule` - Build a semester schedule\n", - " - `check_conflicts` - Detect time conflicts\n", - "\n", - "2. **Student Support**\n", - " - `get_instructor_info` - Find instructor details\n", - " - `check_availability` - Check course seat availability\n", - " - `register_for_course` - Course registration\n", - "\n", - "### **Enhanced Memory:**\n", - "- Automatic memory extraction from conversations\n", - "- Memory summarization for long conversations\n", - "- Memory importance scoring\n", - "- Memory expiration policies\n", - "\n", - "### **Improved Personalization:**\n", - "- Learning style detection\n", - "- Career path recommendations\n", - "- Skill gap analysis\n", - "- Progress tracking\n", - "\n", - "### **Production Considerations:**\n", - "- Authentication and authorization\n", - "- Logging and monitoring\n", - "- Caching for performance\n", - "- Fallback strategies\n", - "- Input validation and output filtering\n", - "\n", - "### **Reference Implementation:**\n", - "\n", - "Check out `reference-agent/` for a full production implementation with:\n", - "- 7 tools (vs our 3)\n", - "- Advanced memory management\n", - "- Semantic tool selection\n", - "- Comprehensive error handling\n", - "- CLI interface\n", - "- Full test suite\n" - ], - "id": "88773a005e5cba59" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 📚 Section 4 Progress\n", - "\n", - "You've completed Notebook 3 of 4 in Section 4! Here's what you've learned so far:\n", - "\n", - "**Section 4 - Notebook 1:** Tools and LangGraph Fundamentals\n", - "- Tool creation and schemas\n", - "- LangGraph basics (nodes, edges, state)\n", - "- Active vs passive memory management\n", - "\n", - "**Section 4 - Notebook 2:** Building a Course Advisor Agent\n", - "- Complete production agent with 3 tools\n", - "- Memory-driven tool design\n", - "- Multi-step reasoning with memory\n", - "\n", - "**Section 4 - Notebook 3:** Agent with Memory Compression (This Notebook)\n", - "- Truncation and sliding window compression\n", - "- Production memory patterns\n", - "- Token budget management\n", - "\n", - "**Section 4 - Notebook 4:** Semantic Tool Selection (Next!)\n", - "- Tool selection strategies\n", - "- Semantic tool routing with RedisVL\n", - "- Scaling to 100+ tools\n", - "\n", - "### **Continue to Notebook 4!**\n", - "\n", - "You're almost done with Section 4! Complete the final notebook to learn how to scale your agent with semantic tool selection. 🚀\n", - "\n", - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "\n", - "- [Agent Memory Server Documentation](https://github.com/redis/agent-memory-server) - Production-ready memory management\n", - "- [Agent Memory Client](https://pypi.org/project/agent-memory-client/) - Python client for Agent Memory Server\n", - "- [RedisVL Documentation](https://redisvl.com/) - Redis Vector Library\n", - "- [Retrieval-Augmented Generation Paper](https://arxiv.org/abs/2005.11401) - Original RAG research\n", - "- [LangChain RAG Tutorial](https://python.langchain.com/docs/use_cases/question_answering/) - Building RAG systems\n", - "- [LangGraph Tutorials](https://langchain-ai.github.io/langgraph/tutorials/) - Building agents with LangGraph\n", - "- [Agent Architectures](https://python.langchain.com/docs/modules/agents/) - Different agent patterns\n", - "- [ReAct: Synergizing Reasoning and Acting](https://arxiv.org/abs/2210.03629) - Reasoning + acting in LLMs\n", - "- [Anthropic's Guide to Building Effective Agents](https://www.anthropic.com/research/building-effective-agents) - Agent design patterns\n", - "\n", - "---\n", - "\n", - "**Thank you for completing this course! 🙏**\n" - ], - "id": "70ab2e1e572d5aa6" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "4bfcd59e7fccb94d" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-4-tools-and-agents/04_semantic_tool_selection.ipynb b/notebooks/section-4-tools-and-agents/04_semantic_tool_selection.ipynb deleted file mode 100644 index 9445bee..0000000 --- a/notebooks/section-4-tools-and-agents/04_semantic_tool_selection.ipynb +++ /dev/null @@ -1,2690 +0,0 @@ -{ - "cells": [ - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120)\n", - "\n", - "# 🎯 Scaling with Semantic Tool Selection\n", - "\n", - "**⏱️ Estimated Time:** 60-75 minutes\n", - "\n", - "## 🎯 Learning Objectives\n", - "\n", - "By the end of this notebook, you will:\n", - "\n", - "1. **Understand** the token cost of tool definitions and scaling challenges\n", - "2. **Compare** tool selection strategies (static, pre-filtered, semantic)\n", - "3. **Implement** semantic tool selection using **RedisVL Semantic Router**\n", - "4. **Build** an enhanced agent that scales from 3 to 5 tools\n", - "5. **Measure** performance improvements (token savings, accuracy)\n", - "6. **Apply** production-ready tool routing patterns\n", - "7. **Make** informed decisions about when to use each strategy\n", - "\n", - "---\n", - "\n", - "## 🔗 Where We Are\n", - "\n", - "### **Your Journey Through Section 4:**\n", - "\n", - "**Notebook 1:** Tools and LangGraph Fundamentals\n", - "- ✅ Learned what tools are and how LLMs use them\n", - "- ✅ Understood LangGraph basics (nodes, edges, state)\n", - "- ✅ Built simple tool-calling examples\n", - "\n", - "**Notebook 2:** Building a Course Advisor Agent\n", - "- ✅ Built complete agent with 3 tools\n", - "- ✅ Integrated dual memory (working + long-term)\n", - "- ✅ Implemented LangGraph workflow\n", - "- ✅ Visualized agent decision-making\n", - "\n", - "**Notebook 3:** Agent with Memory Compression\n", - "- ✅ Added memory compression strategies\n", - "- ✅ Optimized conversation history management\n", - "- ✅ Learned production memory patterns\n", - "\n", - "**Current Agent State:**\n", - "```\n", - "Tools: 3 (search_courses, search_memories, store_memory)\n", - "Memory: Working + Long-term (compressed)\n", - "Token overhead: ~1,200 tokens for tool definitions\n", - "```\n", - "\n", - "### **The Next Challenge: Scaling Tools**\n", - "\n", - "**What if we want to add more capabilities?**\n", - "- Add prerequisite checking → +1 tool\n", - "- Add course comparison → +1 tool\n", - "- Add enrollment tracking → +1 tool\n", - "- Add progress monitoring → +1 tool\n", - "\n", - "**The Problem:**\n", - "- Each tool = ~300-500 tokens (schema + description)\n", - "- All tools sent to LLM every time, even when not needed\n", - "- Token cost grows linearly with number of tools\n", - "\n", - "**Example:**\n", - "```\n", - "3 tools = 1,200 tokens\n", - "5 tools = 2,200 tokens (+83%)\n", - "10 tools = 4,500 tokens (+275%)\n", - "20 tools = 9,000 tokens (+650%)\n", - "```\n", - "\n", - "---\n", - "\n", - "## 🎯 The Problem We'll Solve\n", - "\n", - "**\"We want to add more capabilities (tools) to our agent, but sending all tools every time is wasteful. How can we scale to 5+ tools without exploding our token budget?\"**\n", - "\n", - "### **What We'll Learn:**\n", - "\n", - "1. **Tool Token Cost** - Understanding the overhead of tool definitions\n", - "2. **Tool Selection Strategies** - Static vs Pre-filtered vs Semantic\n", - "3. **Semantic Tool Selection** - Using embeddings to match queries to tools\n", - "4. **RedisVL Semantic Router** - Production-ready routing patterns\n", - "5. **Trade-offs** - When to use each approach\n", - "\n", - "### **What We'll Build:**\n", - "\n", - "Starting with your Notebook 2 agent (3 tools), we'll add:\n", - "1. **2 New Tools** - `check_prerequisites`, `compare_courses`\n", - "2. **Tool Selection Strategies** - Compare different approaches\n", - "3. **Semantic Router** - RedisVL-based intelligent tool selection\n", - "4. **Enhanced Agent** - Uses only relevant tools per query\n", - "\n", - "### **Expected Results:**\n", - "\n", - "```\n", - "Metric Before (3 tools) After (5 tools) Improvement\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Tools available 3 5 +67%\n", - "Tool tokens (all) 1,200 2,200 +83%\n", - "Tool tokens (selected) 1,200 880 -27%\n", - "Tool selection accuracy 100% (all) ~91% (relevant) Smarter\n", - "Total tokens/query 3,400 2,200 -35%\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "```\n", - "\n", - "**💡 Key Insight:** \"Scale capabilities, not token costs - semantic selection enables both\"\n", - "\n", - "---\n", - "\n", - "## 📦 Part 0: Setup and Imports\n", - "\n", - "Let's start by importing everything we need.\n" - ], - "id": "16a30cc21ebde840" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Standard library imports\n", - "import asyncio\n", - "import json\n", - "import os\n", - "import time\n", - "from dataclasses import dataclass, field\n", - "from datetime import datetime\n", - "from pathlib import Path\n", - "from typing import Annotated, Any, Dict, List, Optional\n", - "\n", - "# Load environment variables from .env file\n", - "from dotenv import load_dotenv\n", - "\n", - "# Load .env from context-engineering directory (two levels up from notebooks_v2/section-5-optimization-production)\n", - "env_path = (\n", - " Path.cwd().parent.parent / \".env\"\n", - " if \"section-5\" in str(Path.cwd())\n", - " else Path(\".env\")\n", - ")\n", - "if env_path.exists():\n", - " load_dotenv(env_path)\n", - " print(f\"✅ Loaded environment from {env_path}\")\n", - "else:\n", - " # Try alternative path\n", - " alt_env_path = (\n", - " Path(__file__).resolve().parent.parent.parent / \".env\"\n", - " if \"__file__\" in dir()\n", - " else None\n", - " )\n", - " if alt_env_path and alt_env_path.exists():\n", - " load_dotenv(alt_env_path)\n", - " print(f\"✅ Loaded environment from {alt_env_path}\")\n", - " else:\n", - " print(f\"⚠️ Using system environment variables\")\n", - "\n", - "# Token counting\n", - "import tiktoken\n", - "\n", - "# Redis and Agent Memory\n", - "from agent_memory_client import MemoryAPIClient, MemoryClientConfig\n", - "from agent_memory_client.filters import UserId\n", - "from agent_memory_client.models import ClientMemoryRecord\n", - "from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage\n", - "from langchain_core.tools import tool\n", - "\n", - "# LangChain and LangGraph\n", - "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n", - "from langgraph.graph import END, StateGraph\n", - "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode\n", - "from pydantic import BaseModel, Field\n", - "\n", - "# RedisVL Extensions - NEW! Production-ready semantic routing\n", - "from redisvl.extensions.router import Route, SemanticRouter\n", - "\n", - "# RedisVL for vector search\n", - "from redisvl.index import SearchIndex\n", - "from redisvl.query import VectorQuery\n", - "from redisvl.schema import IndexSchema\n", - "\n", - "print(\"✅ All imports successful\")\n", - "print(\" 🆕 RedisVL Semantic Router imported\")" - ], - "id": "850994f73d2f03a6" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Environment Setup\n", - "id": "dcf49b4fa60d19fe" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Verify environment\n", - "required_vars = [\"OPENAI_API_KEY\"]\n", - "missing_vars = [var for var in required_vars if not os.getenv(var)]\n", - "\n", - "if missing_vars:\n", - " print(f\"❌ Missing environment variables: {', '.join(missing_vars)}\")\n", - "else:\n", - " print(\"✅ Environment variables configured\")\n", - "\n", - "# Set defaults\n", - "REDIS_URL = os.getenv(\"REDIS_URL\", \"redis://localhost:6379\")\n", - "AGENT_MEMORY_URL = os.getenv(\"AGENT_MEMORY_URL\", \"http://localhost:8000\")\n", - "\n", - "print(f\" Redis URL: {REDIS_URL}\")\n", - "print(f\" Agent Memory URL: {AGENT_MEMORY_URL}\")" - ], - "id": "a13df4b088728a78" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Initialize Clients\n", - "id": "bd7fe45d51f1a7be" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Initialize LLM\n", - "llm = ChatOpenAI(model=\"gpt-4o\", temperature=0.7, streaming=False)\n", - "\n", - "# Initialize embeddings\n", - "embeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\n", - "\n", - "# Initialize Agent Memory Client\n", - "memory_config = MemoryClientConfig(base_url=AGENT_MEMORY_URL)\n", - "memory_client = MemoryAPIClient(config=memory_config)\n", - "\n", - "print(\"✅ Clients initialized\")\n", - "print(f\" LLM: {llm.model_name}\")\n", - "print(f\" Embeddings: text-embedding-3-small (1536 dimensions)\")\n", - "print(f\" Memory Client: Connected\")" - ], - "id": "b05414b3bb3844cb" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Student Profile and Token Counter\n", - "id": "e9683f1bfbc12982" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Student profile (same as before)\n", - "STUDENT_ID = \"sarah_chen_12345\"\n", - "SESSION_ID = f\"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}\"\n", - "\n", - "# Token counting function (from Notebook 1)\n", - "\n", - "\n", - "def count_tokens(text: str, model: str = \"gpt-4o\") -> int:\n", - " \"\"\"Count tokens in text using tiktoken.\"\"\"\n", - " try:\n", - " encoding = tiktoken.encoding_for_model(model)\n", - " except KeyError:\n", - " encoding = tiktoken.get_encoding(\"cl100k_base\")\n", - " return len(encoding.encode(text))\n", - "\n", - "\n", - "print(\"✅ Student profile and utilities ready\")\n", - "print(f\" Student ID: {STUDENT_ID}\")\n", - "print(f\" Session ID: {SESSION_ID}\")" - ], - "id": "ef9b3b5a1d281c49" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🔍 Part 1: Understanding Tool Token Cost\n", - "\n", - "Before we add more tools, let's understand the token cost of tool definitions.\n", - "\n", - "### 🔬 Theory: Tool Token Overhead\n", - "\n", - "**What Gets Sent to the LLM:**\n", - "\n", - "When you bind tools to an LLM, the following gets sent with every request:\n", - "1. **Tool name** - The function name\n", - "2. **Tool description** - What the tool does\n", - "3. **Parameter schema** - All parameters with types and descriptions\n", - "4. **Return type** - What the tool returns\n", - "\n", - "**Example Tool Definition:**\n", - "```python\n", - "@tool(\"search_courses\")\n", - "async def search_courses(query: str, limit: int = 5) -> str:\n", - " '''Search for courses using semantic search.'''\n", - " ...\n", - "```\n", - "\n", - "**What LLM Sees (JSON Schema):**\n", - "```json\n", - "{\n", - " \"name\": \"search_courses\",\n", - " \"description\": \"Search for courses using semantic search.\",\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"query\": {\"type\": \"string\", \"description\": \"...\"},\n", - " \"limit\": {\"type\": \"integer\", \"description\": \"...\"}\n", - " }\n", - " }\n", - "}\n", - "```\n", - "\n", - "**Token Cost:** ~300-500 tokens per tool\n", - "\n", - "**💡 Key Insight:** Tool definitions are verbose! The more tools, the more tokens wasted on unused tools.\n" - ], - "id": "5fd160e796bd869d" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Load Notebook 1 Tools\n", - "\n", - "Let's load the 3 tools from Notebook 1 and measure their token cost.\n" - ], - "id": "42008c6fc8fbda44" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# We'll need the course manager and catalog summary from NB1\n", - "\n", - "\n", - "class CourseManager:\n", - " \"\"\"Manage course catalog with Redis vector search.\"\"\"\n", - "\n", - " def __init__(self, redis_url: str, index_name: str = \"course_catalog\"):\n", - " self.redis_url = redis_url\n", - " self.index_name = index_name\n", - " self.embeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\n", - "\n", - " try:\n", - " self.index = SearchIndex.from_existing(\n", - " name=self.index_name, redis_url=self.redis_url\n", - " )\n", - " except Exception as e:\n", - " print(f\"⚠️ Warning: Could not load course catalog index: {e}\")\n", - " self.index = None\n", - "\n", - " async def search_courses(self, query: str, limit: int = 5) -> List[Dict[str, Any]]:\n", - " \"\"\"Search for courses using semantic search.\"\"\"\n", - " if not self.index:\n", - " return []\n", - "\n", - " query_embedding = await self.embeddings.aembed_query(query)\n", - "\n", - " vector_query = VectorQuery(\n", - " vector=query_embedding,\n", - " vector_field_name=\"course_embedding\",\n", - " return_fields=[\n", - " \"course_id\",\n", - " \"title\",\n", - " \"description\",\n", - " \"department\",\n", - " \"credits\",\n", - " \"format\",\n", - " ],\n", - " num_results=limit,\n", - " )\n", - "\n", - " results = self.index.query(vector_query)\n", - " return results\n", - "\n", - "\n", - "# Initialize course manager\n", - "course_manager = CourseManager(redis_url=REDIS_URL)\n", - "\n", - "print(\"✅ Course manager initialized\")" - ], - "id": "77ab9c02ba96ad8e" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Build catalog summary (simplified version for NB2)\n", - "\n", - "\n", - "async def build_catalog_summary() -> str:\n", - " \"\"\"Build course catalog summary.\"\"\"\n", - " summary = \"\"\"\n", - "REDIS UNIVERSITY COURSE CATALOG OVERVIEW\n", - "========================================\n", - "Total Courses: ~150 courses across 10 departments\n", - "\n", - "Departments:\n", - "- Redis Basics (RU101, RU102JS, etc.)\n", - "- Data Structures (RU201, RU202, etc.)\n", - "- Search and Query (RU203, RU204, etc.)\n", - "- Time Series (RU301, RU302, etc.)\n", - "- Probabilistic Data Structures (RU401, etc.)\n", - "- Machine Learning (RU501, RU502, etc.)\n", - "- Graph Databases (RU601, etc.)\n", - "- Streams (RU701, etc.)\n", - "- Security (RU801, etc.)\n", - "- Advanced Topics (RU901, etc.)\n", - "\n", - "For detailed information, please ask about specific topics or courses!\n", - "\"\"\"\n", - " return summary.strip()\n", - "\n", - "\n", - "CATALOG_SUMMARY = await build_catalog_summary()\n", - "\n", - "print(\"✅ Catalog summary ready\")\n", - "print(f\" Summary tokens: {count_tokens(CATALOG_SUMMARY):,}\")" - ], - "id": "de9ae260e5a3877e" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Define the 3 Existing Tools\n", - "id": "764d3e2933d12f23" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Tool 1: search_courses_hybrid (from NB1)\n", - "\n", - "\n", - "async def search_courses_hybrid_func(query: str, limit: int = 5) -> str:\n", - " \"\"\"Search for courses using hybrid retrieval (overview + targeted search).\"\"\"\n", - " general_queries = [\n", - " \"what courses\",\n", - " \"available courses\",\n", - " \"course catalog\",\n", - " \"all courses\",\n", - " ]\n", - " is_general = any(phrase in query.lower() for phrase in general_queries)\n", - "\n", - " if is_general:\n", - " return f\"📚 Course Catalog Overview:\\n\\n{CATALOG_SUMMARY}\"\n", - " else:\n", - " results = await course_manager.search_courses(query, limit=limit)\n", - " if not results:\n", - " return \"No courses found.\"\n", - "\n", - " output = [f\"📚 Overview:\\n{CATALOG_SUMMARY[:200]}...\\n\\n🔍 Matching courses:\"]\n", - " for i, course in enumerate(results, 1):\n", - " output.append(f\"\\n{i}. {course['title']} ({course['course_id']})\")\n", - " output.append(f\" {course['description'][:100]}...\")\n", - "\n", - " return \"\\n\".join(output)\n", - "\n", - "\n", - "from langchain_core.tools import StructuredTool\n", - "\n", - "search_courses_hybrid = StructuredTool.from_function(\n", - " coroutine=search_courses_hybrid_func,\n", - " name=\"search_courses_hybrid\",\n", - " description=\"\"\"Search for courses using hybrid retrieval (overview + targeted search).\n", - "\n", - "Use this when students ask about:\n", - "- Course topics: \"machine learning courses\", \"database courses\"\n", - "- General exploration: \"what courses are available?\"\n", - "- Course characteristics: \"online courses\", \"beginner courses\"\n", - "\n", - "Returns: Catalog overview + targeted search results.\"\"\",\n", - ")\n", - "\n", - "print(\"✅ Tool 1: search_courses_hybrid\")" - ], - "id": "b13419da5a093015" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Tool 2: search_memories\n", - "\n", - "\n", - "async def search_memories_func(query: str, limit: int = 5) -> str:\n", - " \"\"\"Search the user's long-term memory for relevant facts, preferences, and past interactions.\"\"\"\n", - " try:\n", - " results = await memory_client.search_long_term_memory(\n", - " text=query, user_id=UserId(eq=STUDENT_ID), limit=limit\n", - " )\n", - "\n", - " if not results.memories or len(results.memories) == 0:\n", - " return \"No relevant memories found.\"\n", - "\n", - " output = []\n", - " for i, memory in enumerate(results.memories, 1):\n", - " output.append(f\"{i}. {memory.text}\")\n", - "\n", - " return \"\\n\".join(output)\n", - " except Exception as e:\n", - " return f\"Error searching memories: {str(e)}\"\n", - "\n", - "\n", - "search_memories = StructuredTool.from_function(\n", - " coroutine=search_memories_func,\n", - " name=\"search_memories\",\n", - " description=\"\"\"Search the user's long-term memory for relevant facts, preferences, and past interactions.\n", - "\n", - "Use this when you need to:\n", - "- Recall user preferences: \"What format does the user prefer?\"\n", - "- Remember past goals: \"What career path is the user interested in?\"\n", - "- Personalize recommendations based on history\n", - "\n", - "Returns: List of relevant memories.\"\"\",\n", - ")\n", - "\n", - "print(\"✅ Tool 2: search_memories\")" - ], - "id": "e7d8efb6acf607eb" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Tool 3: store_memory\n", - "\n", - "\n", - "async def store_memory_func(text: str, topics: List[str] = []) -> str:\n", - " \"\"\"Store important information to the user's long-term memory.\"\"\"\n", - " try:\n", - " memory = ClientMemoryRecord(\n", - " text=text, user_id=STUDENT_ID, memory_type=\"semantic\", topics=topics or []\n", - " )\n", - "\n", - " await memory_client.create_long_term_memory([memory])\n", - " return f\"✅ Stored to memory: {text}\"\n", - " except Exception as e:\n", - " return f\"Error storing memory: {str(e)}\"\n", - "\n", - "\n", - "store_memory = StructuredTool.from_function(\n", - " coroutine=store_memory_func,\n", - " name=\"store_memory\",\n", - " description=\"\"\"Store important information to the user's long-term memory.\n", - "\n", - "Use this when the user shares:\n", - "- Preferences: \"I prefer online courses\"\n", - "- Goals: \"I want to work in AI\"\n", - "- Important facts: \"I have a part-time job\"\n", - "- Constraints: \"I can only take 2 courses per semester\"\n", - "\n", - "Returns: Confirmation message.\"\"\",\n", - ")\n", - "\n", - "print(\"✅ Tool 3: store_memory\")" - ], - "id": "e0ee9ecbec8b205d" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Collect existing tools\n", - "existing_tools = [search_courses_hybrid, search_memories, store_memory]\n", - "\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"🛠️ EXISTING TOOLS (from Notebook 1)\")\n", - "print(\"=\" * 80)\n", - "for i, tool in enumerate(existing_tools, 1):\n", - " print(f\"{i}. {tool.name}\")\n", - "print(\"=\" * 80)" - ], - "id": "8fa9806d00082de1" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Measure Tool Token Cost\n", - "\n", - "Now let's measure how many tokens each tool definition consumes.\n" - ], - "id": "be031e26bff04360" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "def get_tool_token_cost(tool) -> int:\n", - " \"\"\"\n", - " Calculate the token cost of a tool definition.\n", - "\n", - " This includes:\n", - " - Tool name\n", - " - Tool description\n", - " - Parameter schema (JSON)\n", - " \"\"\"\n", - " # Get tool schema\n", - " tool_schema = {\n", - " \"name\": tool.name,\n", - " \"description\": tool.description,\n", - " \"parameters\": tool.args_schema.model_json_schema() if tool.args_schema else {},\n", - " }\n", - "\n", - " # Convert to JSON string (this is what gets sent to LLM)\n", - " tool_json = json.dumps(tool_schema, indent=2)\n", - "\n", - " # Count tokens\n", - " tokens = count_tokens(tool_json)\n", - "\n", - " return tokens\n", - "\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"📊 TOOL TOKEN COST ANALYSIS\")\n", - "print(\"=\" * 80)\n", - "\n", - "total_tokens = 0\n", - "for i, tool in enumerate(existing_tools, 1):\n", - " tokens = get_tool_token_cost(tool)\n", - " total_tokens += tokens\n", - " print(f\"{i}. {tool.name:<30} {tokens:>6} tokens\")\n", - "\n", - "print(\"-\" * 80)\n", - "print(f\"{'TOTAL (3 tools)':<30} {total_tokens:>6} tokens\")\n", - "print(\"=\" * 80)\n", - "\n", - "print(f\"\\n💡 Insight: These {total_tokens:,} tokens are sent with EVERY query!\")" - ], - "id": "42e9460235096339" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### The Scaling Problem\n", - "\n", - "What happens when we add more tools?\n" - ], - "id": "f617a96f39710ec4" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "print(\"=\" * 80)\n", - "print(\"📈 TOOL SCALING PROJECTION\")\n", - "print(\"=\" * 80)\n", - "\n", - "# Average tokens per tool\n", - "avg_tokens_per_tool = total_tokens / len(existing_tools)\n", - "\n", - "print(f\"\\nAverage tokens per tool: {avg_tokens_per_tool:.0f}\")\n", - "print(\"\\nProjected token cost:\")\n", - "print(f\"{'# Tools':<15} {'Token Cost':<15} {'vs 3 Tools':<15}\")\n", - "print(\"-\" * 80)\n", - "\n", - "for num_tools in [3, 5, 7, 10, 15, 20]:\n", - " projected_tokens = int(avg_tokens_per_tool * num_tools)\n", - " increase = (\n", - " ((projected_tokens - total_tokens) / total_tokens * 100) if num_tools > 3 else 0\n", - " )\n", - " print(\n", - " f\"{num_tools:<15} {projected_tokens:<15,} {'+' + str(int(increase)) + '%' if increase > 0 else '—':<15}\"\n", - " )\n", - "\n", - "print(\"=\" * 80)\n", - "print(\"\\n🚨 THE PROBLEM:\")\n", - "print(\" - Tool tokens grow linearly with number of tools\")\n", - "print(\" - All tools sent every time, even when not needed\")\n", - "print(\" - At 10 tools: ~4,000 tokens just for tool definitions!\")\n", - "print(\" - At 20 tools: ~8,000 tokens (more than our entire query budget!)\")\n", - "print(\"\\n💡 THE SOLUTION:\")\n", - "print(\" - Semantic tool selection: Only send relevant tools\")\n", - "print(\" - Use embeddings to match query intent to tools\")\n", - "print(\" - Scale capabilities without scaling token costs\")" - ], - "id": "2a9c5ab4f97155ff" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🔀 Part 2: Tool Selection Strategies\n", - "\n", - "Now that we understand the problem, let's explore different solutions.\n", - "\n", - "### **Three Approaches to Tool Selection:**\n", - "\n", - "#### **1. Static/Hardcoded Selection**\n", - "- **What:** Always send all tools to the LLM\n", - "- **How:** No selection logic - bind all tools to agent\n", - "- **Pros:** Simple, predictable, no extra latency\n", - "- **Cons:** Doesn't scale, wasteful for large tool sets\n", - "- **When to use:** ≤3 tools, simple use cases\n", - "\n", - "#### **2. Pre-filtered/Rule-based Selection**\n", - "- **What:** Use keywords or rules to filter tools before LLM\n", - "- **How:** Pattern matching, category tags, if/else logic\n", - "- **Pros:** Fast, deterministic, no embedding costs\n", - "- **Cons:** Brittle, requires maintenance, misses semantic matches\n", - "- **When to use:** Clear categories, stable tool set, 4-7 tools\n", - "\n", - "#### **3. Semantic/Dynamic Selection**\n", - "- **What:** Use embeddings to match query intent to tool purpose\n", - "- **How:** Vector similarity between query and tool descriptions\n", - "- **Pros:** Flexible, scales well, intelligent matching\n", - "- **Cons:** Adds latency (~50-100ms), requires embeddings\n", - "- **When to use:** Many tools (8+), diverse queries, semantic complexity\n" - ], - "id": "629412b60c6d4c2f" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Decision Matrix\n", - "\n", - "Here's how to choose the right strategy:\n" - ], - "id": "8d8a9b61c03354c3" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "print(\"\"\"\n", - "📊 TOOL SELECTION STRATEGY DECISION MATRIX\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "\n", - "# Tools Complexity Query Diversity Best Strategy Rationale\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "1-3 Low Any Static Simple, no overhead\n", - "4-7 Medium Low Pre-filtered Fast, deterministic\n", - "4-7 Medium High Semantic Better accuracy\n", - "8-15 High Any Semantic Required for scale\n", - "16+ Very High Any Semantic + Cache Performance critical\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "\n", - "💡 RULE OF THUMB:\n", - " • ≤3 tools: Just send all tools (static)\n", - " • 4-7 tools: Consider pre-filtered OR semantic\n", - " • 8+ tools: Use semantic selection (required)\n", - "\n", - "🎯 OUR CASE:\n", - " • 5 tools (search_courses, search_memories, store_memory, check_prerequisites, compare_courses)\n", - " • High query diversity (course search, memory, prerequisites, comparisons)\n", - " • → SEMANTIC SELECTION is the best choice\n", - "\"\"\")" - ], - "id": "a17072e01fda5ca2", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Example: Pre-filtered vs Semantic\n", - "\n", - "Let's see the difference with a concrete example:\n" - ], - "id": "ce4eead22dcb1fec" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Example query\n", - "example_query = \"What are the prerequisites for the Redis Streams course?\"\n", - "\n", - "print(f\"Query: '{example_query}'\")\n", - "print(\"\\n\" + \"=\"*70)\n", - "\n", - "# Pre-filtered approach (keyword matching)\n", - "print(\"\\n1️⃣ PRE-FILTERED APPROACH (Keyword Matching):\")\n", - "print(\"-\"*70)\n", - "\n", - "keywords_map = {\n", - " \"search_courses\": [\"course\", \"available\", \"find\", \"recommend\", \"learn\"],\n", - " \"search_memories\": [\"remember\", \"recall\", \"told\", \"said\", \"mentioned\"],\n", - " \"store_memory\": [\"save\", \"remember this\", \"note that\", \"keep in mind\"],\n", - " \"check_prerequisites\": [\"prerequisite\", \"requirement\", \"need to know\", \"before\"],\n", - " \"compare_courses\": [\"compare\", \"difference\", \"versus\", \"vs\", \"better\"]\n", - "}\n", - "\n", - "selected_pre_filtered = []\n", - "query_lower = example_query.lower()\n", - "for tool_name, keywords in keywords_map.items():\n", - " if any(kw in query_lower for kw in keywords):\n", - " selected_pre_filtered.append(tool_name)\n", - "\n", - "print(f\"Selected tools: {selected_pre_filtered}\")\n", - "print(f\"Reasoning: Matched keywords 'prerequisites' and 'course'\")\n", - "\n", - "# Semantic approach (what we'll build)\n", - "print(\"\\n2️⃣ SEMANTIC APPROACH (Embedding Similarity):\")\n", - "print(\"-\"*70)\n", - "print(\"Selected tools: ['check_prerequisites', 'search_courses']\")\n", - "print(\"Reasoning: Query semantically matches 'checking prerequisites' (0.89 similarity)\")\n", - "print(\" and 'searching courses' (0.72 similarity)\")\n", - "\n", - "print(\"\\n\" + \"=\"*70)\n", - "print(\"\"\"\n", - "✅ BOTH APPROACHES WORK for this query!\n", - "\n", - "But semantic selection is more robust:\n", - "• Handles synonyms (\"requirements\" vs \"prerequisites\")\n", - "• Understands intent (\"What do I need to know first?\" → check_prerequisites)\n", - "• No manual keyword maintenance\n", - "• Scales to 100+ tools without rule explosion\n", - "\"\"\")" - ], - "id": "2341488310981cb7" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🆕 Part 3: Adding New Tools\n", - "\n", - "Let's add 2 new tools to expand our agent's capabilities.\n", - "\n", - "### New Tool 1: Check Prerequisites\n" - ], - "id": "fa6c94624453c3f7" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Define the function first\n", - "\n", - "\n", - "async def check_prerequisites_func(course_id: str) -> str:\n", - " \"\"\"Check the prerequisites for a specific course.\"\"\"\n", - " # Simulated prerequisite data (in production, this would query a database)\n", - " prerequisites_db = {\n", - " \"RU101\": {\n", - " \"required\": [],\n", - " \"recommended\": [\"Basic command line knowledge\"],\n", - " \"description\": \"Introduction to Redis - no prerequisites required\",\n", - " },\n", - " \"RU202\": {\n", - " \"required\": [\"RU101\"],\n", - " \"recommended\": [\n", - " \"Basic programming experience\",\n", - " \"Understanding of data structures\",\n", - " ],\n", - " \"description\": \"Redis Streams requires foundational Redis knowledge\",\n", - " },\n", - " \"RU203\": {\n", - " \"required\": [\"RU101\"],\n", - " \"recommended\": [\"RU201 or equivalent data structures knowledge\"],\n", - " \"description\": \"Querying, Indexing, and Full-Text Search\",\n", - " },\n", - " \"RU301\": {\n", - " \"required\": [\"RU101\", \"RU201\"],\n", - " \"recommended\": [\"Experience with time-series data\"],\n", - " \"description\": \"Redis Time Series requires solid Redis foundation\",\n", - " },\n", - " \"RU501\": {\n", - " \"required\": [\"RU101\", \"RU201\"],\n", - " \"recommended\": [\"Python programming\", \"Basic ML concepts\"],\n", - " \"description\": \"Machine Learning with Redis requires programming skills\",\n", - " },\n", - " }\n", - "\n", - " course_id_upper = course_id.upper()\n", - "\n", - " if course_id_upper not in prerequisites_db:\n", - " return f\"Course {course_id} not found. Available courses: {', '.join(prerequisites_db.keys())}\"\n", - "\n", - " prereqs = prerequisites_db[course_id_upper]\n", - "\n", - " output = []\n", - " output.append(f\"📋 Prerequisites for {course_id_upper}:\")\n", - " output.append(f\"\\n{prereqs['description']}\\n\")\n", - "\n", - " if prereqs[\"required\"]:\n", - " output.append(\"✅ Required Courses:\")\n", - " for req in prereqs[\"required\"]:\n", - " output.append(f\" • {req}\")\n", - " else:\n", - " output.append(\"✅ No required prerequisites\")\n", - "\n", - " if prereqs[\"recommended\"]:\n", - " output.append(\"\\n💡 Recommended Background:\")\n", - " for rec in prereqs[\"recommended\"]:\n", - " output.append(f\" • {rec}\")\n", - "\n", - " return \"\\n\".join(output)\n", - "\n", - "\n", - "# Create the tool using StructuredTool\n", - "from langchain_core.tools import StructuredTool\n", - "\n", - "check_prerequisites = StructuredTool.from_function(\n", - " coroutine=check_prerequisites_func,\n", - " name=\"check_prerequisites\",\n", - " description=\"\"\"Check the prerequisites for a specific course.\n", - "\n", - "Use this when students ask:\n", - "- \"What are the prerequisites for RU202?\"\n", - "- \"Do I need to take anything before this course?\"\n", - "- \"What should I learn first?\"\n", - "- \"Am I ready for this course?\"\n", - "\n", - "Returns: List of prerequisite courses and recommended background knowledge.\"\"\",\n", - ")\n", - "\n", - "print(\"✅ New Tool 1: check_prerequisites\")\n", - "print(\" Use case: Help students understand course requirements\")" - ], - "id": "641c53f9d3ebcc", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### New Tool 2: Compare Courses\n", - "id": "f67eabfcae3d1d4d" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Define the function first\n", - "\n", - "\n", - "async def compare_courses_func(course_ids: List[str]) -> str:\n", - " \"\"\"Compare multiple courses side-by-side to help students choose.\"\"\"\n", - " if len(course_ids) < 2:\n", - " return \"Please provide at least 2 courses to compare.\"\n", - "\n", - " if len(course_ids) > 3:\n", - " return \"Please limit comparison to 3 courses maximum.\"\n", - "\n", - " # Simulated course data (in production, this would query the course catalog)\n", - " course_db = {\n", - " \"RU101\": {\n", - " \"title\": \"Introduction to Redis Data Structures\",\n", - " \"level\": \"Beginner\",\n", - " \"duration\": \"2 hours\",\n", - " \"format\": \"Online, self-paced\",\n", - " \"focus\": \"Core Redis data structures and commands\",\n", - " \"language\": \"Language-agnostic\",\n", - " },\n", - " \"RU102JS\": {\n", - " \"title\": \"Redis for JavaScript Developers\",\n", - " \"level\": \"Beginner\",\n", - " \"duration\": \"3 hours\",\n", - " \"format\": \"Online, self-paced\",\n", - " \"focus\": \"Using Redis with Node.js applications\",\n", - " \"language\": \"JavaScript/Node.js\",\n", - " },\n", - " \"RU201\": {\n", - " \"title\": \"RediSearch\",\n", - " \"level\": \"Intermediate\",\n", - " \"duration\": \"4 hours\",\n", - " \"format\": \"Online, self-paced\",\n", - " \"focus\": \"Full-text search and secondary indexing\",\n", - " \"language\": \"Language-agnostic\",\n", - " },\n", - " \"RU202\": {\n", - " \"title\": \"Redis Streams\",\n", - " \"level\": \"Intermediate\",\n", - " \"duration\": \"3 hours\",\n", - " \"format\": \"Online, self-paced\",\n", - " \"focus\": \"Stream processing and consumer groups\",\n", - " \"language\": \"Language-agnostic\",\n", - " },\n", - " }\n", - "\n", - " # Get course data\n", - " courses_data = []\n", - " for course_id in course_ids:\n", - " course_id_upper = course_id.upper()\n", - " if course_id_upper in course_db:\n", - " courses_data.append((course_id_upper, course_db[course_id_upper]))\n", - " else:\n", - " return f\"Course {course_id} not found.\"\n", - "\n", - " # Build comparison table\n", - " output = []\n", - " output.append(\"=\" * 80)\n", - " output.append(f\"📊 COURSE COMPARISON: {' vs '.join([c[0] for c in courses_data])}\")\n", - " output.append(\"=\" * 80)\n", - "\n", - " # Compare each attribute\n", - " attributes = [\"title\", \"level\", \"duration\", \"format\", \"focus\", \"language\"]\n", - "\n", - " for attr in attributes:\n", - " output.append(f\"\\n{attr.upper()}:\")\n", - " for course_id, data in courses_data:\n", - " output.append(f\" {course_id}: {data[attr]}\")\n", - "\n", - " output.append(\"\\n\" + \"=\" * 80)\n", - " output.append(\n", - " \"💡 Recommendation: Choose based on your experience level and learning goals.\"\n", - " )\n", - "\n", - " return \"\\n\".join(output)\n", - "\n", - "\n", - "# Create the tool using StructuredTool\n", - "compare_courses = StructuredTool.from_function(\n", - " coroutine=compare_courses_func,\n", - " name=\"compare_courses\",\n", - " description=\"\"\"Compare multiple courses side-by-side to help students choose.\n", - "\n", - "Use this when students ask:\n", - "- \"What's the difference between RU101 and RU102JS?\"\n", - "- \"Should I take RU201 or RU202 first?\"\n", - "- \"Compare these courses for me\"\n", - "- \"Which course is better for beginners?\"\n", - "\n", - "Returns: Side-by-side comparison of courses with key differences highlighted.\"\"\",\n", - ")\n", - "\n", - "print(\"✅ New Tool 2: compare_courses\")\n", - "print(\" Use case: Help students choose between similar courses\")" - ], - "id": "c05aa339438e9e0c" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Collect all 5 tools\n", - "all_tools = [\n", - " search_courses_hybrid,\n", - " search_memories,\n", - " store_memory,\n", - " check_prerequisites,\n", - " compare_courses,\n", - "]\n", - "\n", - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"🛠️ ALL TOOLS (5 total)\")\n", - "print(\"=\" * 80)\n", - "for i, tool in enumerate(all_tools, 1):\n", - " tokens = get_tool_token_cost(tool)\n", - " print(f\"{i}. {tool.name:<30} {tokens:>6} tokens\")\n", - "\n", - "total_all_tools = sum(get_tool_token_cost(t) for t in all_tools)\n", - "print(\"-\" * 80)\n", - "print(f\"{'TOTAL (5 tools)':<30} {total_all_tools:>6} tokens\")\n", - "print(\"=\" * 80)\n", - "\n", - "print(f\"\\n📊 Comparison:\")\n", - "print(f\" 3 tools: {total_tokens:,} tokens\")\n", - "print(f\" 5 tools: {total_all_tools:,} tokens\")\n", - "print(\n", - " f\" Increase: +{total_all_tools - total_tokens:,} tokens (+{(total_all_tools - total_tokens) / total_tokens * 100:.0f}%)\"\n", - ")\n", - "print(\n", - " f\"\\n🚨 Problem: We just added {total_all_tools - total_tokens:,} tokens to EVERY query!\"\n", - ")" - ], - "id": "4c7088587e5bee15", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🎯 Part 4: Semantic Tool Selection with RedisVL\n", - "\n", - "Now let's implement semantic tool selection to solve the scaling problem.\n", - "\n", - "### 🔬 Theory: Semantic Tool Selection\n", - "\n", - "**The Idea:**\n", - "Instead of sending all tools to the LLM, we:\n", - "1. **Embed tool descriptions** - Create vector embeddings for each tool\n", - "2. **Embed user query** - Create vector embedding for the user's question\n", - "3. **Find similar tools** - Use cosine similarity to find relevant tools\n", - "4. **Send only relevant tools** - Only include top-k most relevant tools\n", - "\n", - "**Example:**\n", - "\n", - "```\n", - "User Query: \"What are the prerequisites for RU202?\"\n", - "\n", - "Step 1: Embed query → [0.23, -0.45, 0.67, ...]\n", - "\n", - "Step 2: Compare to tool embeddings:\n", - " check_prerequisites: similarity = 0.92 ✅\n", - " search_courses_hybrid: similarity = 0.45\n", - " compare_courses: similarity = 0.38\n", - " search_memories: similarity = 0.12\n", - " store_memory: similarity = 0.08\n", - "\n", - "Step 3: Select top 2 tools:\n", - " → check_prerequisites\n", - " → search_courses_hybrid\n", - "\n", - "Step 4: Send only these 2 tools to LLM (instead of all 5)\n", - "```\n", - "\n", - "**Benefits:**\n", - "- ✅ Constant token cost (always send top-k tools)\n", - "- ✅ Better tool selection (semantically relevant)\n", - "- ✅ Scales to 100+ tools without token explosion\n", - "- ✅ Faster inference (fewer tools = faster LLM processing)\n", - "\n", - "**💡 Key Insight:** Semantic similarity enables intelligent tool selection at scale.\n" - ], - "id": "fa2f293a4b328d96" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Step 1: Create Tool Metadata\n", - "\n", - "First, let's create rich metadata for each tool to improve embedding quality.\n" - ], - "id": "8b52619d67c9c18f" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "@dataclass\n", - "class ToolMetadata:\n", - " \"\"\"Metadata for a tool to enable semantic selection.\"\"\"\n", - "\n", - " name: str\n", - " description: str\n", - " use_cases: List[str]\n", - " keywords: List[str]\n", - " tool_obj: Any # The actual tool object\n", - "\n", - " def get_embedding_text(self) -> str:\n", - " \"\"\"\n", - " Create rich text representation for embedding.\n", - "\n", - " This combines all metadata into a single text that captures\n", - " the tool's purpose, use cases, and keywords.\n", - " \"\"\"\n", - " parts = [\n", - " f\"Tool: {self.name}\",\n", - " f\"Description: {self.description}\",\n", - " f\"Use cases: {', '.join(self.use_cases)}\",\n", - " f\"Keywords: {', '.join(self.keywords)}\",\n", - " ]\n", - " return \"\\n\".join(parts)\n", - "\n", - "\n", - "print(\"✅ ToolMetadata dataclass defined\")" - ], - "id": "c564db7df0a0fef" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Create metadata for all 5 tools\n", - "tool_metadata_list = [\n", - " ToolMetadata(\n", - " name=\"search_courses_hybrid\",\n", - " description=\"Search for courses using hybrid retrieval (overview + targeted search)\",\n", - " use_cases=[\n", - " \"Find courses by topic or subject\",\n", - " \"Explore available courses\",\n", - " \"Get course recommendations\",\n", - " \"Search for specific course types\",\n", - " ],\n", - " keywords=[\n", - " \"search\",\n", - " \"find\",\n", - " \"courses\",\n", - " \"available\",\n", - " \"topics\",\n", - " \"subjects\",\n", - " \"catalog\",\n", - " \"browse\",\n", - " ],\n", - " tool_obj=search_courses_hybrid,\n", - " ),\n", - " ToolMetadata(\n", - " name=\"search_memories\",\n", - " description=\"Search user's long-term memory for preferences and past interactions\",\n", - " use_cases=[\n", - " \"Recall user preferences\",\n", - " \"Remember past goals\",\n", - " \"Personalize recommendations\",\n", - " \"Check user history\",\n", - " ],\n", - " keywords=[\n", - " \"remember\",\n", - " \"recall\",\n", - " \"preference\",\n", - " \"history\",\n", - " \"past\",\n", - " \"previous\",\n", - " \"memory\",\n", - " ],\n", - " tool_obj=search_memories,\n", - " ),\n", - " ToolMetadata(\n", - " name=\"store_memory\",\n", - " description=\"Store important information to user's long-term memory\",\n", - " use_cases=[\n", - " \"Save user preferences\",\n", - " \"Remember user goals\",\n", - " \"Store important facts\",\n", - " \"Record constraints\",\n", - " ],\n", - " keywords=[\n", - " \"save\",\n", - " \"store\",\n", - " \"remember\",\n", - " \"record\",\n", - " \"preference\",\n", - " \"goal\",\n", - " \"constraint\",\n", - " ],\n", - " tool_obj=store_memory,\n", - " ),\n", - " ToolMetadata(\n", - " name=\"check_prerequisites\",\n", - " description=\"Check prerequisites and requirements for a specific course\",\n", - " use_cases=[\n", - " \"Check course prerequisites\",\n", - " \"Verify readiness for a course\",\n", - " \"Understand course requirements\",\n", - " \"Find what to learn first\",\n", - " ],\n", - " keywords=[\n", - " \"prerequisites\",\n", - " \"requirements\",\n", - " \"ready\",\n", - " \"before\",\n", - " \"first\",\n", - " \"needed\",\n", - " \"required\",\n", - " ],\n", - " tool_obj=check_prerequisites,\n", - " ),\n", - " ToolMetadata(\n", - " name=\"compare_courses\",\n", - " description=\"Compare multiple courses side-by-side to help choose between them\",\n", - " use_cases=[\n", - " \"Compare course options\",\n", - " \"Understand differences between courses\",\n", - " \"Choose between similar courses\",\n", - " \"Evaluate course alternatives\",\n", - " ],\n", - " keywords=[\n", - " \"compare\",\n", - " \"difference\",\n", - " \"versus\",\n", - " \"vs\",\n", - " \"between\",\n", - " \"choose\",\n", - " \"which\",\n", - " \"better\",\n", - " ],\n", - " tool_obj=compare_courses,\n", - " ),\n", - "]\n", - "\n", - "print(\"✅ Tool metadata created for all 5 tools\")\n", - "print(\"\\nExample metadata:\")\n", - "print(f\" Tool: {tool_metadata_list[3].name}\")\n", - "print(f\" Use cases: {len(tool_metadata_list[3].use_cases)}\")\n", - "print(f\" Keywords: {len(tool_metadata_list[3].keywords)}\")" - ], - "id": "dc77ab4d3a8fbe84", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Step 2: Build Semantic Router with RedisVL\n", - "\n", - "Instead of building a custom tool selector from scratch, we'll use **RedisVL's Semantic Router** - a production-ready solution for semantic routing.\n", - "\n", - "#### 🎓 What is Semantic Router?\n", - "\n", - "**Semantic Router** is a RedisVL extension that provides KNN-style classification over a set of \"routes\" (in our case, tools). It automatically:\n", - "- Creates and manages Redis vector index\n", - "- Generates embeddings for route references\n", - "- Performs semantic similarity search\n", - "- Returns best matching route(s) with distance scores\n", - "- Supports serialization (YAML/dict) for configuration management\n", - "\n", - "#### 🔑 Why This Matters for Context Engineering\n", - "\n", - "**Context engineering is about managing what information reaches the LLM**. Semantic Router helps by:\n", - "\n", - "1. **Intelligent Tool Selection** - Only relevant tools are included in the context\n", - "2. **Constant Token Overhead** - Top-k selection means predictable context size\n", - "3. **Semantic Understanding** - Matches query intent to tool purpose using embeddings\n", - "4. **Production Patterns** - Learn industry-standard approaches, not custom implementations\n", - "\n", - "**Key Concept**: Routes are like \"semantic buckets\" - each route (tool) has reference examples that define when it should be selected.\n" - ], - "id": "eea0a219477cb649" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Create routes for each tool\n", - "# Each route has:\n", - "# - name: Tool identifier\n", - "# - references: Example use cases that define when this tool should be selected\n", - "# - metadata: Store the actual tool object for later retrieval\n", - "# - distance_threshold: How similar a query must be to match this route\n", - "\n", - "print(\"🔨 Creating semantic routes for tools...\")\n", - "\n", - "search_courses_route = Route(\n", - " name=\"search_courses_hybrid\",\n", - " references=[\n", - " \"Find courses by topic or subject\",\n", - " \"Explore available courses\",\n", - " \"Get course recommendations\",\n", - " \"Search for specific course types\",\n", - " \"What courses are available?\",\n", - " \"Show me machine learning courses\",\n", - " \"Browse the course catalog\",\n", - " ],\n", - " metadata={\"category\": \"course_discovery\"},\n", - " distance_threshold=0.3, # Lower = more strict matching\n", - ")\n", - "\n", - "search_memories_route = Route(\n", - " name=\"search_memories\",\n", - " references=[\n", - " \"Recall user preferences\",\n", - " \"Remember past goals\",\n", - " \"Personalize recommendations based on history\",\n", - " \"Check user history\",\n", - " \"What format does the user prefer?\",\n", - " \"What did I say about my learning goals?\",\n", - " \"Remember my preferences\",\n", - " ],\n", - " metadata={\"category\": \"personalization\"},\n", - " distance_threshold=0.3,\n", - ")\n", - "\n", - "store_memory_route = Route(\n", - " name=\"store_memory\",\n", - " references=[\n", - " \"Save user preferences\",\n", - " \"Remember user goals\",\n", - " \"Store important facts\",\n", - " \"Record constraints\",\n", - " \"Remember that I prefer online courses\",\n", - " \"Save my learning goal\",\n", - " \"Keep track of my interests\",\n", - " ],\n", - " metadata={\"category\": \"personalization\"},\n", - " distance_threshold=0.3,\n", - ")\n", - "\n", - "check_prerequisites_route = Route(\n", - " name=\"check_prerequisites\",\n", - " references=[\n", - " \"Check course prerequisites\",\n", - " \"Verify readiness for a course\",\n", - " \"Understand course requirements\",\n", - " \"Find what to learn first\",\n", - " \"What do I need before taking this course?\",\n", - " \"Am I ready for RU202?\",\n", - " \"What are the requirements?\",\n", - " ],\n", - " metadata={\"category\": \"course_planning\"},\n", - " distance_threshold=0.3,\n", - ")\n", - "\n", - "compare_courses_route = Route(\n", - " name=\"compare_courses\",\n", - " references=[\n", - " \"Compare course options\",\n", - " \"Understand differences between courses\",\n", - " \"Choose between similar courses\",\n", - " \"Evaluate course alternatives\",\n", - " \"What's the difference between RU101 and RU102?\",\n", - " \"Which course is better for beginners?\",\n", - " \"Compare these two courses\",\n", - " ],\n", - " metadata={\"category\": \"course_planning\"},\n", - " distance_threshold=0.3,\n", - ")\n", - "\n", - "print(\"✅ Created 5 semantic routes\")\n", - "print(\"\\nExample route:\")\n", - "print(f\" Name: {check_prerequisites_route.name}\")\n", - "print(f\" References: {len(check_prerequisites_route.references)} examples\")\n", - "print(f\" Distance threshold: {check_prerequisites_route.distance_threshold}\")" - ], - "id": "689d8b93a1eda3d5", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "#### 🎓 Understanding Routes vs Custom Implementation\n", - "\n", - "**What We're NOT Doing** (Custom Approach):\n", - "```python\n", - "# ❌ Manual index schema definition\n", - "tool_index_schema = {\"index\": {...}, \"fields\": [...]}\n", - "\n", - "# ❌ Manual embedding generation\n", - "embedding_vector = await embeddings.aembed_query(text)\n", - "\n", - "# ❌ Manual storage\n", - "tool_index.load([tool_data], keys=[...])\n", - "\n", - "# ❌ Custom selector class\n", - "class SemanticToolSelector:\n", - " def __init__(self, tool_index, embeddings, ...):\n", - " # ~100 lines of custom code\n", - "```\n", - "\n", - "**What We ARE Doing** (RedisVL Semantic Router):\n", - "```python\n", - "# ✅ Define routes with references\n", - "route = Route(name=\"tool_name\", references=[...])\n", - "\n", - "# ✅ Initialize router (handles everything automatically)\n", - "router = SemanticRouter(routes=[...])\n", - "\n", - "# ✅ Select tools (one line!)\n", - "matches = router.route_many(query, max_k=3)\n", - "```\n", - "\n", - "**Result**: 60% less code, production-ready patterns, easier to maintain.\n" - ], - "id": "693bb3a5927ab86e" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Initialize the Semantic Router\n", - "# This automatically:\n", - "# 1. Creates Redis vector index for route references\n", - "# 2. Generates embeddings for all references\n", - "# 3. Stores embeddings in Redis\n", - "# 4. Provides simple API for routing queries\n", - "\n", - "print(\"🔨 Initializing Semantic Router...\")\n", - "\n", - "tool_router = SemanticRouter(\n", - " name=\"course-advisor-tool-router\",\n", - " routes=[\n", - " search_courses_route,\n", - " search_memories_route,\n", - " store_memory_route,\n", - " check_prerequisites_route,\n", - " compare_courses_route,\n", - " ],\n", - " redis_url=REDIS_URL,\n", - " overwrite=True, # Recreate index if it exists\n", - ")\n", - "\n", - "print(\"✅ Semantic Router initialized\")\n", - "print(f\" Router name: {tool_router.name}\")\n", - "print(f\" Routes: {len(tool_router.routes)}\")\n", - "print(f\" Index created: course-advisor-tool-router\")\n", - "print(\n", - " \"\\n💡 The router automatically created the Redis index and stored all embeddings!\"\n", - ")" - ], - "id": "d8f156346d3545a5" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Step 3: Test Semantic Tool Routing\n", - "\n", - "Let's test how the router selects tools based on query semantics.\n" - ], - "id": "ff67e322435bb2e3" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "async def test_tool_routing(query: str, max_k: int = 3):\n", - " \"\"\"\n", - " Test semantic tool routing for a given query.\n", - "\n", - " This demonstrates how the router:\n", - " 1. Embeds the query\n", - " 2. Compares to all route references\n", - " 3. Returns top-k most similar routes (tools)\n", - " \"\"\"\n", - " print(\"=\" * 80)\n", - " print(f\"🔍 QUERY: {query}\")\n", - " print(\"=\" * 80)\n", - "\n", - " # Get top-k route matches\n", - " # route_many() returns multiple routes ranked by similarity\n", - " route_matches = tool_router.route_many(query, max_k=max_k)\n", - "\n", - " print(f\"\\n📊 Top {max_k} Tool Matches:\")\n", - " print(f\"{'Rank':<6} {'Tool Name':<30} {'Distance':<12} {'Similarity':<12}\")\n", - " print(\"-\" * 80)\n", - "\n", - " for i, match in enumerate(route_matches, 1):\n", - " # Distance: 0.0 = perfect match, 1.0 = completely different\n", - " # Similarity: 1.0 = perfect match, 0.0 = completely different\n", - " similarity = 1.0 - match.distance\n", - " print(f\"{i:<6} {match.name:<30} {match.distance:<12.3f} {similarity:<12.3f}\")\n", - "\n", - " # Map route names to tool objects\n", - " tool_map = {\n", - " \"search_courses_hybrid\": search_courses_hybrid,\n", - " \"search_memories\": search_memories,\n", - " \"store_memory\": store_memory,\n", - " \"check_prerequisites\": check_prerequisites,\n", - " \"compare_courses\": compare_courses,\n", - " }\n", - "\n", - " # Get the actual tool objects by name\n", - " selected_tools = [\n", - " tool_map[match.name] for match in route_matches if match.name in tool_map\n", - " ]\n", - "\n", - " print(f\"\\n✅ Selected {len(selected_tools)} tools for this query\")\n", - " print(f\" Tools: {', '.join([match.name for match in route_matches])}\")\n", - "\n", - " return route_matches, selected_tools\n", - "\n", - "\n", - "print(\"✅ Tool routing test function defined\")" - ], - "id": "a890b7e7981e8f1c" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Step 4: Run Tool Routing Tests\n", - "\n", - "Let's test the router with different types of queries to see how it intelligently selects tools.\n", - "\n", - "#### 🎓 Understanding the Results\n", - "\n", - "For each query, the router:\n", - "1. **Embeds the query** using the same embedding model\n", - "2. **Compares to all route references** (the example use cases we defined)\n", - "3. **Calculates semantic similarity** (distance scores)\n", - "4. **Returns top-k most relevant tools**\n", - "\n", - "**Key Observations:**\n", - "- **Distance scores**: Lower = better match (0.0 = perfect, 1.0 = completely different)\n", - "- **Similarity scores**: Higher = better match (1.0 = perfect, 0.0 = completely different)\n", - "- **Intelligent selection**: The router correctly identifies which tools are relevant for each query\n" - ], - "id": "6d5c114daa3034e" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Test 1: Prerequisites query\n", - "print(\"🧪 Test 1: Prerequisites Query\\n\")\n", - "await test_tool_routing(\"What are the prerequisites for RU202?\", max_k=3)" - ], - "id": "895b0be719fabd60", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Test 2: Course search query\n", - "print(\"\\n🧪 Test 2: Course Search Query\\n\")\n", - "await test_tool_routing(\"What machine learning courses are available?\", max_k=3)" - ], - "id": "18db3f727daa20c0", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Test 3: Comparison query\n", - "print(\"\\n🧪 Test 3: Course Comparison Query\\n\")\n", - "await test_tool_routing(\"What's the difference between RU101 and RU102JS?\", max_k=3)" - ], - "id": "4cc199ace8346100", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Test 4: Memory/preference query\n", - "print(\"\\n🧪 Test 4: Memory Storage Query\\n\")\n", - "await test_tool_routing(\"I prefer online courses and I'm interested in AI\", max_k=3)" - ], - "id": "aaa84414aae72403", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Test 5: Memory recall query\n", - "print(\"\\n🧪 Test 5: Memory Recall Query\\n\")\n", - "await test_tool_routing(\"What did I say about my learning preferences?\", max_k=3)" - ], - "id": "9b9dec756575c685", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Analysis: Tool Selection Accuracy\n", - "id": "b19acf1c54229753" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "print(\"=\" * 80)\n", - "print(\"📊 TOOL SELECTION ANALYSIS\")\n", - "print(\"=\" * 80)\n", - "\n", - "test_cases = [\n", - " {\n", - " \"query\": \"What are the prerequisites for RU202?\",\n", - " \"expected_top_tool\": \"check_prerequisites\",\n", - " \"description\": \"Prerequisites query\",\n", - " },\n", - " {\n", - " \"query\": \"What machine learning courses are available?\",\n", - " \"expected_top_tool\": \"search_courses_hybrid\",\n", - " \"description\": \"Course search query\",\n", - " },\n", - " {\n", - " \"query\": \"What's the difference between RU101 and RU102JS?\",\n", - " \"expected_top_tool\": \"compare_courses\",\n", - " \"description\": \"Comparison query\",\n", - " },\n", - " {\n", - " \"query\": \"I prefer online courses\",\n", - " \"expected_top_tool\": \"store_memory\",\n", - " \"description\": \"Preference statement\",\n", - " },\n", - "]\n", - "\n", - "print(\"\\nTest Results:\")\n", - "print(f\"{'Query Type':<25} {'Expected':<25} {'Actual':<25} {'Match':<10}\")\n", - "print(\"-\" * 80)\n", - "\n", - "correct = 0\n", - "total = len(test_cases)\n", - "\n", - "# Map route names to tool objects\n", - "tool_map = {\n", - " \"search_courses_hybrid\": search_courses_hybrid,\n", - " \"search_memories\": search_memories,\n", - " \"store_memory\": store_memory,\n", - " \"check_prerequisites\": check_prerequisites,\n", - " \"compare_courses\": compare_courses,\n", - "}\n", - "\n", - "for test in test_cases:\n", - " # Use tool_router to get top match\n", - " route_matches = tool_router.route_many(test[\"query\"], max_k=1)\n", - " actual_tool = route_matches[0].name if route_matches else \"none\"\n", - " match = \"✅ YES\" if actual_tool == test[\"expected_top_tool\"] else \"❌ NO\"\n", - " if actual_tool == test[\"expected_top_tool\"]:\n", - " correct += 1\n", - "\n", - " print(\n", - " f\"{test['description']:<25} {test['expected_top_tool']:<25} {actual_tool:<25} {match:<10}\"\n", - " )\n", - "\n", - "accuracy = (correct / total * 100) if total > 0 else 0\n", - "print(\"-\" * 80)\n", - "print(f\"Accuracy: {correct}/{total} ({accuracy:.0f}%)\")\n", - "print(\"=\" * 80)\n", - "\n", - "print(f\"\\n✅ Semantic tool selection achieves ~{accuracy:.0f}% accuracy\")\n", - "print(\" This is significantly better than random selection (20%)\")" - ], - "id": "353263d94616b811" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🤖 Part 5: Enhanced Agent with Semantic Tool Selection\n", - "\n", - "Now let's build an agent that uses semantic tool selection.\n", - "\n", - "### AgentState with Tool Selection\n" - ], - "id": "b84f217a05e705bb" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "class AgentState(BaseModel):\n", - " \"\"\"State for the course advisor agent with tool selection.\"\"\"\n", - "\n", - " messages: Annotated[List[BaseMessage], add_messages]\n", - " student_id: str\n", - " session_id: str\n", - " context: Dict[str, Any] = {}\n", - " selected_tools: List[Any] = [] # NEW: Store selected tools\n", - "\n", - "\n", - "print(\"✅ AgentState defined with selected_tools field\")" - ], - "id": "e8ae76577b0a8c3c" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Build Enhanced Agent Workflow\n", - "id": "d5501fdc2b20e25c" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Node 1: Load memory (same as before)\n", - "\n", - "\n", - "async def load_memory(state: AgentState) -> AgentState:\n", - " \"\"\"Load conversation history from working memory.\"\"\"\n", - " try:\n", - " from agent_memory_client.filters import SessionId\n", - "\n", - " _, working_memory = await memory_client.get_or_create_working_memory(\n", - " user_id=UserId(eq=state.student_id),\n", - " session_id=SessionId(eq=state.session_id),\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " if working_memory and working_memory.messages:\n", - " state.context[\"working_memory_loaded\"] = True\n", - " except Exception as e:\n", - " state.context[\"working_memory_error\"] = str(e)\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 1: load_memory\")" - ], - "id": "b2c5ae05ede43e52", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Node 2: Select tools (NEW!)\n", - "\n", - "\n", - "async def select_tools_node(state: AgentState) -> AgentState:\n", - " \"\"\"Select relevant tools based on the user's query.\"\"\"\n", - " # Get the latest user message\n", - " user_messages = [msg for msg in state.messages if isinstance(msg, HumanMessage)]\n", - " if not user_messages:\n", - " # No user message yet, use all tools\n", - " state.selected_tools = all_tools\n", - " state.context[\"tool_selection\"] = \"all (no query)\"\n", - " return state\n", - "\n", - " latest_query = user_messages[-1].content\n", - "\n", - " # Use semantic tool router\n", - " route_matches = tool_router.route_many(latest_query, max_k=3)\n", - "\n", - " # Map route names to tool objects\n", - " tool_map = {\n", - " \"search_courses_hybrid\": search_courses_hybrid,\n", - " \"search_memories\": search_memories,\n", - " \"store_memory\": store_memory,\n", - " \"check_prerequisites\": check_prerequisites,\n", - " \"compare_courses\": compare_courses,\n", - " }\n", - "\n", - " selected_tools = [\n", - " tool_map[match.name] for match in route_matches if match.name in tool_map\n", - " ]\n", - " state.selected_tools = selected_tools\n", - " state.context[\"tool_selection\"] = \"semantic\"\n", - " state.context[\"selected_tool_names\"] = [t.name for t in selected_tools]\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 2: select_tools_node (NEW)\")" - ], - "id": "67157e0234ef44c5", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Node 3: Agent with dynamic tools\n", - "\n", - "\n", - "async def enhanced_agent_node(state: AgentState) -> AgentState:\n", - " \"\"\"The agent with dynamically selected tools.\"\"\"\n", - " system_message = SystemMessage(\n", - " content=\"\"\"\n", - "You are a helpful Redis University course advisor assistant.\n", - "\n", - "Your role:\n", - "- Help students find courses that match their interests and goals\n", - "- Check prerequisites and compare courses\n", - "- Remember student preferences and use them for personalized recommendations\n", - "- Store important information about students for future conversations\n", - "\n", - "Guidelines:\n", - "- Use the available tools to help students\n", - "- Be conversational and helpful\n", - "- Provide specific course recommendations with details\n", - "\"\"\"\n", - " )\n", - "\n", - " # Bind ONLY the selected tools to LLM\n", - " llm_with_tools = llm.bind_tools(state.selected_tools)\n", - "\n", - " # Call LLM\n", - " messages = [system_message] + state.messages\n", - " response = await llm_with_tools.ainvoke(messages)\n", - "\n", - " state.messages.append(response)\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 3: enhanced_agent_node\")" - ], - "id": "191e1374d09e7d8", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Node 4: Save memory (same as before)\n", - "\n", - "\n", - "async def save_memory(state: AgentState) -> AgentState:\n", - " \"\"\"Save updated conversation to working memory.\"\"\"\n", - " try:\n", - " from agent_memory_client.filters import SessionId\n", - "\n", - " await memory_client.put_working_memory(\n", - " user_id=state.student_id,\n", - " session_id=state.session_id,\n", - " memory=working_memory,\n", - " model_name=\"gpt-4o\",\n", - " )\n", - "\n", - " state.context[\"working_memory_saved\"] = True\n", - " except Exception as e:\n", - " state.context[\"save_error\"] = str(e)\n", - "\n", - " return state\n", - "\n", - "\n", - "print(\"✅ Node 4: save_memory\")" - ], - "id": "b257d38b5f2d575", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Routing logic\n", - "\n", - "\n", - "def should_continue(state: AgentState) -> str:\n", - " \"\"\"Determine if we should continue to tools or end.\"\"\"\n", - " last_message = state.messages[-1]\n", - "\n", - " if hasattr(last_message, \"tool_calls\") and last_message.tool_calls:\n", - " return \"tools\"\n", - "\n", - " return \"save_memory\"\n", - "\n", - "\n", - "print(\"✅ Routing: should_continue\")" - ], - "id": "b5272a2124590695", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "# Build the enhanced agent graph\n", - "enhanced_workflow = StateGraph(AgentState)\n", - "\n", - "# Add nodes\n", - "enhanced_workflow.add_node(\"load_memory\", load_memory)\n", - "enhanced_workflow.add_node(\"select_tools\", select_tools_node) # NEW NODE\n", - "enhanced_workflow.add_node(\"agent\", enhanced_agent_node)\n", - "enhanced_workflow.add_node(\n", - " \"tools\", lambda state: state\n", - ") # Placeholder, will use ToolNode dynamically\n", - "enhanced_workflow.add_node(\"save_memory\", save_memory)\n", - "\n", - "# Define edges\n", - "enhanced_workflow.set_entry_point(\"load_memory\")\n", - "enhanced_workflow.add_edge(\"load_memory\", \"select_tools\") # NEW: Select tools first\n", - "enhanced_workflow.add_edge(\"select_tools\", \"agent\")\n", - "enhanced_workflow.add_conditional_edges(\n", - " \"agent\", should_continue, {\"tools\": \"tools\", \"save_memory\": \"save_memory\"}\n", - ")\n", - "enhanced_workflow.add_edge(\"tools\", \"agent\")\n", - "enhanced_workflow.add_edge(\"save_memory\", END)\n", - "\n", - "# Note: We'll need to handle tool execution dynamically\n", - "# For now, compile the graph\n", - "enhanced_agent = enhanced_workflow.compile()\n", - "\n", - "print(\"✅ Enhanced agent graph compiled\")\n", - "print(\" New workflow: load_memory → select_tools → agent → tools → save_memory\")" - ], - "id": "b70eaceb75ecdb65", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Run Enhanced Agent with Metrics\n", - "id": "d9bec881195cdfbf" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "@dataclass\n", - "class EnhancedMetrics:\n", - " \"\"\"Track metrics for enhanced agent with tool selection.\"\"\"\n", - "\n", - " query: str\n", - " response: str\n", - " total_tokens: int\n", - " tool_tokens_all: int\n", - " tool_tokens_selected: int\n", - " tool_savings: int\n", - " selected_tools: List[str]\n", - " latency_seconds: float\n", - "\n", - "\n", - "async def run_enhanced_agent_with_metrics(user_message: str) -> EnhancedMetrics:\n", - " \"\"\"Run the enhanced agent and track metrics.\"\"\"\n", - " print(\"=\" * 80)\n", - " print(f\"👤 USER: {user_message}\")\n", - " print(\"=\" * 80)\n", - "\n", - " start_time = time.time()\n", - "\n", - " # Select tools using semantic router\n", - " route_matches = tool_router.route_many(user_message, max_k=3)\n", - "\n", - " # Map route names to tool objects\n", - " tool_map = {\n", - " \"search_courses_hybrid\": search_courses_hybrid,\n", - " \"search_memories\": search_memories,\n", - " \"store_memory\": store_memory,\n", - " \"check_prerequisites\": check_prerequisites,\n", - " \"compare_courses\": compare_courses,\n", - " }\n", - "\n", - " selected_tools = [\n", - " tool_map[match.name] for match in route_matches if match.name in tool_map\n", - " ]\n", - " selected_tool_names = [t.name for t in selected_tools]\n", - "\n", - " print(f\"\\n🎯 Selected tools: {', '.join(selected_tool_names)}\")\n", - "\n", - " # Create initial state\n", - " initial_state = AgentState(\n", - " messages=[HumanMessage(content=user_message)],\n", - " student_id=STUDENT_ID,\n", - " session_id=SESSION_ID,\n", - " context={},\n", - " selected_tools=selected_tools,\n", - " )\n", - "\n", - " # Run agent with selected tools\n", - " llm_with_selected_tools = llm.bind_tools(selected_tools)\n", - " system_message = SystemMessage(\n", - " content=\"You are a helpful Redis University course advisor.\"\n", - " )\n", - "\n", - " messages = [system_message, HumanMessage(content=user_message)]\n", - " response = await llm_with_selected_tools.ainvoke(messages)\n", - "\n", - " end_time = time.time()\n", - "\n", - " # Calculate metrics\n", - " response_text = response.content if hasattr(response, \"content\") else str(response)\n", - " total_tokens = count_tokens(user_message) + count_tokens(response_text)\n", - "\n", - " tool_tokens_all = sum(\n", - " get_tool_token_cost(meta.tool_obj) for meta in tool_metadata_list\n", - " )\n", - " tool_tokens_selected = sum(get_tool_token_cost(t) for t in selected_tools)\n", - " tool_savings = tool_tokens_all - tool_tokens_selected\n", - "\n", - " metrics = EnhancedMetrics(\n", - " query=user_message,\n", - " response=response_text[:200] + \"...\",\n", - " total_tokens=total_tokens,\n", - " tool_tokens_all=tool_tokens_all,\n", - " tool_tokens_selected=tool_tokens_selected,\n", - " tool_savings=tool_savings,\n", - " selected_tools=selected_tool_names,\n", - " latency_seconds=end_time - start_time,\n", - " )\n", - "\n", - " print(f\"\\n🤖 AGENT: {metrics.response}\")\n", - " print(f\"\\n📊 Metrics:\")\n", - " print(f\" Tool tokens (all 5): {metrics.tool_tokens_all:,}\")\n", - " print(f\" Tool tokens (selected 3): {metrics.tool_tokens_selected:,}\")\n", - " print(\n", - " f\" Tool savings: {metrics.tool_savings:,} ({metrics.tool_savings / metrics.tool_tokens_all * 100:.0f}%)\"\n", - " )\n", - " print(f\" Latency: {metrics.latency_seconds:.2f}s\")\n", - "\n", - " return metrics\n", - "\n", - "\n", - "print(\"✅ Enhanced agent runner with metrics defined\")" - ], - "id": "cea9ecc411f0459f", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 📊 Part 6: Performance Comparison\n", - "\n", - "Let's test the enhanced agent and compare it to sending all tools.\n", - "\n", - "### Test 1: Prerequisites Query\n" - ], - "id": "537684b00566da00" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "enhanced_metrics_1 = await run_enhanced_agent_with_metrics(\n", - " \"What are the prerequisites for RU202?\"\n", - ")" - ], - "id": "3016507c856c84f1", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Test 2: Course Search Query\n", - "id": "5440d2d251b51b5c" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "enhanced_metrics_2 = await run_enhanced_agent_with_metrics(\n", - " \"What machine learning courses are available?\"\n", - ")" - ], - "id": "85ff9cb9552c2272", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Test 3: Comparison Query\n", - "id": "a5bace4febda0d0e" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "enhanced_metrics_3 = await run_enhanced_agent_with_metrics(\n", - " \"What's the difference between RU101 and RU102JS?\"\n", - ")" - ], - "id": "53710932cb10b2b3", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Performance Summary\n", - "id": "67b3c397e1853fec" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"📊 PERFORMANCE SUMMARY: Semantic Tool Selection\")\n", - "print(\"=\" * 80)\n", - "\n", - "all_metrics = [enhanced_metrics_1, enhanced_metrics_2, enhanced_metrics_3]\n", - "\n", - "print(f\"\\n{'Test':<40} {'Tools Selected':<20} {'Tool Savings':<15}\")\n", - "print(\"-\" * 80)\n", - "\n", - "for i, metrics in enumerate(all_metrics, 1):\n", - " tools_str = \", \".join(metrics.selected_tools[:2]) + \"...\"\n", - " savings_pct = metrics.tool_savings / metrics.tool_tokens_all * 100\n", - " print(f\"Test {i}: {metrics.query[:35]:<35} {tools_str:<20} {savings_pct:>13.0f}%\")\n", - "\n", - "# Calculate averages\n", - "avg_tool_tokens_all = sum(m.tool_tokens_all for m in all_metrics) / len(all_metrics)\n", - "avg_tool_tokens_selected = sum(m.tool_tokens_selected for m in all_metrics) / len(\n", - " all_metrics\n", - ")\n", - "avg_savings = avg_tool_tokens_all - avg_tool_tokens_selected\n", - "avg_savings_pct = avg_savings / avg_tool_tokens_all * 100\n", - "\n", - "print(\"\\n\" + \"-\" * 80)\n", - "print(\"AVERAGE PERFORMANCE:\")\n", - "print(f\" Tool tokens (all 5 tools): {avg_tool_tokens_all:,.0f}\")\n", - "print(f\" Tool tokens (selected 3 tools): {avg_tool_tokens_selected:,.0f}\")\n", - "print(\n", - " f\" Average savings: {avg_savings:,.0f} tokens ({avg_savings_pct:.0f}%)\"\n", - ")\n", - "print(\"=\" * 80)" - ], - "id": "793096f16d990380" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Summary of Results\n", - "id": "e7a210da06b3d61d" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "print(\"\\n\" + \"=\" * 80)\n", - "print(\"📊 SEMANTIC TOOL SELECTION RESULTS\")\n", - "print(\"=\" * 80)\n", - "\n", - "print(f\"\\n{'Metric':<30} {'Before':<15} {'After':<15} {'Change':<15}\")\n", - "print(\"-\" * 80)\n", - "print(f\"{'Tools available':<30} {'3':<15} {'5':<15} {'+67%':<15}\")\n", - "print(f\"{'Tool tokens (all 5)':<30} {'1,200':<15} {'2,200':<15} {'+83%':<15}\")\n", - "print(f\"{'Tool tokens (selected 3)':<30} {'1,200':<15} {'880':<15} {'-27%':<15}\")\n", - "print(f\"{'Tool selection accuracy':<30} {'100% (all)':<15} {'~91%':<15} {'Smarter':<15}\")\n", - "print(f\"{'Total tokens/query':<30} {'3,400':<15} {'2,200':<15} {'-35%':<15}\")\n", - "print(\"=\" * 80)\n", - "\n", - "print(\"\"\"\n", - "🎯 KEY ACHIEVEMENT: We added 2 new tools (+67% capabilities) while REDUCING tokens by 35%!\n", - "\n", - "This is the power of semantic tool selection:\n", - "• Scale capabilities without scaling token costs\n", - "• Intelligent tool selection based on query intent\n", - "• Better performance with more features\n", - "• Can now scale to 100+ tools with constant overhead\n", - "\"\"\")" - ], - "id": "95acaac38eb1b6bf" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🎓 Part 7: Trade-offs and Best Practices\n", - "\n", - "### When to Use Semantic Tool Selection\n" - ], - "id": "592a6fe82f13f420" - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "print(\"\"\"\n", - "✅ USE SEMANTIC TOOL SELECTION WHEN:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "• You have 5+ tools in your agent\n", - "• Query types are diverse and unpredictable\n", - "• Tools have clear semantic boundaries\n", - "• Token budget is constrained\n", - "• You need to scale to 10+ tools in the future\n", - "\n", - "❌ DON'T USE SEMANTIC TOOL SELECTION WHEN:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "• You have ≤3 tools (overhead not worth it)\n", - "• All tools are needed for every query\n", - "• Tools are very similar semantically\n", - "• Latency is absolutely critical (adds ~50-100ms)\n", - "• Tools change frequently (requires re-indexing)\n", - "\n", - "⚖️ TRADE-OFFS TO CONSIDER:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Benefit Cost\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "60% token reduction +50-100ms latency\n", - "Scales to 100+ tools Requires embedding infrastructure\n", - "Intelligent tool matching ~91% accuracy (not 100%)\n", - "Constant token overhead Additional complexity\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "\"\"\")" - ], - "id": "53ca827180235e93", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "### Production Considerations\n", - "id": "b0bdb4671ab48eb5" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "print(\"\"\"\n", - "🏭 PRODUCTION BEST PRACTICES:\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "\n", - "1. CACHE ROUTE EMBEDDINGS\n", - " • Don't re-embed routes on every request\n", - " • Use RedisVL's built-in caching\n", - " • Update only when tools change\n", - "\n", - "2. MONITOR SELECTION ACCURACY\n", - " • Track which tools are selected\n", - " • Log when wrong tools are chosen\n", - " • A/B test selection strategies\n", - "\n", - "3. FALLBACK STRATEGY\n", - " • If selection fails, send all tools\n", - " • Better to be slow than broken\n", - " • Log failures for investigation\n", - "\n", - "4. TUNE DISTANCE THRESHOLD\n", - " • Start with 0.3 (default)\n", - " • Adjust based on your use case\n", - " • Lower = more strict, Higher = more permissive\n", - "\n", - "5. RICH TOOL METADATA\n", - " • Include use cases and examples\n", - " • Add keywords for better matching\n", - " • Update descriptions based on usage patterns\n", - "\n", - "6. A/B TESTING\n", - " • Compare semantic vs static selection\n", - " • Measure token savings vs accuracy\n", - " • Validate with real user queries\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "\"\"\")" - ], - "id": "b77b97e6a50a41b7" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### Production Monitoring and Observability\n", - "\n", - "When deploying agents to production, **observability** becomes critical for understanding behavior, debugging issues, and optimizing performance. Here's why monitoring matters and what tools can help:\n", - "\n", - "#### 🔍 **Why Observability Matters for Production Agents**\n", - "\n", - "**1. Debugging Agent Behavior**\n", - "- Agents make autonomous decisions that can be hard to predict\n", - "- Understanding *why* an agent chose a specific tool or action is crucial\n", - "- Trace the full decision path from user query to final response\n", - "- Identify when agents get stuck in loops or make poor choices\n", - "\n", - "**2. Monitoring Token Usage and Costs**\n", - "- LLM API calls are expensive - track costs in real-time\n", - "- Identify queries that consume excessive tokens\n", - "- Measure the impact of optimizations (compression, tool selection)\n", - "- Set budgets and alerts for cost control\n", - "\n", - "**3. Tracking Tool Selection Accuracy**\n", - "- Monitor which tools are selected for different query types\n", - "- Measure semantic selection accuracy vs ground truth\n", - "- Identify tools that are over-selected or under-utilized\n", - "- Detect when wrong tools are chosen and why\n", - "\n", - "**4. Performance Optimization**\n", - "- Measure end-to-end latency for agent responses\n", - "- Identify bottlenecks (LLM calls, tool execution, memory retrieval)\n", - "- Track cache hit rates for embeddings and tool selections\n", - "- Optimize based on real usage patterns\n", - "\n", - "**5. Error Detection and Alerting**\n", - "- Catch failures in tool execution or LLM calls\n", - "- Monitor error rates and types\n", - "- Set up alerts for critical issues\n", - "- Track recovery from failures\n", - "\n", - "#### 🛠️ **Production Monitoring Tools**\n", - "\n", - "**LangSmith** (LangChain's Observability Platform)\n", - "- **What it does:** End-to-end tracing for LangChain/LangGraph applications\n", - "- **Key features:**\n", - " - Trace every LLM call, tool invocation, and agent decision\n", - " - Visualize agent execution graphs and decision paths\n", - " - Monitor token usage and costs per request\n", - " - Debug failures with full context and stack traces\n", - " - A/B test different prompts and configurations\n", - "- **Best for:** LangChain/LangGraph applications (like our course advisor agent)\n", - "- **Learn more:** [langchain.com/langsmith](https://www.langchain.com/langsmith)\n", - "\n", - "**Prometheus** (Metrics and Monitoring)\n", - "- **What it does:** Time-series metrics collection and alerting\n", - "- **Key features:**\n", - " - Track custom metrics (requests/sec, latency, error rates)\n", - " - Set up alerts for anomalies or threshold breaches\n", - " - Visualize metrics with Grafana dashboards\n", - " - Monitor system resources (CPU, memory, Redis performance)\n", - "- **Best for:** Infrastructure monitoring and alerting\n", - "- **Learn more:** [prometheus.io](https://prometheus.io/)\n", - "\n", - "**OpenTelemetry** (Distributed Tracing)\n", - "- **What it does:** Standardized observability framework for traces, metrics, and logs\n", - "- **Key features:**\n", - " - Trace requests across multiple services\n", - " - Correlate LLM calls with database queries and API calls\n", - " - Vendor-neutral (works with many backends)\n", - " - Automatic instrumentation for popular frameworks\n", - "- **Best for:** Complex systems with multiple services\n", - "- **Learn more:** [opentelemetry.io](https://opentelemetry.io/)\n", - "\n", - "#### 📊 **What to Monitor in Production Agents**\n", - "\n", - "**Agent Performance Metrics:**\n", - "- Response latency (p50, p95, p99)\n", - "- Token usage per request (input + output)\n", - "- Tool selection accuracy\n", - "- Memory retrieval latency\n", - "- Cache hit rates\n", - "\n", - "**Business Metrics:**\n", - "- User satisfaction (thumbs up/down, ratings)\n", - "- Task completion rate\n", - "- Conversation length (turns per session)\n", - "- Most common queries and intents\n", - "- Feature usage (which tools are most valuable)\n", - "\n", - "**System Health Metrics:**\n", - "- Error rates (LLM API, tool execution, memory)\n", - "- Redis performance (latency, memory usage)\n", - "- API rate limits and throttling\n", - "- Concurrent users and load\n", - "\n", - "#### 💡 **Best Practices for Agent Observability**\n", - "\n", - "1. **Start Simple:** Begin with basic logging, then add structured tracing\n", - "2. **Trace Everything:** Log all LLM calls, tool invocations, and decisions\n", - "3. **Add Context:** Include user ID, session ID, query intent in traces\n", - "4. **Set Alerts:** Monitor critical metrics (error rates, latency, costs)\n", - "5. **Review Regularly:** Analyze traces weekly to identify patterns and issues\n", - "6. **Iterate:** Use insights to improve prompts, tools, and selection strategies\n", - "\n", - "**Example: Monitoring Our Course Advisor Agent**\n", - "```\n", - "Key metrics to track:\n", - "- Tool selection accuracy (semantic router performance)\n", - "- Memory retrieval relevance (are we finding the right memories?)\n", - "- Token usage per query (impact of compression and tool selection)\n", - "- Response quality (user feedback, task completion)\n", - "- Error rates (failed tool calls, LLM timeouts)\n", - "```\n", - "\n", - "Observability transforms your agent from a \"black box\" into a transparent, debuggable, and optimizable system. It's essential for production deployments where reliability and cost-efficiency matter.\n" - ], - "id": "73273e097836a4f1" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 🎓 Part 8: Key Takeaways and Next Steps\n", - "\n", - "### What We've Achieved\n", - "\n", - "In this notebook, we scaled our agent from 3 to 5 tools while reducing token costs:\n", - "\n", - "**✅ Added 2 New Tools**\n", - "- `check_prerequisites` - Help students understand course requirements\n", - "- `compare_courses` - Compare courses side-by-side\n", - "\n", - "**✅ Implemented Semantic Tool Selection**\n", - "- Created rich tool metadata with use cases and keywords\n", - "- Built Redis tool embedding index\n", - "- Implemented semantic tool selector using vector similarity\n", - "- Achieved ~91% tool selection accuracy\n", - "\n", - "**✅ Reduced Tool Token Overhead**\n", - "- Tool tokens: 2,200 → 880 (-60% with selection)\n", - "- Total tokens: 2,800 → 2,200 (-21%)\n", - "- Maintained all 5 tools available, but only send top 3 per query\n", - "\n", - "**✅ Better Scalability**\n", - "- Can now scale to 10, 20, or 100+ tools\n", - "- Token cost stays constant (always top-k tools)\n", - "- Better tool selection than random or rule-based approaches\n", - "\n", - "### Cumulative Progress Through Section 4\n", - "\n", - "```\n", - "Metric NB2 (Basic) NB4 (Optimized) Improvement\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "Tools 3 5 +67%\n", - "Tool tokens 1,200 880 (selected) -27%\n", - "Total tokens 3,400 2,200 -35%\n", - "Scalability Limited 100+ tools ∞\n", - "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n", - "```\n", - "\n", - "### 💡 Key Takeaway\n", - "\n", - "**\"Scale capabilities, not token costs - semantic selection enables both\"**\n", - "\n", - "The biggest wins come from:\n", - "1. **Semantic understanding** - Match query intent to tool purpose\n", - "2. **Dynamic selection** - Only send what's needed\n", - "3. **Rich metadata** - Better embeddings = better selection\n", - "4. **Constant overhead** - Top-k selection scales to any number of tools\n", - "\n", - "### 🎯 What You've Learned in Section 4\n", - "\n", - "**Notebook 1:** Tool fundamentals and LangGraph basics\n", - "**Notebook 2:** Building a complete agent with tools and memory\n", - "**Notebook 3:** Memory compression for long conversations\n", - "**Notebook 4:** Semantic tool selection for scalability\n", - "\n", - "**You now know how to:**\n", - "- ✅ Build production-ready agents with LangGraph\n", - "- ✅ Integrate tools for dynamic capabilities\n", - "- ✅ Manage memory efficiently (working + long-term)\n", - "- ✅ Compress conversation history\n", - "- ✅ Scale to 100+ tools with semantic selection\n", - "- ✅ Make informed decisions about tool selection strategies\n", - "\n", - "---\n", - "\n", - "## 🎓 Course Completion: Your Context Engineering Journey\n", - "\n", - "### 🎉 **Congratulations!** You've completed the entire Context Engineering course!\n", - "\n", - "Let's reflect on everything you've learned across all four sections:\n", - "\n", - "### **Section 1: Context Engineering Foundations**\n", - "- ✅ Understood the four context types (System, User, Conversation, Retrieved)\n", - "- ✅ Learned how context shapes LLM behavior and responses\n", - "- ✅ Mastered context engineering principles and best practices\n", - "\n", - "### **Section 2: Retrieved Context Engineering**\n", - "- ✅ Built RAG systems with semantic search and vector embeddings\n", - "- ✅ Implemented context assembly and generation pipelines\n", - "- ✅ Engineered high-quality context from raw data\n", - "- ✅ Applied context quality optimization techniques\n", - "\n", - "### **Section 3: Memory Systems for Context Engineering**\n", - "- ✅ Implemented dual-memory architecture (working + long-term)\n", - "- ✅ Built memory-enhanced RAG systems\n", - "- ✅ Mastered memory extraction and compression strategies\n", - "- ✅ Managed conversation continuity and persistent knowledge\n", - "\n", - "### **Section 4: Integrating Tools and Agents**\n", - "- ✅ Created production-ready agents with LangGraph\n", - "- ✅ Integrated multiple tools for dynamic capabilities\n", - "- ✅ Implemented memory compression for long conversations\n", - "- ✅ Scaled agents to 100+ tools with semantic selection\n", - "\n", - "### 🚀 **You Are Now Ready To:**\n", - "\n", - "**Build Production AI Systems:**\n", - "- Design and implement context-aware LLM applications\n", - "- Build RAG systems that retrieve and use relevant information\n", - "- Create stateful agents with memory and tools\n", - "- Scale systems efficiently with compression and semantic routing\n", - "\n", - "**Apply Best Practices:**\n", - "- Engineer high-quality context for optimal LLM performance\n", - "- Manage token budgets and costs effectively\n", - "- Implement dual-memory architectures for conversation continuity\n", - "- Make informed architectural decisions (RAG vs Agents vs Hybrid)\n", - "\n", - "**Solve Real-World Problems:**\n", - "- Course advisors, customer support agents, research assistants\n", - "- Document Q&A systems, knowledge bases, chatbots\n", - "- Multi-tool agents for complex workflows\n", - "- Any application requiring context-aware AI\n", - "\n", - "### 🔮 What's Next?\n", - "\n", - "**Apply Your Knowledge:**\n", - "- Build your own context-aware applications\n", - "- Experiment with different architectures and patterns\n", - "- Contribute to open-source projects\n", - "- Share your learnings with the community\n", - "\n", - "**Continue Learning:**\n", - "- **Advanced LangGraph:** Sub-graphs, checkpointing, human-in-the-loop\n", - "- **Multi-Agent Systems:** Agent collaboration and orchestration\n", - "- **Production Deployment:** Monitoring, observability, scaling\n", - "- **Advanced RAG:** Hybrid search, re-ranking, query decomposition\n", - "\n", - "**Explore the Reference Implementation:**\n", - "- Study `reference-agent/` for production patterns\n", - "- See how all concepts integrate in a real application\n", - "- Learn advanced error handling and edge cases\n", - "- Understand CLI design and user experience\n", - "\n", - "### 📚 **Recommended Next Steps:**\n", - "\n", - "1. **Build a Project** - Apply these concepts to a real use case\n", - "2. **Study the Reference Agent** - See production implementation\n", - "3. **Explore Advanced Topics** - LangGraph, multi-agent systems, observability\n", - "4. **Join the Community** - Share your work, get feedback, help others\n", - "\n", - "### 🙏 Thank You!\n", - "\n", - "Thank you for completing the Context Engineering course! You've built a strong foundation in:\n", - "- Context engineering principles and best practices\n", - "- RAG systems and semantic search\n", - "- Memory architectures and compression\n", - "- Agent design and tool integration\n", - "- Production patterns and scalability\n", - "\n", - "**You're now equipped to build sophisticated, context-aware AI systems that solve real-world problems.**\n", - "\n", - "Keep building, keep learning, and keep pushing the boundaries of what's possible with context engineering! 🚀\n", - "\n", - "---\n", - "\n", - "**🎉 Congratulations on completing the Context Engineering course!** 🎉\n" - ], - "id": "58bf14c713a9dce4" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "---\n", - "\n", - "## 📚 Additional Resources\n", - "\n", - "### Semantic Search and Embeddings\n", - "- [OpenAI Embeddings Guide](https://platform.openai.com/docs/guides/embeddings)\n", - "- [Vector Similarity Search](https://redis.io/docs/stack/search/reference/vectors/)\n", - "- [Semantic Search Best Practices](https://www.pinecone.io/learn/semantic-search/)\n", - "\n", - "### Tool Selection and Agent Design\n", - "- [LangChain Tool Calling](https://python.langchain.com/docs/modules/agents/tools/)\n", - "- [Function Calling Best Practices](https://platform.openai.com/docs/guides/function-calling)\n", - "- [Agent Design Patterns](https://www.anthropic.com/index/agent-design-patterns)\n", - "\n", - "### Redis Vector Search\n", - "- [RedisVL Documentation](https://redisvl.com/)\n", - "- [Redis Vector Similarity](https://redis.io/docs/stack/search/reference/vectors/)\n", - "- [Hybrid Search with Redis](https://redis.io/docs/stack/search/reference/hybrid-queries/)\n", - "\n", - "### Scaling Agents\n", - "- [Scaling LLM Applications](https://www.anthropic.com/index/scaling-llm-applications)\n", - "- [Production Agent Patterns](https://www.langchain.com/blog/production-agent-patterns)\n", - "- [Cost Optimization for LLM Apps](https://platform.openai.com/docs/guides/production-best-practices)\n", - "\n", - "### Context Engineering and RAG\n", - "- [Context Rot Research](https://research.trychroma.com/context-rot) - Research on context quality\n", - "- [RAG Best Practices](https://www.anthropic.com/index/contextual-retrieval)\n", - "- [LangChain Documentation](https://python.langchain.com/docs/get_started/introduction)\n", - "\n", - "### Production Monitoring and Observability\n", - "- [LangSmith](https://www.langchain.com/langsmith) - LangChain's observability platform\n", - "- [OpenTelemetry](https://opentelemetry.io/) - Distributed tracing and monitoring\n", - "- [Prometheus](https://prometheus.io/) - Metrics and alerting\n", - "\n", - "\n" - ], - "id": "a944c2c9edbf8850" - } - ], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/section-4-tools-and-agents/README.md b/notebooks/section-4-tools-and-agents/README.md deleted file mode 100644 index c33c83c..0000000 --- a/notebooks/section-4-tools-and-agents/README.md +++ /dev/null @@ -1,216 +0,0 @@ -# Section 4: Integrating Tools and Agents - -**⏱️ Estimated Time:** 3.5-4.5 hours total - -## 🎯 Overview - -This section teaches you how to build intelligent agents that combine RAG, memory, and tools to create adaptive, multi-step workflows. You'll progress from understanding tool fundamentals to building a complete course advisor agent, and then learn how to scale it with semantic tool selection. - -## 📚 Notebooks - -### 1. Memory Tools and LangGraph Fundamentals (45-60 minutes) -**File:** `01_tools_and_langgraph_fundamentals.ipynb` - -**What You'll Learn:** -- How memory tools enable active context engineering -- Building the 3 essential memory tools: store, search, retrieve -- LangGraph fundamentals (nodes, edges, state) -- Passive vs active memory management -- When to use memory tools vs automatic memory - -**Key Concepts:** -- Memory tools for context engineering -- Active vs passive memory management -- LangGraph state management -- Tool-driven context construction - -### 2. Building a Course Advisor Agent (60-75 minutes) -**File:** `02_building_course_advisor_agent.ipynb` - -**What You'll Build:** -A complete course advisor agent with: -- **3 Tools (Memory-Focused):** - 1. `store_memory` - Save important information to long-term memory - 2. `search_memories` - Recall user preferences and facts - 3. `search_courses` - Semantic search over course catalog - -- **Active Memory Management:** - - LLM decides what to remember - - LLM searches memories strategically - - Dynamic context construction - -- **LangGraph Workflow:** - - Load memory → Agent decision → Tools → Save memory - - Conditional routing based on LLM decisions - - Graph visualization - -**Key Concepts:** -- Building agents with LangGraph -- Memory-driven tool design -- Active context engineering -- Multi-step reasoning with memory -- Personalized recommendations using stored preferences - -### 3. Agent with Memory Compression (90-120 minutes) -**File:** `03_agent_with_memory_compression.ipynb` - -**What You'll Learn:** -- Memory compression strategies for long conversations -- Truncation and sliding window techniques -- Production memory patterns -- Managing token budgets - -**Key Concepts:** -- Working memory compression -- Conversation history management -- Token optimization -- Production memory patterns - -### 4. Semantic Tool Selection (60-75 minutes) -**File:** `04_semantic_tool_selection.ipynb` - -**What You'll Build:** -An enhanced agent that scales from 3 to 5 tools using semantic selection: -- **2 New Tools:** - 1. `check_prerequisites` - Course prerequisite checking - 2. `compare_courses` - Side-by-side course comparison - -- **Tool Selection Strategies:** - - Static/hardcoded selection - - Pre-filtered/rule-based selection - - Semantic/dynamic selection with RedisVL - -- **Production Patterns:** - - RedisVL Semantic Router for intelligent tool routing - - 60% token reduction through selective tool loading - - Scalability to 100+ tools - -**Key Concepts:** -- Tool token cost and scaling challenges -- Tool selection strategy comparison -- Semantic tool routing with embeddings -- Production-ready routing patterns -- Trade-offs and best practices - -## 🔗 Connection to Previous Sections - -### Section 1: Context Types -- System, User, Conversation, Retrieved context -- Foundation for understanding how agents use context - -### Section 2: RAG Foundations -- Semantic search with vector embeddings -- Course catalog retrieval -- Single-step retrieval → generation - -### Section 3: Memory Systems for Context Engineering -- Working memory for conversation continuity -- Long-term memory for persistent knowledge -- Memory-enhanced RAG systems - -### Section 4: Integrating Tools and Agents (This Section) -- **Combines everything:** RAG + Memory + Tools + Decision-Making -- Agents can decide when to search, store, and recall -- Multi-step reasoning and adaptive workflows - -## 📊 Progression: RAG → Memory-RAG → Agent - -| Feature | RAG (S2) | Memory-RAG (S3) | Agent (S4) | -|---------|----------|-----------------|------------| -| **Retrieval** | ✅ | ✅ | ✅ | -| **Conversation Memory** | ❌ | ✅ | ✅ | -| **Long-term Memory** | ❌ | ⚠️ (manual) | ✅ (automatic) | -| **Decision Making** | ❌ | ❌ | ✅ | -| **Multi-step Reasoning** | ❌ | ❌ | ✅ | -| **Tool Selection** | ❌ | ❌ | ✅ | - -## ⚠️ Prerequisites - -**CRITICAL: This section requires ALL services to be running.** - -### Required Services: -1. **Redis** - Vector storage and caching (port 6379) -2. **Agent Memory Server** - Memory management (port 8088) -3. **OpenAI API** - LLM functionality - -### 🚀 Quick Setup: - -**Option 1: Automated Setup (Recommended)** -```bash -# Navigate to notebooks_v2 directory -cd ../ - -# Run setup script -./setup_memory_server.sh -``` - -**Option 2: Manual Setup** -See `../SETUP_GUIDE.md` for detailed instructions. - -### Additional Requirements: -1. **Completed Sections 1-3** - This section builds on previous concepts -2. **Docker Desktop running** - Required for containerized services -3. **Course data** - Will be generated automatically by notebooks - -## 🚀 Getting Started - -1. **Start with Notebook 1** to learn tool fundamentals -2. **Then Notebook 2** to build the complete agent -3. **Continue with Notebook 3** to learn memory compression -4. **Finish with Notebook 4** to scale with semantic tool selection -5. **Experiment** with different queries and watch the agent work -6. **Extend** the agent with additional tools (see suggestions in notebooks) - -## 🎓 Learning Outcomes - -By the end of this section, you will be able to: - -- ✅ Design and implement tools for LLM agents -- ✅ Build LangGraph workflows with conditional routing -- ✅ Integrate memory systems with agents -- ✅ Create agents that make multi-step decisions -- ✅ Compress conversation history for long interactions -- ✅ Implement semantic tool selection for scalability -- ✅ Scale agents to 100+ tools without token explosion -- ✅ Choose between RAG, Memory-RAG, and Agent architectures -- ✅ Make informed decisions about tool selection strategies -- ✅ Understand trade-offs (complexity, latency, cost, capabilities) - -## 📁 Archive - -The `_archive/` directory contains previous versions of Section 4 notebooks: -- `01_defining_tools.ipynb` - Original tool definition content -- `02_tool_selection_strategies.ipynb` - Tool selection patterns -- `03_building_multi_tool_intelligence.ipynb` - Multi-tool agent examples - -These were consolidated and improved in the current notebooks. - -## 🔗 Additional Resources - -### Core Technologies -- [Redis Agent Memory Server](https://github.com/redis/agent-memory-server) - Dual-memory architecture for agents -- [RedisVL](https://github.com/redis/redis-vl) - Redis Vector Library for semantic search -- [Redis Vector Search](https://redis.io/docs/stack/search/reference/vectors/) - Vector similarity search documentation - -### LangChain & LangGraph -- [LangChain Tools Documentation](https://python.langchain.com/docs/modules/agents/tools/) -- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/) -- [LangGraph Tutorials](https://langchain-ai.github.io/langgraph/tutorials/) - -### OpenAI -- [OpenAI Function Calling Guide](https://platform.openai.com/docs/guides/function-calling) -- [OpenAI API Documentation](https://platform.openai.com/docs/api-reference) - -## 💡 Next Steps - -After completing this section: - -1. **Explore the reference-agent** - See a production implementation with 7 tools -2. **Build your own agent** - Apply these concepts to your use case -3. **Experiment with tools** - Try different tool combinations -4. **Optimize performance** - Explore caching, parallel execution, etc. - ---- - -**Ready to build intelligent agents? Start with Notebook 1! 🚀** - diff --git a/progressive_agents/README.md b/progressive_agents/README.md deleted file mode 100644 index 062ff78..0000000 --- a/progressive_agents/README.md +++ /dev/null @@ -1,314 +0,0 @@ -# Progressive Agents - Context Engineering Learning Path - -A progressive learning experience teaching students how to evolve from basic RAG to production-ready agents with memory, using LangGraph-based architecture. - -## 🎯 Learning Objectives - -Students will learn: - -1. **RAG Fundamentals** - Build retrieval-augmented generation systems -2. **Context Engineering** - Optimize token efficiency with progressive disclosure -3. **LangGraph Workflows** - Create observable, stateful agent architectures -4. **Hybrid Search** - Combine semantic and exact-match retrieval -5. **Memory Systems** - Add working and long-term memory for personalization -6. **ReAct Pattern** - Implement explicit reasoning with Thought → Action → Observation loops - -## 📚 Stage Overview - -```mermaid -graph LR - S1[Stage 1
Baseline RAG] --> S2[Stage 2
Context Engineering] - S2 --> S3[Stage 3
Full Agent] - S3 --> S4[Stage 4
Hybrid Search + ReAct] - S4 --> S5[Stage 5
Working Memory] - S5 --> S6[Stage 6
Full Memory] -``` - -| Stage | Directory | Key Feature | Reasoning | -|-------|-----------|-------------|-----------| -| 1 | `stage1_baseline_rag/` | Basic RAG | Hidden | -| 2 | `stage2_context_engineered/` | Progressive disclosure | Hidden | -| 3 | `stage3_full_agent_without_memory/` | LangGraph + quality eval | Hidden | -| 4 | `stage4_hybrid_search/` | Hybrid search + NER | **Visible (ReAct)** | -| 5 | `stage5_working_memory/` | Working memory (session-based) | **Visible (ReAct)** | -| 6 | `stage6_full_memory/` | Working + Long-term memory | **Visible (ReAct)** | - -## 🔬 Stage Details - -### Stage 1: Baseline RAG -**Problem**: Show that basic retrieval works but is inefficient - -``` -┌─────────┐ ┌─────────┐ ┌──────────┐ -│ Query │ ──▶ │ Search │ ──▶ │ Response │ -└─────────┘ └─────────┘ └──────────┘ -``` - -**Features**: Raw JSON context, no optimization, ~5000 tokens per query - -### Stage 2: Context-Engineered RAG -**Solution**: Apply context engineering from notebooks Section 2 - -``` -┌─────────┐ ┌───────────┐ ┌────────────┐ ┌──────────┐ -│ Query │ ──▶ │ Search │ ──▶ │ Transform │ ──▶ │ Response │ -└─────────┘ └───────────┘ └────────────┘ └──────────┘ - │ - Progressive - Disclosure -``` - -**What's New**: Context transformation, token optimization (~1000 tokens) - -### Stage 3: Full Agent -**Enhancement**: Add LangGraph structure, intent classification, quality evaluation - -```mermaid -graph TD - Q[Query] --> IC[Classify Intent] - IC -->|GREETING| HG[Handle Greeting] - IC -->|Other| DQ[Decompose Query] - DQ --> R[Research] - R --> EQ[Evaluate Quality] - EQ -->|Poor| R - EQ -->|Good| S[Synthesize] - HG --> END - S --> END -``` - -**What's New**: Intent routing, query decomposition, iterative quality improvement - -### Stage 4: Hybrid Search with ReAct -**Enhancement**: Named Entity Recognition for precise course code matching + visible reasoning - -```mermaid -graph TD - Q[Query] --> RA[ReAct Agent] - - subgraph ReAct Loop - RA --> T1[💭 Thought: Analyze query] - T1 --> A1[🔧 Action: search_courses] - A1 --> O1[👁️ Observation: Results] - O1 --> T2[💭 Thought: Evaluate] - T2 --> |Need more| A1 - T2 --> |Done| F[✅ FINISH] - end - - F --> R[Response + Reasoning Trace] -``` - -**What's New**: -- FilterQuery for exact course code matching -- Hierarchical context assembly -- Progressive disclosure based on intent -- Visible reasoning trace with `--show-reasoning` CLI flag - -### Stage 5: Working Memory with ReAct -**Enhancement**: Add session-based working memory for multi-turn conversations - -```mermaid -graph TD - Q[Query] --> LM[Load Working Memory] - LM --> IC[Classify Intent] - IC --> RA[ReAct Agent] - RA --> SM[Save Working Memory] - SM --> END -``` - -**What's New**: -- Agent Memory Server integration for session storage -- Session-based conversation history (within a session) -- Pronoun resolution ("Tell me more about it") -- Auto-extraction to long-term memory (but no explicit tools to query it) - -**Tools**: `search_courses` (1 tool) - -### Stage 6: Full Memory with ReAct -**Final Stage**: Complete implementation with working + long-term memory - -``` -User Query - ↓ -┌─────────────────────────────────────────────────────┐ -│ ReAct Loop │ -│ ┌───────────────────────────────────────────────┐ │ -│ │ Thought: Analyze query, plan approach │ │ -│ │ Action: search_courses / remember / recall │ │ -│ │ Observation: Tool results │ │ -│ └───────────────────────────────────────────────┘ │ -│ ↓ (repeat) │ -│ ┌───────────────────────────────────────────────┐ │ -│ │ Thought: I have enough information │ │ -│ │ Action: FINISH │ │ -│ │ Action Input: [Final Answer] │ │ -│ └───────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────┘ - ↓ -Final Response + Reasoning Trace -``` - -**What's New**: -- `search_memories` tool for querying long-term memory -- `store_memory` tool for saving preferences/facts -- Cross-session personalization -- All previous features + visible reasoning - -**Tools**: `search_courses`, `search_memories`, `store_memory` (3 tools) - -## 🚀 Quick Start - -### Prerequisites - -1. **Install the package** (from repository root): - ```bash - pip install -e . - ``` - -2. **Set environment variables** (add to `.env` file at repository root or export in shell): - ```bash - export OPENAI_API_KEY="your-api-key" - export REDIS_URL="redis://localhost:6379" - export AGENT_MEMORY_URL="http://localhost:8088" # For stages 5-6 - ``` - -3. **Start required services**: - ```bash - # Start Redis and Agent Memory Server (for stages 5-6) - docker-compose up -d - - # Verify services are running - docker ps - ``` - -### Running Each Stage - -All commands assume you're starting from the repository root. - -```bash -# Stage 1: Baseline RAG (information overload) -cd progressive_agents/stage1_baseline_rag -python cli.py "What machine learning courses are available?" - -# Stage 2: Context-engineered RAG -cd progressive_agents/stage2_context_engineered -python cli.py "What machine learning courses are available?" - -# Stage 3: Full agent with hierarchical retrieval -cd progressive_agents/stage3_full_agent_without_memory -python cli.py "What courses teach machine learning?" - -# Stage 4: Hybrid search with ReAct -cd progressive_agents/stage4_hybrid_search -python cli.py --show-reasoning "What are the prerequisites for CS002?" - -# Stage 5: Working memory (session-based) - requires Agent Memory Server -cd progressive_agents/stage5_working_memory -python cli.py --student-id alice --session-id s1 "What is CS004?" -python cli.py --student-id alice --session-id s1 "Tell me more about it" - -# Stage 6: Full memory (working + long-term) - requires Agent Memory Server -cd progressive_agents/stage6_full_memory -python cli.py --student-id alice --show-reasoning "I prefer online courses" -python cli.py --student-id alice --show-reasoning "What courses do you recommend?" -``` - -### CLI Flags - -All stages support these common flags: - -| Flag | Description | -|------|-------------| -| `--quiet` / `-q` | Suppress intermediate logging, show only final response | -| `--show-reasoning` | Show agent reasoning trace (stages 4-6) | -| `--student-id ` | Student identifier for memory (stages 5-6) | -| `--session-id ` | Session identifier for working memory (stages 5-6) | - -```bash -# Quiet mode - only shows final response (useful for scripting) -python cli.py --quiet "What is CS004?" -python cli.py -q --student-id alice "What courses are available?" -``` - -## 📖 Notebook Concepts Demonstrated - -| Stage | Notebook Concepts | -|-------|-------------------| -| 1-2 | **Section 2**: RAG fundamentals, context crafting | -| 3 | **Section 4**: LangGraph, tool calling, agent architecture | -| 4 | **Section 2**: Progressive disclosure, hierarchical context + **Section 4**: ReAct pattern | -| 5 | **Section 3**: Working memory, conversation history + ReAct | -| 6 | **Section 3**: Long-term memory, memory extraction + Full ReAct | - -### Notebook References - -- **Section 1**: Context Engineering Foundations - - `01_what_is_context_engineering.ipynb` - - `02_context_assembly_strategies.ipynb` - -- **Section 2**: Retrieved Context Engineering - - `01_rag_fundamentals_and_implementation.ipynb` → Stages 1-2 - - `02_crafting_and_optimizing_context.ipynb` → Stages 2-4 - -- **Section 3**: Memory Systems - - `01_working_and_longterm_memory.ipynb` → Stages 5-6 - - `02_combining_memory_with_retrieved_context.ipynb` → Stages 5-6 - -- **Section 4**: Tools and Agents - - `01_tools_and_langgraph_fundamentals.ipynb` → All stages - - `02_building_course_advisor_agent.ipynb` → Stages 3+ - -## 📊 Feature Comparison - -| Feature | S1 | S2 | S3 | S4 | S5 | S6 | -|---------|----|----|----|----|----|----| -| **Context Engineering** | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | -| **Intent Classification** | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | -| **Hybrid Search (NER)** | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | -| **Working Memory** | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | -| **Long-term Memory** | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | -| **ReAct (Visible Reasoning)** | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | -| **Progressive Disclosure** | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | - -*S1=Stage 1, S2=Stage 2, etc.* - -## 🔧 Technical Details - -### Key Components - -| Component | Description | Used In | -|-----------|-------------|---------| -| `CourseManager` | Basic Redis vector search for courses | Stages 1-3 | -| `HierarchicalCourseManager` | Two-tier retrieval (summaries + details) | Stages 4+ | -| `HierarchicalContextAssembler` | Progressive disclosure | Stages 4+ | -| `FilterQuery` | Exact course code matching | Stages 4+ | -| `Agent Memory Server` | Working memory (Stage 5), Full memory (Stage 6) | Stages 5-6 | -| `ReActAgent` | Visible reasoning loop | Stages 4-6 | - -**Note:** The workshop modules use `HierarchicalCourseManager` throughout for consistency with the progressive agents. - -### Architecture Patterns - -1. **Tool-Calling Pattern** (Stage 3): LLM decides when to call tools via `bind_tools()` -2. **ReAct Pattern** (Stages 4-6): Explicit Thought → Action → Observation loop - -## 🎓 Learning Outcomes - -By completing this progressive path, students will: - -1. ✅ **Build RAG systems** from basic to advanced -2. ✅ **Apply context engineering** for token efficiency -3. ✅ **Use LangGraph** for observable agent workflows -4. ✅ **Implement hybrid search** combining NER + semantic search -5. ✅ **Integrate memory systems** for multi-turn conversations -6. ✅ **Understand ReAct** for transparent reasoning - -## 📚 Resources - -- **Notebooks**: `notebooks/section-1-4/` -- **CourseManager**: `src/redis_context_course/` -- **LangGraph Docs**: https://langchain-ai.github.io/langgraph/ - -## 📄 License - -MIT License - diff --git a/progressive_agents/stage1_baseline_rag/README.md b/progressive_agents/stage1_baseline_rag/README.md deleted file mode 100644 index eb5633b..0000000 --- a/progressive_agents/stage1_baseline_rag/README.md +++ /dev/null @@ -1,406 +0,0 @@ -# Stage 1: Baseline RAG Agent (Information Overload) - -## 📍 Position in Learning Path - -| Previous | Current | Next | -|----------|---------|------| -| — | **Stage 1: Baseline RAG** | [Stage 2: Context-Engineered](../stage2_context_engineered/) | - -This is the **starting point** of the progressive agents learning path. It intentionally demonstrates the problems that arise without context engineering, setting the stage for the improvements you'll learn in subsequent stages. - ---- - -## 🎯 Purpose - -This is the **baseline** RAG agent that demonstrates **INFORMATION OVERLOAD** - what happens when you return EVERYTHING for EVERYONE without any context engineering or hierarchical retrieval. - -**Key Learning**: "More information ≠ better answers. Progressive disclosure and context engineering are essential." - ---- - -## 📚 Related Notebooks - -This stage demonstrates the **problems** that the following notebooks teach you to solve: - -| Notebook | Concepts Demonstrated | How This Stage Relates | -|----------|----------------------|------------------------| -| [Section 1: What is Context Engineering?](../../notebooks/section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb) | The four context types, why context matters | Stage 1 shows what happens **without** proper context engineering | -| [Section 1: Context Assembly Strategies](../../notebooks/section-1-context-engineering-foundations/02_context_assembly_strategies.ipynb) | Token limits, context window constraints | Stage 1 wastes tokens by ignoring these constraints | -| [Section 2: RAG Fundamentals](../../notebooks/section-2-retrieved-context-engineering/01_rag_fundamentals_and_implementation.ipynb) | Basic RAG implementation | Stage 1 uses basic RAG but without optimization | -| [Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb) | Context cleaning, transformation, optimization | Stage 1 shows the **before** state; Stage 2 applies these techniques | - -**Study Path**: Run this stage first to see the problems, then read the Section 2 notebooks to understand the solutions, then move to Stage 2 to see them applied. - ---- - -## ⚠️ What's Wrong with This Agent? - -This agent demonstrates the problem of **information overload**: - -### 1. **Returns EVERYTHING for ALL Courses** -- Returns FULL course details for ALL 5 courses -- Includes complete 14-week syllabi for EVERY course -- All assignments, grading policies, textbooks for ALL courses -- No discrimination based on relevance - -### 2. **Massive Token Waste** -- ~6,000+ tokens for 5 courses (vs ~700 with hierarchical retrieval) -- Spends tokens on courses user doesn't care about -- Includes syllabi for courses that aren't even relevant -- 8-10x more tokens than necessary - -### 3. **Information Overload** -- LLM gets overwhelmed with too much data -- User has to wade through massive amounts of information -- No progressive disclosure (everything at once) -- Poor user experience - -### 4. **No Prioritization** -- Treats all courses equally regardless of relevance -- Doesn't adapt detail level to match importance -- No hierarchy or structure -- Flat, undifferentiated information dump - -## 🏗️ Architecture - -### Simple 2-Node Workflow - -```mermaid -graph LR - START([Start]) --> Research[Research Node
Semantic Search
RAW Context] - Research --> Synthesize[Synthesize Node
LLM Answer] - Synthesize --> END([End]) - - style Research fill:#ff6b6b - style Synthesize fill:#4ecdc4 -``` - -### What It Does - -1. **Research Node**: - - Performs semantic search using Redis vector embeddings - - Retrieves top 5 courses - - Matches to hierarchical courses with FULL syllabi - - Returns **COMPLETE details for ALL 5 courses** (information overload!) - -2. **Synthesize Node**: - - Sends massive context to LLM (~6,000+ tokens) - - Generates answer based on overwhelming data - -### What It Doesn't Do - -- ❌ No progressive disclosure (no hierarchy) -- ❌ No context budget management -- ❌ No prioritization by relevance -- ❌ No adaptive detail levels -- ❌ No context cleaning or optimization -- ❌ No query decomposition -- ❌ No quality evaluation - -## 📊 Example: The Problem - -### Query -``` -"What machine learning courses are available?" -``` - -### Context Sent to LLM (~6,000+ tokens) - -Returns FULL details for ALL 5 courses including: - -**Course 1: CS010 - Machine Learning Fundamentals** -- Full description -- Complete 14-week syllabus with topics, subtopics, readings -- All 10 assignments (homeworks, exams, projects) -- Grading policy breakdown -- Prerequisites: CS002 (Data Structures), MATH020 (Linear Algebra) -- Learning objectives -- Schedule and location - -**Course 2: CS011 - Deep Learning and Neural Networks** -- [Same complete details with 14-week syllabus] -- Prerequisites: CS010 (ML Fundamentals) - -**Course 3: CS013 - Computer Vision** -- [Same complete details with 14-week syllabus] -- Prerequisites: CS010 (ML Fundamentals) - -**Course 4: CS012 - Natural Language Processing** -- [Same complete details with 14-week syllabus] -- Prerequisites: CS010 (ML Fundamentals) - -**Course 5: CS017 - Reinforcement Learning** -- [Same complete details with 14-week syllabus] -- Prerequisites: CS010 (ML Fundamentals) - -**Total**: ~6,000+ tokens of raw JSON data - -### Problems Visible to Students - -1. **Information Overload**: User only needs 2-3 courses, but gets full details for all 5 -2. **Token Waste**: Spends ~5,000 tokens on courses user doesn't care about -3. **No Hierarchy**: Everything at the same detail level, no progressive disclosure -4. **Poor UX**: User has to wade through 70+ weeks of syllabus content -5. **Inefficient**: 8-10x more tokens than hierarchical approach (~700 tokens) - -## 🚀 Usage - -### Installation - -From the repository root: - -```bash -cd progressive_agents/stage1_baseline_rag -``` - -### Environment Setup - -Make sure you have set the required environment variables (either in a `.env` file at the repository root or exported in your shell): - -```bash -OPENAI_API_KEY=your_key_here -REDIS_URL=redis://localhost:6379 -``` - -### Running the Agent - -**Interactive Mode** (default): -```bash -python cli.py -``` - -**Single Query**: -```bash -python cli.py "What machine learning courses are available?" -``` - -**Simulation Mode** (run example queries): -```bash -python cli.py --simulate -``` - -**With Cleanup** (remove courses from Redis on exit): -```bash -python cli.py --cleanup -``` - -**Help**: -```bash -python cli.py --help -``` - -## 📈 Expected Results - -### Sample Output - -``` -❓ Question: What machine learning courses are available? - -🔍 Searching for courses: 'What machine learning courses are available?' -✅ Found 5 courses -📊 INFORMATION OVERLOAD: 24,532 chars (~6133 tokens) -⚠️ Returning FULL details (including syllabi) for ALL 5 courses! -⚠️ This wastes tokens on courses the user doesn't care about! -⚠️ No progressive disclosure, no context engineering! -🔬 Research complete in 245.32ms -🔗 Synthesizing answer from raw context... -🔗 Synthesis complete in 2134.56ms - -============================================================ -📝 Answer: -============================================================ -Based on the course information provided, there are 5 machine learning -related courses available: - -1. CS010: Machine Learning Fundamentals - - Instructor: Dr. Smith - - Credits: 4, Level: Advanced - - 14-week course covering ML algorithms, neural networks, etc. - - Prerequisites: CS002 (Data Structures), MATH020 (Linear Algebra) - -2. CS011: Deep Learning and Neural Networks - - Instructor: Dr. Johnson - - Credits: 4, Level: Advanced - - 14-week course on advanced neural architectures - - Prerequisites: CS010 (ML Fundamentals) - -[... continues with courses 3, 4, 5 ...] - -============================================================ -📊 Metrics: -============================================================ - Courses Found: 5 - Estimated Tokens: ~6133 - -⚠️ INFORMATION OVERLOAD: 8-10x more tokens than necessary! -⚠️ Includes full syllabi for ALL courses (even irrelevant ones) - See Stage 2 for context engineering (64% reduction) - See Stage 3 for hierarchical retrieval (progressive disclosure) -``` - -## 🔍 What Students Should Observe - -### 1. Examine the Information Overload - -Look at what's being sent to the LLM: -- How many tokens? (~6,000+) -- How many courses get FULL details? (All 5) -- How many syllabi are included? (All 5, ~70 weeks total) -- Does the user need all this information? (No!) - -### 2. Identify Wasted Tokens - -Which information is unnecessary? -- Full syllabi for courses 3, 4, 5 (user probably only cares about top 2-3) -- All assignments for all courses -- Complete grading policies for all courses -- Textbook lists for all courses -- Week-by-week details for courses user won't take - -### 3. Calculate Token Waste - -```python -# Token breakdown -Total tokens: ~6,133 -Courses: 5 -Tokens per course: ~1,227 (with full syllabus) - -# What's actually needed? -Summaries for 5 courses: ~300 tokens -Full details for top 2-3: ~400 tokens -Total needed: ~700 tokens - -# Waste calculation -Wasted tokens: 6,133 - 700 = 5,433 tokens (88% waste!) -``` - -### 4. Compare to Other Stages - -After running Stage 1, students should: -1. Run the same query on Stage 2 (context-engineered, ~539 tokens) -2. Run the same query on Stage 3 (hierarchical, ~700 tokens with syllabi) -3. Compare token counts and information quality -4. Understand the value of progressive disclosure -5. See why hierarchical retrieval is the best approach - -## 🎓 Learning Objectives - -By using this baseline agent, students will: - -1. **Understand Information Overload**: See what happens when you return everything for everyone -2. **Identify Token Waste**: Learn to spot unnecessary information -3. **Measure Inefficiency**: Calculate token waste (88% in this case!) -4. **Motivate Progressive Disclosure**: Understand why hierarchical retrieval matters -5. **Prepare for Advanced Stages**: Know what to improve (Stage 2: cleaning, Stage 3: hierarchy) - -## 📚 Course Data - -### Hierarchical Course Data - -The agent uses hierarchical course data with: -- **CourseSummary**: Lightweight overview (code, title, instructor, credits) -- **CourseDetails**: Full details with 14-week syllabi, assignments, grading policies - -### Auto-Loading - -The agent automatically loads hierarchical courses on first run: -- 50 courses with full syllabi -- 500 total assignments -- 711 weeks of content -- Generated from `redis_context_course/data/hierarchical/hierarchical_courses.json` - -### Persistence - -By default, basic courses persist in Redis between runs. Use `--cleanup` to remove them on exit. - -### Data Generation - -To regenerate hierarchical course data (from repository root): -```bash -python -m redis_context_course.scripts.generate_hierarchical_courses \ - --count 50 \ - --seed 42 \ - --output-dir src/redis_context_course/data/hierarchical -``` - -## 🔄 Next Steps - -After understanding the information overload problem: - -1. **Move to Stage 2**: See how context engineering reduces tokens (64% reduction) -2. **Move to Stage 3**: See how hierarchical retrieval adds progressive disclosure -3. **Compare All Three**: Run the same queries on all stages -4. **Measure Improvements**: - - Stage 1: ~6,133 tokens (information overload) - - Stage 2: ~539 tokens (context-engineered, but no syllabi) - - Stage 3: ~700 tokens (hierarchical, with syllabi for top matches) -5. **Learn Techniques**: Understand cleaning, transformation, progressive disclosure - -## 🛠️ Technical Details - -### Dependencies - -- `langgraph` - Workflow orchestration -- `langchain-openai` - LLM integration -- `redis` - Vector storage -- `redisvl` - Redis vector library -- `nest_asyncio` - Async/sync compatibility - -### State Definition - -```python -class AgentState(TypedDict): - query: str # User's question - raw_context: str # Raw course data with FULL syllabi - courses_found: int # Number of courses retrieved - final_answer: str # LLM's answer - total_tokens: int # Estimated token count (~6,000+) - total_time_ms: float # Total execution time -``` - -### Workflow Nodes - -1. **research_node**: Semantic search → match to hierarchical courses → return FULL details for ALL -2. **synthesize_node**: LLM answer generation from massive context - -## 📝 Notes for Instructors - -### Teaching Points - -1. **Show, Don't Tell**: Let students see information overload firsthand -2. **Measure Everything**: Token counts, costs, quality, waste -3. **Compare All Three Stages**: Progression from overload → cleaning → hierarchy -4. **Emphasize Progressive Disclosure**: Overview first, details on-demand - -### Common Student Questions - -**Q: "Why not just return everything? The LLM can handle it."** -A: Yes, but it's massively inefficient. You're paying for 5,000+ tokens you don't need. Plus, information overload degrades answer quality. - -**Q: "How much does this cost?"** -A: ~6,133 tokens × $0.01/1K tokens = $0.061 per query. Stage 3 reduces this by 89% while maintaining better information quality! - -**Q: "Why include syllabi at all?"** -A: Syllabi are valuable for decision-making, but only for courses the user actually cares about. That's why Stage 3 uses hierarchical retrieval (summaries for all, syllabi for top matches). - -**Q: "Isn't Stage 2 better since it uses fewer tokens?"** -A: Stage 2 is more efficient than Stage 1, but it sacrifices information quality (no syllabi). Stage 3 achieves the best balance: ~700 tokens with syllabi for top matches. - -## 🔗 Related Resources - -### Next Steps in Learning Path -- **[Stage 2: Context-Engineered](../stage2_context_engineered/)**: Applies Section 2 techniques for 91% token reduction -- **[Stage 3: Full Agent](../stage3_full_agent_without_memory/)**: Adds LangGraph, intent classification, and progressive disclosure - -### Notebooks to Study -- **[Section 1: What is Context Engineering?](../../notebooks/section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb)**: Understand why context matters -- **[Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb)**: Learn the techniques to fix Stage 1's problems - -### Technical Resources -- **Comparison Document**: `../HIERARCHICAL_RETRIEVAL_COMPARISON.md` -- **Hierarchical Models**: `redis_context_course/hierarchical_models.py` - ---- - -**Remember**: This agent demonstrates INFORMATION OVERLOAD. Study the Section 2 notebooks to understand the solutions, then see them applied in Stage 2! - diff --git a/progressive_agents/stage2_context_engineered/README.md b/progressive_agents/stage2_context_engineered/README.md deleted file mode 100644 index 0230a45..0000000 --- a/progressive_agents/stage2_context_engineered/README.md +++ /dev/null @@ -1,488 +0,0 @@ -# Stage 2: Context-Engineered Agent (Flat Retrieval) - -## 📍 Position in Learning Path - -| Previous | Current | Next | -|----------|---------|------| -| [Stage 1: Baseline RAG](../stage1_baseline_rag/) | **Stage 2: Context-Engineered** | [Stage 3: Full Agent](../stage3_full_agent_without_memory/) | - -This stage applies the **context engineering techniques** from Section 2 notebooks to dramatically reduce token usage while maintaining answer quality. - ---- - -## 🎯 Purpose - -This agent demonstrates the **power of context engineering** by applying Section 2 techniques to dramatically reduce tokens compared to Stage 1. - -**Key Learning**: "Context engineering dramatically improves RAG efficiency through cleaning, transformation, and optimization." - ---- - -## 📚 Related Notebooks - -This stage directly implements concepts from these notebooks: - -| Notebook | Concepts Applied | Implementation in This Stage | -|----------|-----------------|------------------------------| -| [Section 2: RAG Fundamentals](../../notebooks/section-2-retrieved-context-engineering/01_rag_fundamentals_and_implementation.ipynb) | Vector search, RAG pipeline | `agent/tools.py` - semantic search implementation | -| [Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb) | Context cleaning, transformation, optimization | `agent/context_engineering.py` - all three techniques applied | - -### Key Notebook Concepts Demonstrated - -**From Section 2, Notebook 2 - "Crafting and Optimizing Context":** - -1. **Context Cleaning** (Notebook Section: "Data Engineering for Context") - - Remove noise fields (id, timestamps, enrollment) - - Keep only query-relevant information - - See: `transform_course_to_text()` function - -2. **Context Transformation** (Notebook Section: "The Transformation Workflow") - - Convert JSON → natural text format - - Make context LLM-friendly - - See: `format_courses_for_llm()` function - -3. **Context Optimization** (Notebook Section: "Context Preparation Pipelines") - - Efficient token usage - - Structured, consistent formatting - - See: `optimize_course_text()` function - -**Study Path**: Read Section 2, Notebook 2 first to understand the theory, then examine this stage's `context_engineering.py` to see the practical implementation. - ---- - -## 🔄 What Changed from Stage 1 - -### Improvements Made - -## ✨ What's Different from Stage 1? - -### Same Architecture -- ✅ Same LangGraph workflow (research → synthesize) -- ✅ Same semantic search (Redis vector embeddings) -- ✅ No query decomposition -- ✅ No quality evaluation - -### **NEW: Context Engineering!** -- ✅ **Context Cleaning**: Remove noise fields (id, timestamps, enrollment) -- ✅ **Context Transformation**: JSON → natural text format -- ✅ **Context Optimization**: Efficient token usage - -### ⚠️ Limitations (Fixed in Stage 3) -- ❌ **Flat Retrieval**: All courses get same detail level -- ❌ **No Progressive Disclosure**: Everything at once, no hierarchy -- ❌ **No Syllabi**: Had to remove syllabi to fit token budget -- ❌ **No Adaptation**: Doesn't adapt detail level to relevance - -This makes it easy to compare and see the **direct impact** of context engineering! - -## 📊 Improvements Over Stage 1 - -### Token Efficiency - -| Metric | Stage 1 (Overload) | Stage 2 (Engineered) | Improvement | -|--------|-------------------|---------------------|-------------| -| **Tokens per Query** | ~6,133 | ~539 | **91% reduction** | -| **Cost per Query** | $0.061 | $0.005 | **92% savings** | -| **Context Format** | Raw JSON with syllabi | Natural text | **Better parsing** | -| **Includes Syllabi** | ✅ All courses | ❌ None | **Trade-off** | - -### Quality Improvements - -- **Better LLM Understanding**: Natural text is easier to parse than JSON -- **Faster Processing**: Much less context to process -- **Clearer Answers**: LLM focuses on relevant information -- **No Information Overload**: Removed syllabi to fit budget - -### Trade-offs - -- ✅ **Massive token reduction** (91% vs Stage 1) -- ⚠️ **Lost syllabi** (had to remove to fit budget) -- ⚠️ **Still flat** (all courses get same detail level) -- ⚠️ **No progressive disclosure** (can't show overview first, details later) - -## 🧠 Context Engineering Techniques - -This agent applies three core techniques from Section 2 Notebook 2: - -### 1. Context Cleaning - -**Remove noise fields that don't help answer queries:** - -```python -# Stage 1 (includes noise): -{ - "id": "course_abc123", - "created_at": "2024-01-15T10:30:00Z", - "updated_at": "2024-01-20T14:22:00Z", - "enrollment_capacity": 50, - "current_enrollment": 0, - ... -} - -# Stage 2 (cleaned): -# Only includes: course_code, title, description, department, -# credits, difficulty_level, format, instructor, prerequisites -``` - -**Savings**: ~150-200 tokens per course (26-35% reduction) - -### 2. Context Transformation - -**Convert JSON → natural text format:** - -```python -# Stage 1 (JSON): -{"course_code": "CS101", "title": "Intro to Programming", "credits": 3, ...} - -# Stage 2 (Natural Text): -CS101: Intro to Programming -Department: Computer Science -Credits: 3 -Level: beginner -Format: in_person -Instructor: John Smith -Description: Learn Python programming fundamentals... -``` - -**Benefits**: -- Easier for LLMs to parse -- More readable -- No JSON overhead (brackets, quotes, commas) - -### 3. Context Optimization - -**Efficient token usage while preserving information:** - -```python -def transform_course_to_text(course: Course) -> str: - """Transform course to LLM-optimized text format.""" - prereq_text = "" - if course.prerequisites: - prereq_codes = [p.course_code for p in course.prerequisites] - prereq_text = f"\nPrerequisites: {', '.join(prereq_codes)}" - - course_text = f"""{course.course_code}: {course.title} -Department: {course.department} -Credits: {course.credits} -Level: {course.difficulty_level.value} -Format: {course.format.value} -Instructor: {course.instructor}{prereq_text} -Description: {course.description}""" - - return course_text -``` - -**Result**: Clean, structured, efficient context - -## 🏗️ Architecture - -### Simple 2-Node Workflow (Same as Stage 1) - -```mermaid -graph LR - START([Start]) --> Research[Research Node
Semantic Search
ENGINEERED Context] - Research --> Synthesize[Synthesize Node
LLM Answer] - Synthesize --> END([End]) - - style Research fill:#51cf66 - style Synthesize fill:#4ecdc4 -``` - -### What It Does - -1. **Research Node**: - - Performs semantic search using Redis vector embeddings - - Retrieves top 5 courses - - **Applies context engineering** (clean, transform, optimize) - - Returns natural text format - -2. **Synthesize Node**: - - Sends engineered context to LLM - - Generates answer based on clean, optimized data - -## 📈 Example: The Solution - -### Query -``` -"What machine learning courses are available?" -``` - -### Engineered Context Sent to LLM (539 tokens - 64% reduction!) - -``` -Course 1: -CS002: Machine Learning -Department: Computer Science -Credits: 4 -Level: advanced -Format: in_person -Instructor: Lisa Dunlap -Description: Introduction to machine learning algorithms and applications, covering supervised and unsupervised learning, and neural networks. -Learning Objectives: - - Understand ML algorithms - - Implement classification and regression models - - Evaluate model performance - - Apply ML to real-world problems - -Course 2: -CS009: Machine Learning -Department: Computer Science -Credits: 4 -Level: advanced -Format: hybrid -Instructor: Katelyn Jones -Prerequisites: CS001 -Description: Introduction to machine learning algorithms and applications... -Learning Objectives: - - Understand ML algorithms - - Implement classification and regression models - - Evaluate model performance - - Apply ML to real-world problems -``` - -### Improvements Visible to Students - -1. **Clean**: No `id`, `created_at`, `updated_at`, `enrollment_capacity` -2. **Readable**: Natural text instead of JSON -3. **Efficient**: 539 tokens vs 1,515 tokens (64% reduction) -4. **Structured**: Consistent, LLM-friendly format - -## 🚀 Usage - -### Installation - -From the repository root: - -```bash -cd progressive_agents/stage2_context_engineered -``` - -### Environment Setup - -Make sure you have set the required environment variables (either in a `.env` file at the repository root or exported in your shell): - -```bash -OPENAI_API_KEY=your_key_here -REDIS_URL=redis://localhost:6379 -``` - -### Running the Agent - -**Interactive Mode**: -```bash -python cli.py -``` - -**Single Query**: -```bash -python cli.py "What machine learning courses are available?" -``` - -**Simulation Mode** (run example queries): -```bash -python cli.py --simulate -``` - -**With Cleanup** (remove courses on exit): -```bash -python cli.py --cleanup -``` - -## 📊 Expected Results - -### Sample Output - -``` -❓ Question: What machine learning courses are available? - -🔍 Searching for courses: 'What machine learning courses are available?' -✅ Found 5 courses -📊 Engineered context: 2,157 chars (~539 tokens) -✅ Context engineering applied: - - Cleaned: Removed noise fields (id, timestamps, enrollment) - - Transformed: JSON → natural text format - - Structured: Consistent, LLM-friendly formatting -🔬 Research complete in 277.02ms - -============================================================ -📝 Answer: -============================================================ -There are two machine learning courses available: - -1. CS002: Machine Learning - - Department: Computer Science - - Credits: 4 - - Level: Advanced - - Format: In-person - - Instructor: Lisa Dunlap - -2. CS009: Machine Learning - - Department: Computer Science - - Credits: 4 - - Level: Advanced - - Format: Hybrid - - Instructor: Katelyn Jones - - Prerequisites: CS001 - -============================================================ -📊 Metrics: -============================================================ - Courses Found: 5 - Estimated Tokens: ~539 - -✨ Context engineering applied: - - Cleaned: Removed noise fields - - Transformed: JSON → natural text - - Optimized: Efficient token usage - -💡 Compare with Stage 1 to see the improvements! -``` - -## 🔍 What Students Should Observe - -### 1. Compare Token Counts - -Run the same query on both stages: - -```bash -# Stage 1 -cd ../stage1_baseline_rag -python cli.py "What machine learning courses are available?" -# Result: ~1,515 tokens - -# Stage 2 -cd ../stage2_context_engineered -python cli.py "What machine learning courses are available?" -# Result: ~539 tokens - -# Improvement: 64% reduction! -``` - -### 2. Compare Context Quality - -**Stage 1 Context** (noisy, verbose): -- Includes irrelevant fields -- JSON format -- Hard to parse - -**Stage 2 Context** (clean, optimized): -- Only relevant fields -- Natural text format -- Easy to parse - -### 3. Calculate ROI - -```python -# Cost savings per 1,000 queries -Stage 1: 1,515 tokens × 1,000 queries = 1,515,000 tokens = $15.15 -Stage 2: 539 tokens × 1,000 queries = 539,000 tokens = $5.39 - -Savings: $9.76 per 1,000 queries (64% reduction) - -# For 100,000 queries/month: -Savings: $976/month just from context engineering! -``` - -### 4. Understand the Techniques - -Students should examine `agent/context_engineering.py` to see: -- How `transform_course_to_text()` works -- How `optimize_course_text()` compresses further -- How `format_courses_for_llm()` assembles the final context - -## 🎓 Learning Objectives - -By using this context-engineered agent, students will: - -1. **See the Impact**: Measure the direct benefit of context engineering -2. **Understand Techniques**: Learn cleaning, transformation, optimization -3. **Apply Section 2**: Use techniques from notebooks in a real agent -4. **Calculate ROI**: Understand cost savings and efficiency gains -5. **Prepare for Production**: Learn patterns used in real-world RAG systems - -## 📚 Course Data - -Same as Stage 1: -- Auto-loads ~50 sample courses on first run -- Courses persist in Redis between runs -- Use `--cleanup` to remove on exit - -## 🔄 Next Steps - -After seeing the improvements from context engineering: - -1. **Compare with Stage 1**: Run same queries, measure differences -2. **Experiment**: Try different queries, observe token counts -3. **Understand Code**: Read `context_engineering.py` to see how it works -4. **Apply to Your Data**: Use these techniques on your own datasets - -## 🛠️ Technical Details - -### Dependencies - -Same as Stage 1: -- `langgraph` - Workflow orchestration -- `langchain-openai` - LLM integration -- `redis` - Vector storage -- `redisvl` - Redis vector library -- `nest_asyncio` - Async/sync compatibility - -### State Definition - -```python -class AgentState(TypedDict): - query: str # User's question - engineered_context: str # Context-engineered course data - courses_found: int # Number of courses retrieved - final_answer: str # LLM's answer - total_tokens: int # Estimated token count - total_time_ms: float # Total execution time -``` - -### Context Engineering Functions - -1. **transform_course_to_text()**: JSON → natural text -2. **optimize_course_text()**: Ultra-compact format -3. **format_courses_for_llm()**: Assemble final context - -## 📝 Notes for Instructors - -### Teaching Points - -1. **Show the Numbers**: Token counts, cost savings, efficiency -2. **Side-by-Side Comparison**: Run both stages with same queries -3. **Explain Each Technique**: Cleaning, transformation, optimization -4. **Real-World Impact**: This is how production RAG systems work - -### Common Student Questions - -**Q: "Is 64% reduction typical?"** -A: Yes! Context engineering often achieves 40-70% token reduction depending on data structure and noise levels. - -**Q: "Do we lose any information?"** -A: No! We remove noise (irrelevant fields) but keep all information needed to answer queries. - -**Q: "When should I use optimized vs full format?"** -A: Use full format (transform_course_to_text) for quality, optimized format (optimize_course_text) when you need to fit many results in context. - -**Q: "Can I apply this to other data types?"** -A: Absolutely! These techniques work for any structured data: products, documents, users, etc. - -## 🔗 Related Resources - -### Learning Path Navigation -- **Previous**: [Stage 1: Baseline RAG](../stage1_baseline_rag/) - See the problem this stage solves -- **Next**: [Stage 3: Full Agent](../stage3_full_agent_without_memory/) - Add LangGraph and progressive disclosure - -### Notebooks to Study -- **[Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb)**: The theory behind this stage's implementation -- **[Section 1: Context Assembly Strategies](../../notebooks/section-1-context-engineering-foundations/02_context_assembly_strategies.ipynb)**: Understanding token budgets and trade-offs - -### Technical Resources -- **Comparison Tools**: Side-by-side stage comparison -- **Context Engineering Code**: `agent/context_engineering.py` - ---- - -**Remember**: Same architecture as Stage 1, but with context engineering from Section 2 notebooks - that's the only difference, and it achieves 91% token reduction! - diff --git a/progressive_agents/stage3_full_agent_without_memory/README.md b/progressive_agents/stage3_full_agent_without_memory/README.md deleted file mode 100644 index 109aaaf..0000000 --- a/progressive_agents/stage3_full_agent_without_memory/README.md +++ /dev/null @@ -1,716 +0,0 @@ -# Stage 3: Full Agent with Hierarchical Retrieval - -## 📍 Position in Learning Path - -| Previous | Current | Next | -|----------|---------|------| -| [Stage 2: Context-Engineered](../stage2_context_engineered/) | **Stage 3: Full Agent** | [Stage 4: Hybrid Search](../stage4_hybrid_search/) | - -This stage introduces **LangGraph workflows**, **intent classification**, and **progressive disclosure** - transforming the simple RAG pipeline into a full agent architecture. - ---- - -## 🎯 Purpose - -A LangGraph-based intelligent agent demonstrating **hierarchical retrieval** and **progressive disclosure** patterns. This agent shows the best approach to context engineering: summaries for all results, full details (including syllabi) for top matches. - -**Key Learning**: "Agents need structure. LangGraph provides observable, stateful workflows with intent-based routing." - ---- - -## 📚 Related Notebooks - -This stage introduces agent architecture concepts from Section 4: - -| Notebook | Concepts Applied | Implementation in This Stage | -|----------|-----------------|------------------------------| -| [Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb) | LangGraph nodes, edges, state | `agent/workflow.py` - graph definition | -| [Section 4: Building Course Advisor Agent](../../notebooks/section-4-tools-and-agents/02_building_course_advisor_agent.ipynb) | Complete agent architecture | `agent/nodes.py` - node implementations | -| [Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb) | Progressive disclosure, hierarchical context | `HierarchicalContextAssembler` usage | - -### Key Notebook Concepts Demonstrated - -**From Section 4, Notebook 1 - "Tools and LangGraph Fundamentals":** -- **LangGraph State**: `AgentState` TypedDict for tracking workflow state -- **Nodes**: Functions that process and transform state -- **Edges**: Routing logic between nodes -- **Conditional Routing**: Intent-based path selection - -**From Section 4, Notebook 2 - "Building Course Advisor Agent":** -- **Intent Classification**: Detect greeting vs. course queries -- **Query Decomposition**: Break complex questions into sub-questions -- **Quality Evaluation**: Iterative improvement loop - -**From Section 2, Notebook 2 - "Crafting and Optimizing Context":** -- **Progressive Disclosure**: Summaries for all, details for top matches -- **Hierarchical Context Assembly**: Two-tier retrieval strategy - -**Study Path**: Read Section 4, Notebook 1 to understand LangGraph basics, then examine this stage's `workflow.py` and `nodes.py` to see the practical implementation. - ---- - -## 🔄 What Changed from Stage 2 - -| Feature | Stage 2 | Stage 3 | -|---------|---------|---------| -| **Architecture** | Simple 2-node pipeline | **LangGraph workflow** with 6+ nodes | -| **Intent Handling** | None | **Intent classification** (greeting, overview, details) | -| **Query Processing** | Direct search | **Query decomposition** into sub-questions | -| **Quality Control** | None | **Quality evaluation** with iterative improvement | -| **Context Assembly** | Flat | **Hierarchical** (summaries + details) | -| **Syllabi** | None (removed for tokens) | **Included** for top 2-3 matches | - ---- - -## 🚀 Features - -### **NEW: Intent Classification & Adaptive Retrieval!** -- **Query Intent Classification**: Automatically detects greeting, overview, or detail requests -- **Adaptive Detail Levels**: Matches retrieval depth to query intent - - **Greetings**: No course search (~50 tokens) - - **Overview queries**: Summaries only (~400 tokens) - - **Detail requests**: Full syllabi (~700 tokens) -- **Smart Routing**: Skips unnecessary processing for simple queries -- **Token Efficiency**: 85-99% reduction for non-detail queries - -### **Hierarchical Retrieval** -- **Two-Tier Retrieval**: Summaries for ALL courses, full details for top 2-3 -- **Progressive Disclosure**: Overview first, details on-demand -- **Context Budget Management**: Strategic token allocation based on query intent -- **Includes Syllabi**: Full 14-week syllabi for top matches (when requested) -- **Summary-Only Mode**: Course overviews without syllabi for overview queries - -### Advanced RAG Patterns -- **Intelligent Query Decomposition**: Breaks down complex questions into focused sub-questions -- **Semantic Course Search**: Redis vector search with hierarchical course data -- **Quality Assurance**: Evaluates and improves research quality through iterative loops -- **LangGraph Workflow**: Clean, observable agent architecture with explicit state management -- **Auto-loading Course Data**: Automatically loads 50 hierarchical courses with full syllabi -- **Persistent Storage**: Courses persist in Redis between runs (optional cleanup on exit) - -## 🎯 How It Works - -The agent follows an intelligent workflow with **intent classification** and **adaptive retrieval**: - -1. **Intent Classification**: LLM classifies query intent and determines detail level needed - - **GREETING**: Social interactions → No course search - - **COURSE_OVERVIEW**: "What courses exist?" → Summaries only - - **COURSE_DETAILS**: "Show me syllabus" → Full details with syllabi - - **GENERAL_QUESTION**: Other queries → Adaptive retrieval - -2. **Smart Routing**: Based on intent classification - - **Greetings** → Direct response, skip all course retrieval - - **Course queries** → Continue to decomposition and research - -3. **Query Decomposition**: Complex questions are broken into focused sub-questions using LLM - -4. **Cache Check**: Each sub-question is checked against semantic cache (currently disabled for educational purposes) - -5. **Adaptive Course Search**: - - **Summary Mode** (for overview queries): - - Semantic search returns top 5 courses - - Returns ONLY summaries (~400 tokens) - - No syllabi included - - **Full Mode** (for detail requests): - - Semantic search returns top 5 courses - - Returns summaries for ALL 5, full details for top 2-3 - - Includes complete 14-week syllabi (~700 tokens) - -6. **Quality Evaluation**: LLM evaluates search results for completeness and accuracy (0.0-1.0 score) - -7. **Iterative Improvement**: Low-quality results (score < 0.7) trigger additional search rounds - -8. **Response Synthesis**: All answers are combined into a comprehensive final response using LLM - -### Workflow Diagram - -```mermaid -graph TD - Start([User Query]) --> Classify[Classify Intent
LLM determines intent & detail level] - - Classify -->|GREETING
detail=none| Greeting[Handle Greeting
No course search] - Classify -->|COURSE_OVERVIEW
detail=summary| Decompose - Classify -->|COURSE_DETAILS
detail=full| Decompose - - Greeting --> End1([Friendly Response]) - - Decompose[Decompose Query
LLM breaks into sub-questions] --> Cache{Check Cache
DISABLED} - - Cache -->|All Cache Misses| Research[Adaptive Course Search
Redis Vector Search] - Cache -.->|Future: Cache Hits| Synthesize - - Research -->|detail=summary| SummaryOnly[Return Summaries Only
~400 tokens, no syllabi] - Research -->|detail=full| Hierarchical[Hierarchical Retrieval
~700 tokens, with syllabi] - - SummaryOnly --> Quality - Hierarchical --> Quality - - Quality{Evaluate Quality
LLM scores 0.0-1.0} - - Quality -->|Score < 0.7
Needs Improvement| Research - Quality -->|Score >= 0.7
Adequate| CacheStore[Store in Cache
DISABLED] - - CacheStore --> Synthesize[Synthesize Response
LLM combines answers] - Synthesize --> End2([Final Response]) - - style Classify fill:#ffe0b2,stroke:#e65100,stroke-width:3px - style Greeting fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px - style Cache fill:#f9f,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5 - style CacheStore fill:#f9f,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5 - style Decompose fill:#e1f5ff,stroke:#01579b,stroke-width:2px - style Research fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style SummaryOnly fill:#fff9c4,stroke:#f57f17,stroke-width:2px - style Hierarchical fill:#b2dfdb,stroke:#00695c,stroke-width:2px - style Quality fill:#fff3e0,stroke:#e65100,stroke-width:2px - style Synthesize fill:#f3e5f5,stroke:#4a148c,stroke-width:2px -``` - -**Legend**: -- 🟠 **Orange (thick)**: NEW! Intent classification -- 🟢 **Green**: Greeting handler (no retrieval) -- 🔵 **Blue**: LLM-powered decomposition -- 🟢 **Green**: Redis vector search (RAG) -- 🟡 **Yellow**: Summary-only retrieval -- 🟢 **Teal**: Hierarchical retrieval (full details) -- 🟠 **Orange**: LLM-powered quality evaluation -- 🟣 **Purple**: LLM-powered synthesis -- 🩷 **Pink (dashed)**: Disabled features (semantic caching) - -**Note**: Semantic caching is currently disabled for educational purposes. The agent demonstrates the full workflow without caching to show how RAG works at its core. - -## 📁 Project Structure - -``` -stage3_full_agent_without_memory/ -├── agent/ # Core agent implementation -│ ├── __init__.py # Package exports -│ ├── edges.py # LangGraph routing logic -│ ├── nodes.py # LangGraph workflow nodes -│ ├── setup.py # Initialization logic -│ ├── state.py # Agent state definitions -│ ├── tools.py # Course search tools -│ └── workflow.py # LangGraph workflow definition -├── cli.py # Interactive CLI -└── README.md # This file -``` - -## 🛠️ Setup - -### Prerequisites - -- Python 3.9+ -- OpenAI API key -- Redis server (for course data) -- `redis-context-course` package installed - -### Installation - -From the repository root: - -```bash -# Install the redis-context-course package (if not already installed) -pip install -e . - -# Navigate to stage 3 -cd progressive_agents/stage3_full_agent_without_memory - -# Set environment variables (or add to .env file at repository root) -export OPENAI_API_KEY="your-openai-api-key" -export REDIS_URL="redis://localhost:6379" -``` - -### Quick Start - -**Interactive Mode** (recommended): -```bash -python cli.py -``` - -**Single Query Mode**: -```bash -python cli.py "What machine learning courses are available for beginners?" -``` - -**Simulation Mode** (run example queries): -```bash -python cli.py --simulate -``` - -**Help**: -```bash -python cli.py --help -``` - -**Course Data Management**: -- On first run, the CLI automatically loads 50 hierarchical courses with full syllabi -- Courses persist in Redis between runs (no need to reload each time) -- Use `--cleanup` flag to remove courses from Redis on exit: - ```bash - python cli.py --cleanup - ``` -- Hierarchical course data is loaded from `redis_context_course/data/hierarchical/hierarchical_courses.json` - -**Programmatic Usage**: -```python -import asyncio -from agent import setup_agent, create_workflow, run_agent - -async def main(): - # Initialize the agent - course_manager, _ = await setup_agent() - - # Create the workflow - agent = create_workflow(course_manager) - - # Run a query - result = run_agent( - agent, - "What machine learning courses are available for beginners?" - ) - - # Print the response - print(result["final_response"]) - -if __name__ == "__main__": - asyncio.run(main()) -``` - -## 📚 Example Queries - -### Greeting (No Course Search) - -```bash -$ python cli.py "hello" -``` - -**Response** (~50 tokens): -``` -Hello! It's great to hear from you. I'm a course advisor agent here to help you -find courses, view syllabi, check prerequisites, and more. How can I assist you today? -``` - -**What happened**: -- Intent: GREETING, Detail Level: none -- Execution: greeting_handled -- Course search: ❌ Skipped -- Token efficiency: ✅ 99% reduction vs full search - ---- - -### Course Overview (Summaries Only) - -```bash -$ python cli.py "What machine learning courses are available?" -``` - -**Response** (~400 tokens): -``` -Found 5 relevant courses: - -1. CS002: Deep Learning and Neural Networks - Department: Computer Science | Instructor: Abigail Shaffer - Credits: 4 | Level: Graduate | Format: Hybrid - Description: Advanced neural network architectures and deep learning techniques. - Tags: deep learning, neural networks, transformers, computer vision - -2. CS009: Computer Vision - Department: Computer Science | Instructor: Sherry Decker - Credits: 4 | Level: Advanced | Format: Online - Description: Image processing, object detection, and visual recognition systems. - Prerequisites: CS004 - Tags: computer vision, image processing, object detection, CNN - -[... 3 more course summaries ...] -``` - -**What happened**: -- Intent: COURSE_OVERVIEW, Detail Level: summary -- Execution: decomposed → researched → synthesized -- Course search: ✅ Summary-only mode -- Syllabi included: ❌ No (summaries only) -- Token efficiency: ✅ 85% reduction vs full details - ---- - -### Course Details (Full Syllabi) - -```bash -$ python cli.py "Show me the syllabus for CS002" -``` - -**Response** (~3,900 tokens): -``` -Found relevant courses: - -## Overview of All Matches (5 courses) -[... summaries for all 5 courses ...] - -## Detailed Information (Top 3 Courses) - ---- -## CS002: Deep Learning and Neural Networks - -**Instructor**: Abigail Shaffer -**Schedule**: Monday, Wednesday, Friday, 04:00 PM - 04:50 PM -**Location**: Science Hall 540 - -### Description -Advanced neural network architectures and deep learning techniques... - -### Learning Objectives -- Understand core concepts in deep learning... -[... full learning objectives ...] - -### Grading Policy -- Homework: 40% -- Projects: 40% -- Participation: 20% - -### Assignments (10 total, 1250 points) -[... complete assignment list ...] - -### Course Syllabus (15 weeks) - -**Week 1: Deep Learning Foundations** -Topics: Deep Learning Foundations - Part 1, Part 2, Part 3, Part 4 -Readings: Chapter 1, Research Paper 1 - -**Week 2: Convolutional Neural Networks** -[... complete 15-week syllabus ...] - -### Textbooks -[... required and recommended textbooks ...] - -[... full details for 2 more courses ...] -``` - -**What happened**: -- Intent: COURSE_DETAILS, Detail Level: full -- Execution: decomposed → researched → synthesized -- Course search: ✅ Hierarchical mode -- Syllabi included: ✅ Yes (top 2-3 courses) -- Token efficiency: ✅ Appropriate for detail request - ---- - -## 🧠 Context Engineering Techniques - -This agent applies **advanced context engineering** from Section 2 notebooks: - -### 1. Intent Classification & Adaptive Retrieval (NEW!) - -**Match retrieval depth to query intent:** - -```python -# Step 1: Classify intent -intent, detail_level = classify_query_intent(query) -# Returns: ("COURSE_OVERVIEW", "summary") or ("COURSE_DETAILS", "full") - -# Step 2: Adaptive retrieval -if detail_level == "summary": - # Return ONLY summaries (~400 tokens) - context = assemble_summary_only_context(summaries) -elif detail_level == "full": - # Return summaries + full details (~700 tokens) - context = assemble_hierarchical_context(summaries, details) -else: # detail_level == "none" - # Skip course search entirely - return handle_greeting(query) -``` - -**Benefits**: -- **Token efficiency**: 85-99% reduction for non-detail queries -- **Better UX**: Don't overwhelm users with unnecessary information -- **Cost savings**: Fewer tokens = lower API costs -- **Faster responses**: Skip unnecessary retrieval and processing - -### 2. Hierarchical Retrieval - -**Two-tier retrieval with progressive disclosure:** - -```python -# TIER 1: Search summaries (lightweight) -summaries = search_summaries(query, limit=5) # ~300 tokens - -# TIER 2: Fetch details for top matches (comprehensive) -top_details = fetch_details(summaries[:3]) # ~400 tokens - -# PROGRESSIVE DISCLOSURE: Combine both -context = assemble_hierarchical_context( - summaries=summaries, # All 5 courses (overview) - details=top_details # Top 2-3 courses (full syllabi) -) -# Total: ~700 tokens with BETTER information quality -``` - -**Benefits**: -- Overview of all options (broad awareness) -- Deep details for best matches (informed decisions) -- Efficient token usage (~700 vs ~6,000 in Stage 1) -- Includes syllabi for top matches (vs none in Stage 2) - -### 2. Context Transformation - -Converts structured course objects into LLM-friendly natural text format: - -```python -# Hierarchical format: -## Overview of All Matches (5 courses) -CS101: Intro to Programming -Department: Computer Science, Credits: 3, Level: beginner -... - -## Detailed Information (Top 2 Courses) -CS101: Intro to Programming -[Full description, 14-week syllabus, assignments, grading policy] -``` - -**Benefits**: Easier for LLMs to parse, progressive disclosure, natural language - -### 3. Context Budget Management - -Strategic token allocation across retrieval tiers: -- Summaries: ~60 tokens per course × 5 = ~300 tokens -- Details: ~200 tokens per course × 2-3 = ~400 tokens -- Total: ~700 tokens (vs ~6,000 in Stage 1, ~539 in Stage 2) - -### 4. Semantic Search - -Uses Redis vector search (RedisVL) to find relevant courses based on semantic similarity: - -```python -results = await course_manager.search_courses( - query="machine learning courses", - limit=5, - similarity_threshold=0.5 # Lowered for better recall -) -``` - -**Implementation Note**: The agent uses a simplified direct search approach instead of a ReAct agent to avoid recursion issues. The `search_courses_sync` function wraps the async CourseManager search with `nest_asyncio` to handle nested event loops in LangGraph. - -**Benefits**: Finds relevant courses even with different wording - -## 📊 Performance Metrics - -The agent tracks detailed performance metrics: - -- **Total Latency**: End-to-end query processing time -- **Decomposition Latency**: Time to break down query -- **Cache Latency**: Time to check cache (currently minimal) -- **Research Latency**: Time for course search -- **Synthesis Latency**: Time to combine answers -- **Cache Hit Rate**: Percentage of cached answers (currently 0%) -- **LLM Calls**: Number of LLM API calls made - -Access metrics from the result: - -```python -result = run_agent(agent, query) -print(f"Total time: {result['metrics']['total_latency']:.2f}ms") -print(f"Execution path: {result['metrics']['execution_path']}") -``` - -## 🔄 Progressive Learning Path - -This is **Stage 3** of the progressive learning experience: - -| Stage | Approach | Tokens | Syllabi | Key Learning | -|-------|----------|--------|---------|--------------| -| **Stage 1** | Information Overload | ~6,133 | ✅ All courses | The problem: too much information | -| **Stage 2** | Context-Engineered | ~539 | ❌ None | Solution 1: cleaning & optimization | -| **Stage 3** | Hierarchical Retrieval | ~700 | ✅ Top 2-3 | Solution 2: progressive disclosure | -| **Stage 4** | Memory-Augmented | TBD | TBD | Add Redis Agent Memory Server | - -### Why Stage 3 is Best - -**vs Stage 1**: -- ✅ 91% token reduction (~700 vs ~6,133) -- ✅ Progressive disclosure (not information overload) -- ✅ Better information architecture - -**vs Stage 2**: -- ✅ Includes syllabi for top matches (Stage 2 has none) -- ✅ Better information quality for decision-making -- ⚠️ Slightly more tokens (~700 vs ~539), but worth it for syllabi - -**Best of Both Worlds**: -- Efficient like Stage 2 (massive reduction vs Stage 1) -- Informative like Stage 1 (includes syllabi for top matches) -- Smart architecture (progressive disclosure, hierarchical retrieval) - -## 🎓 Educational Goals - -Students learn: - -1. **Hierarchical Retrieval**: Two-tier retrieval with progressive disclosure -2. **Context Budget Management**: Strategic token allocation across tiers -3. **LangGraph Architecture**: How to build observable, stateful agents -4. **Query Decomposition**: Breaking complex questions into manageable parts -5. **Quality Evaluation**: Iterative improvement through self-assessment -6. **Advanced Section 2 Techniques**: Structured views, hybrid assembly, multi-strategy retrieval - -## 🔧 Implementation Details - -### Simplified Architecture - -This agent uses a **simplified direct search approach** instead of the original ReAct agent pattern: - -**Original (caching-agent)**: -- Used `create_react_agent` with tool calling -- Agent autonomously decided when to call search tools -- Hit LangGraph recursion limits (25 iterations) - -**Simplified (this implementation)**: -- Direct call to `search_courses_sync` function -- No ReAct agent loop - just semantic search -- Avoids recursion issues while maintaining functionality - -**Why the change?**: -- Educational clarity: Students see exactly what's happening -- Reliability: No recursion limit errors -- Performance: Fewer LLM calls, faster execution -- Simplicity: Easier to understand and debug - -### Async/Sync Handling - -The agent handles async/sync compatibility using `nest_asyncio`: - -```python -def search_courses_sync(query: str, top_k: int = 5) -> str: - """Synchronous wrapper for async search_courses.""" - import asyncio - import nest_asyncio - - nest_asyncio.apply() # Allow nested event loops - loop = asyncio.get_event_loop() - return loop.run_until_complete(course_manager.search_courses(...)) -``` - -This allows the async CourseManager to work within LangGraph's synchronous node functions. - -## 🚧 What's Commented Out (For Future Stages) - -### Semantic Caching - -Currently disabled to focus on core RAG workflow. Will be added in future stages: - -```python -# In nodes.py - check_cache_node -# semantic_cache.check(question, num_results=1) - -# In nodes.py - synthesize_response_node -# semantic_cache.store(question, answer) -``` - -### Why Disabled? - -- Focus on understanding the core workflow first -- Semantic caching adds complexity (similarity thresholds, false positives) -- Will be introduced progressively with proper tuning and monitoring - -## 🧪 Testing - -Run the CLI in simulation mode to test with example queries: - -```bash -cd progressive_agents/stage3_full_agent_without_memory -python cli.py --simulate -``` - -Or test interactively: - -```bash -python cli.py -``` - -## 🔍 Code References & Automatic Behaviors - -This section provides exact code references for key concepts and documents automatic behaviors from underlying infrastructure. - -### Progressive Disclosure Implementation - -The `HierarchicalContextAssembler` class implements progressive disclosure - a pattern that addresses the **"Lost in the Middle"** research finding (where LLMs perform worse on information in the middle of long contexts). - -**Code References:** - -| Concept | File | Lines | Description | -|---------|------|-------|-------------| -| Class Definition | `src/redis_context_course/hierarchical_context.py` | 16-28 | `HierarchicalContextAssembler` class with progressive disclosure strategy | -| Hierarchical Assembly | `src/redis_context_course/hierarchical_context.py` | 61-100 | `assemble_hierarchical_context()` - summaries for all, details for top N | -| Summary-Only Mode | `src/redis_context_course/hierarchical_context.py` | 30-59 | `assemble_summary_only_context()` - lightweight overview mode | -| Tool Integration | `progressive_agents/stage3_full_agent_without_memory/agent/tools.py` | 21, 34 | Import and instantiation of `HierarchicalContextAssembler` | -| Usage in Search | `progressive_agents/stage3_full_agent_without_memory/agent/tools.py` | 244-246, 333-335 | Calls to `assemble_hierarchical_context()` | - -**How Progressive Disclosure Addresses "Lost in the Middle":** - -```python -# From src/redis_context_course/hierarchical_context.py (lines 78-99) -# Structure: Header → Summaries (beginning) → Details (end) -# This places overview information at the START where LLMs perform best, -# and detailed information at the END (second-best position) - -sections.append(f"# Course Search Results for: {query}\n") # Header -sections.append("## Overview of All Matches\n") # Summaries first -for i, summary in enumerate(summaries, 1): - sections.append(self._format_summary(summary, i)) -if details: - sections.append(f"\n## Detailed Information (Top {len(details)} Courses)\n") # Details last -``` - -### Automatic Behaviors (Handled by Infrastructure) - -The following behaviors are **automatically handled** by the underlying infrastructure, even though they're not explicitly coded in this stage: - -| Behavior | Handled By | How It Works | -|----------|------------|--------------| -| **Token Budget Awareness** | `HierarchicalContextAssembler` | Summaries (~60 tokens each) + Details (~200 tokens each) = predictable budget | -| **"Lost in the Middle" Mitigation** | Context structure | Header → Summaries → Details places key info at start/end | -| **Hybrid Storage Pattern** | `assemble_hierarchical_context()` | Combines lightweight summaries with detailed views automatically | - -### Experimental Features (Available but Not Used) - -The `HierarchicalContextAssembler` includes experimental methods that are available for external use: - -```python -# From src/redis_context_course/hierarchical_context.py (lines 194-226) -def assemble_with_budget( - self, - summaries: List[CourseSummary], - details: List[CourseDetails], - query: str, - max_tokens: int = 2000, -) -> Tuple[str, int]: - """Assemble context with explicit token budget management.""" -``` - -These are marked as "EXPERIMENTAL" and not used in the progressive agents to maintain educational clarity. - ---- - -## 🔗 Related Resources - -### Learning Path Navigation -- **Previous**: [Stage 2: Context-Engineered](../stage2_context_engineered/) - Context engineering without agent architecture -- **Next**: [Stage 4: Hybrid Search](../stage4_hybrid_search/) - Add hybrid search and ReAct pattern - -### Notebooks to Study -- **[Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb)**: LangGraph basics used in this stage -- **[Section 4: Building Course Advisor Agent](../../notebooks/section-4-tools-and-agents/02_building_course_advisor_agent.ipynb)**: Complete agent architecture patterns -- **[Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb)**: Progressive disclosure concepts - -### Stage Comparison -- **Comparison Document**: `../HIERARCHICAL_RETRIEVAL_COMPARISON.md` - Detailed side-by-side comparison -- **Stage 1**: Information overload baseline (~6,133 tokens) -- **Stage 2**: Context-engineered flat retrieval (~539 tokens) -- **Stage 3**: Hierarchical retrieval with progressive disclosure (~700 tokens) ← **You are here** - -### Technical Resources -- **Hierarchical Models**: `redis_context_course/hierarchical_models.py` -- **Context Assemblers**: `redis_context_course/hierarchical_context.py` -- **CourseManager**: Redis-based course search (`redis_context_course.course_manager`) -- **LangGraph Docs**: https://langchain-ai.github.io/langgraph/ - -## 📄 License - -MIT License - See LICENSE file for details - diff --git a/progressive_agents/stage4_hybrid_search/README.md b/progressive_agents/stage4_hybrid_search/README.md deleted file mode 100644 index cd089aa..0000000 --- a/progressive_agents/stage4_hybrid_search/README.md +++ /dev/null @@ -1,192 +0,0 @@ -# Stage 4: Hybrid Search with ReAct Loop - -## 📍 Position in Learning Path - -| Previous | Current | Next | -|----------|---------|------| -| [Stage 3: Full Agent](../stage3_full_agent_without_memory/) | **Stage 4** | [Stage 5: Working Memory](../stage5_working_memory/) | - -This stage adds hybrid search capabilities with Named Entity Recognition and an explicit **ReAct** (Reasoning + Acting) loop for transparent reasoning. - ---- - -## 🎯 Purpose - -The ReAct pattern makes the agent's decision-making process **visible and debuggable**. Instead of opaque tool-calling, you see: -- **Thought**: What the agent is thinking -- **Action**: What tool it decides to use -- **Observation**: What results it receives - -**Key Learning**: "Transparent reasoning improves debugging, trust, and understanding of agent behavior." - ---- - -## 📚 Related Notebooks - -| Notebook | Concepts Applied | Implementation in This Stage | -|----------|-----------------|------------------------------| -| [Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb) | ReAct pattern, agent loops | `react_agent.py` - ReAct loop implementation | -| [Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb) | Hybrid search, progressive disclosure | `tools.py: search_courses_sync()` | - -### Key Notebook Concepts Demonstrated - -**From Section 4, Notebook 1 - "Tools and LangGraph Fundamentals":** -- **ReAct Pattern**: Thought → Action → Observation loop -- **Iterative Reasoning**: Multiple iterations until task complete -- **Explicit Termination**: FINISH action to end loop - -**Study Path**: Read Section 4, Notebook 1's ReAct section, then examine `react_agent.py` and `react_prompts.py` to see the implementation. - ---- - -## 🔄 What Changed from Stage 3 - -| Feature | Stage 3 | Stage 4 | -|---------|---------|---------| -| **Search** | Semantic only | **Hybrid** (exact + semantic) | -| **Reasoning** | Hidden (tool-calling) | **Visible** (Thought → Action → Observation) | -| **Decision Process** | Opaque LLM | **Transparent** reasoning trace | -| **Debugging** | Harder | **Easier** with `--show-reasoning` | - ---- - -## 🏗️ Architecture - -```mermaid -graph TD - Q[Query] --> RA[ReAct Agent] - - subgraph ReAct Loop - RA --> T1[💭 Thought: Analyze query] - T1 --> A1[🔧 Action: search_courses] - A1 --> O1[👁️ Observation: Results] - O1 --> T2[💭 Thought: Evaluate] - T2 --> |Need more| A1 - T2 --> |Done| F[✅ FINISH] - end - - F --> R[Response + Reasoning Trace] -``` - -## 🚀 Usage - -### Prerequisites - -Make sure you have: -- Installed the package: `pip install -e .` (from repository root) -- Set environment variables: - ```bash - export OPENAI_API_KEY="your-openai-api-key" - export REDIS_URL="redis://localhost:6379" - ``` - -### Running the Agent - -From the repository root: - -```bash -cd progressive_agents/stage4_hybrid_search - -# Single query -python cli.py "What are the prerequisites for CS002?" - -# Show reasoning trace -python cli.py --show-reasoning "What are the prerequisites for CS009?" - -# Interactive mode -python cli.py -``` - -## 📁 File Structure - -``` -stage4_hybrid_search/ -├── cli.py # Interactive CLI with --show-reasoning -├── README.md # This file -└── agent/ - ├── __init__.py # Module exports - ├── react_agent.py # ReAct loop implementation - ├── react_parser.py # Output parsing (max_length=8000) - ├── react_prompts.py # System prompt with examples - ├── tools.py # search_courses tool with FilterQuery - ├── state.py # WorkflowState with reasoning_trace - ├── setup.py # CourseManager initialization - └── workflow.py # LangGraph workflow -``` - -## Key Fixes Applied - -1. **Hierarchical Path**: Uses correct path `parent.parent.parent.parent / "src"` -2. **FilterQuery**: Exact course code matching instead of semantic search -3. **Observation Length**: 8000 chars to prevent syllabus truncation -4. **Empty Data Handling**: Prompt guidance for empty prerequisites - -## Test Results - -| Query | Time | Iterations | Result | -|-------|------|------------|--------| -| CS002 prerequisites (has CS001) | 5.1s | 2 | ✅ "requires CS001 (Intro to Programming)" | -| CS010 prerequisites (has CS002, MATH020) | 3.3s | 2 | ✅ "requires CS002 and MATH020" | -| CS006 syllabus | 7.3s | 2 | ✅ Full syllabus returned | - -## Comparison with Other Stages - -| Feature | Stage 3 | Stage 4 | Stage 5 | Stage 6 | -|---------|---------|---------|---------|---------| -| Search | Semantic | Hybrid | Hybrid | Hybrid | -| Reasoning | Hidden | **Visible** | Visible | Visible | -| Memory | None | None | Working (session) | Full (working + long-term) | -| Tools | N/A | 1 | 1 | 3 | - -## Example Reasoning Trace - -``` -🧠 Reasoning Trace: -================================================================================ -💭 Thought: The user is asking about prerequisites. I'll use exact match. - -🔧 Action: search_courses - Input: {"query": "CS002", "intent": "PREREQUISITES", "search_strategy": "exact_match", ...} -👁️ Observation: Found CS002 - Data Structures and Algorithms... - -💭 Thought: I found the course info. Prerequisites: CS001 (Introduction to Programming). - -✅ FINISH -================================================================================ -``` - -## 🔍 Code References & Automatic Behaviors - -This section provides exact code references for the ReAct pattern implementation. - -### ReAct Loop Implementation - -**Code References:** - -| Concept | File | Lines | Description | -|---------|------|-------|-------------| -| ReAct Agent | `progressive_agents/stage4_hybrid_search/agent/react_agent.py` | All | ReAct loop implementation | -| ReAct Prompts | `progressive_agents/stage4_hybrid_search/agent/react_prompts.py` | All | System prompt with Thought/Action/Observation format | -| Output Parser | `progressive_agents/stage4_hybrid_search/agent/react_parser.py` | All | Parses LLM output into structured format | -| State with Trace | `progressive_agents/stage4_hybrid_search/agent/state.py` | All | `WorkflowState` with `reasoning_trace` field | - -### Automatic Behaviors (Inherited from Stage 3) - -| Behavior | Handled By | How It Works | -|----------|------------|--------------| -| **Progressive Disclosure** | `HierarchicalContextAssembler` | Summaries for all, details for top N | -| **Hybrid Search Fallback** | `search_courses_sync()` | Falls back to semantic if exact match fails | -| **Observation Truncation** | `react_parser.py` | Limits observation to 8000 chars to prevent syllabus truncation | - ---- - -## 🔗 Related Resources - -### Learning Path Navigation -- **Previous**: [Stage 3: Full Agent](../stage3_full_agent_without_memory/) - Basic agent with tool calling -- **Next**: [Stage 5: Working Memory](../stage5_working_memory/) - Add session-based memory - -### Notebooks to Study -- **[Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb)**: ReAct pattern fundamentals -- **[Section 3: Working and Long-term Memory](../../notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb)**: Prepare for Stage 5 - diff --git a/progressive_agents/stage5_working_memory/README.md b/progressive_agents/stage5_working_memory/README.md deleted file mode 100644 index f351552..0000000 --- a/progressive_agents/stage5_working_memory/README.md +++ /dev/null @@ -1,302 +0,0 @@ -# Stage 5: Working Memory (Session-Based) - -## 📍 Position in Learning Path - -| Previous | Current | Next | -|----------|---------|------| -| [Stage 4: Hybrid Search](../stage4_hybrid_search/) | **Stage 5: Working Memory** | [Stage 6: Full Memory](../stage6_full_memory/) | - -This stage adds **session-based working memory** with the **ReAct** pattern for multi-turn conversations within a session. - ---- - -## 🎯 Purpose - -This stage adds **session-based working memory**: -- **Working Memory**: Conversation history stored per session -- **ReAct Pattern**: Visible reasoning traces -- **Auto-extraction**: Facts automatically promoted to long-term storage (but no explicit tools to query it) - -**Key Learning**: "Working memory enables multi-turn conversations with context continuity." - -**Tools**: `search_courses` (1 tool) — Long-term memory tools are added in Stage 6. - ---- - -## 📚 Related Notebooks - -| Notebook | Concepts Applied | Implementation in This Stage | -|----------|-----------------|------------------------------| -| [Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb) | ReAct pattern | `react_agent.py: ReActAgent` | -| [Section 3: Working and Long-term Memory](../../notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb) | Working memory | `nodes.py: load/save_working_memory_node()` | -| [Section 3: Combining Memory with Retrieved Context](../../notebooks/section-3-memory-systems/02_combining_memory_with_retrieved_context.ipynb) | Memory + RAG | Agent combines history + search | - -### Key Notebook Concepts Demonstrated - -**From Section 4, Notebook 1 - "Tools and LangGraph Fundamentals":** -- **ReAct Pattern**: Thought → Action → Observation loop -- **Visible Reasoning**: Debug-friendly decision traces - -**From Section 3, Notebook 1 - "Working and Long-term Memory":** -- **Working Memory**: Session-scoped conversation storage -- **Grounding**: Resolving "it", "that course" references - -**Study Path**: Review both Stage 4 ReAct and Stage 5 Memory to understand the components, then see how they combine here. - ---- - -## 🔄 What Changed from Stage 4 - -| Feature | Stage 4 | Stage 5 | -|---------|---------|---------| -| **Memory** | None | **Working memory** | -| **Multi-turn** | Single query | **Conversation continuity** | -| **Reasoning** | Visible (ReAct) | Visible (ReAct) | -| **Session** | Stateless | **Session-based** | - ---- - -## 🏗️ Architecture - -```mermaid -graph TD - Q[Query] --> LM[Load Working Memory] - LM --> IC[Classify Intent] - IC -->|GREETING| HG[Handle Greeting] - IC -->|Other| RA[ReAct Agent] - - subgraph ReAct Loop - RA --> T1[💭 Thought: Analyze + use history] - T1 --> A1[🔧 Action: search_courses] - A1 --> O1[👁️ Observation: Results] - O1 --> T2[💭 Thought: Evaluate] - T2 --> |Need more| A1 - T2 --> |Done| F[✅ FINISH] - end - - F --> SM[Save Working Memory] - HG --> SM - SM --> END[Response + Reasoning Trace] - - subgraph Memory Layer - LM -.->|Read| AMS[(Agent Memory Server)] - SM -.->|Write| AMS - end -``` - -## 🚀 Usage - -### Prerequisites - -1. **Install the package** (from repository root): - ```bash - pip install -e . - ``` - -2. **Set environment variables**: - ```bash - export OPENAI_API_KEY="your-openai-api-key" - export REDIS_URL="redis://localhost:6379" - export AGENT_MEMORY_URL="http://localhost:8088" # Optional, defaults to this - ``` - -3. **Start Agent Memory Server** (required for this stage): - ```bash - # Check if running - curl http://localhost:8088/v1/health - - # Start if needed (see main README for docker-compose setup) - docker-compose up -d agent-memory-server - ``` - -### Running the Agent - -From the repository root: - -```bash -cd progressive_agents/stage5_working_memory - -# Multi-turn with visible reasoning -python cli.py --student-id alice --session-id s1 --show-reasoning "What is CS004?" -python cli.py --student-id alice --session-id s1 --show-reasoning "Tell me more about it" - -# Interactive mode -python cli.py --student-id alice -``` - -## 📝 Example: Multi-turn with Reasoning Trace - -``` -Turn 1: -User: "What is CS004?" - -🧠 Reasoning Trace: -================================================================================ -💭 Thought: The user is asking about a specific course. I'll use exact match. - -🔧 Action: search_courses - Input: {"query": "CS004", "intent": "GENERAL", "search_strategy": "exact_match"} -👁️ Observation: Found CS004 - Web Development... - -💭 Thought: I have the course information. I can provide a complete answer. - -✅ FINISH -================================================================================ - -Answer: CS004 is Web Development, an intermediate course covering frontend and backend... - [Saves to working memory] - -Turn 2 (same session): -User: "What are the prerequisites?" -Agent: [Loads working memory, sees CS004 context] - "CS004 has no formal prerequisites listed..." - -Turn 3 (same session): -User: "Show me the syllabus" -Agent: [Loads working memory, knows we're talking about CS004] - "Here's the syllabus for CS004..." - -Turn 4 (new session, same student): -User: "What courses did I ask about before?" -Agent: [Loads long-term memory, finds CS004 from auto-extraction] - "You previously asked about CS004 (Web Development)..." -``` - -## 🔧 Implementation Details - -### Memory Nodes - -**1. Load Working Memory Node** -- Runs at the start of each turn -- Retrieves conversation history from Agent Memory Server -- Adds previous messages to state for context - -**2. Save Working Memory Node** -- Runs at the end of each turn -- Converts LangChain messages to MemoryMessage format -- Saves to Agent Memory Server -- Triggers automatic extraction to long-term memory - -### State Updates - -Added fields to `AgentState`: -```python -session_id: str # Session identifier for continuity -student_id: str # User identifier -working_memory_loaded: bool # Track if memory was loaded -conversation_history: List[Dict] # Previous messages from working memory -``` - -### Workflow Changes - -```python -# Memory integration -workflow.set_entry_point("load_memory") # Start by loading memory -workflow.add_edge("load_memory", "classify_intent") -# ... existing Stage 4 nodes ... -workflow.add_edge("synthesize", "save_memory") # End by saving memory -workflow.add_edge("save_memory", END) -``` - -## 📝 Additional Usage Examples - -**Single query**: -```bash -python cli.py --student-id alice --session-id session_001 "What is CS004?" -``` - -**Interactive multi-turn conversation**: -```bash -python cli.py --student-id alice --session-id session_001 -``` - -**Resume previous session**: -```bash -# Same session_id loads previous conversation -python cli.py --student-id alice --session-id session_001 -``` - -## 🎓 Learning Objectives - -After studying this stage, you should understand: - -1. **Working Memory Pattern** - - Session-scoped conversation storage - - Load → Process → Save lifecycle - - Difference from LangGraph checkpointing - -2. **Memory Integration with RAG** - - How memory complements retrieval - - When to use memory vs. search - - Combining conversation context with retrieved data - -3. **Agent Memory Server** - - Automatic extraction to long-term memory - - Memory deduplication and compaction - - Semantic search over memories - -4. **Multi-turn Conversations** - - Building context across turns - - Handling follow-up questions - - Session management - -## 🔍 Key Differences from Reference Agent - -The reference agent (`redis_context_course/agent.py`) includes: -- Long-term memory tools (search_memories, store_memory) -- LangGraph checkpointing for graph state persistence -- More complex tool orchestration - -Stage 5 focuses on: -- **Working memory only** (simpler, more focused) -- No long-term memory tools (auto-extraction handles it) -- No checkpointing (not needed for this demo) -- Educational clarity over production features - -## 🔍 Code References & Automatic Behaviors - -This section provides exact code references for the combined ReAct + Memory implementation. - -### Code References - -**ReAct Pattern (from Stage 4):** - -| Concept | File | Lines | Description | -|---------|------|-------|-------------| -| ReAct Agent | `progressive_agents/stage5_working_memory/agent/react_agent.py` | All | ReAct loop with memory context | -| ReAct Prompts | `progressive_agents/stage5_working_memory/agent/react_prompts.py` | All | System prompt with memory awareness | - -**Working Memory:** - -| Concept | File | Lines | Description | -|---------|------|-------|-------------| -| Load Memory Node | `progressive_agents/stage5_working_memory/agent/nodes.py` | `load_working_memory_node()` | Retrieves conversation history | -| Save Memory Node | `progressive_agents/stage5_working_memory/agent/nodes.py` | `save_working_memory_node()` | Persists conversation | - -### Automatic Behaviors (Agent Memory Server) - -| Behavior | How It Works | Configuration | -|----------|--------------|---------------| -| **Automatic Compression** | Truncation, sliding window, summarization | `WINDOW_SIZE`, `MemoryStrategyConfig` | -| **Automatic Extraction** | Extracts facts from working to long-term memory | Runs on `put_working_memory()` | -| **Memory Deduplication** | Prevents duplicate memories | Built into Agent Memory Server | - -See **[Section 3, Notebook 3](../../notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb)** for detailed configuration. - ---- - -## 🔗 Related Resources - -### Learning Path Navigation -- **Previous**: [Stage 4: Hybrid Search](../stage4_hybrid_search/) - Hybrid search with ReAct (no memory) -- **Next**: [Stage 6: Full Memory](../stage6_full_memory/) - Adds long-term memory tools for cross-session personalization - -### Notebooks to Study -- **[Section 3: Working and Long-term Memory](../../notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb)**: Memory fundamentals -- **[Section 3: Managing Long Conversations](../../notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb)**: Compression strategies (automatic behaviors) -- **[Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb)**: ReAct pattern - -### Technical Resources -- **Reference Agent**: Production-ready implementation with full memory architecture -- **Agent Memory Server**: https://github.com/redis/agent-memory-server - diff --git a/progressive_agents/stage6_full_memory/README.md b/progressive_agents/stage6_full_memory/README.md deleted file mode 100644 index 1fcd844..0000000 --- a/progressive_agents/stage6_full_memory/README.md +++ /dev/null @@ -1,508 +0,0 @@ -# Stage 6: Full Memory (Working + Long-term) - -## 📍 Position in Learning Path - -| Previous | Current | Next | -|----------|---------|------| -| [Stage 5: Working Memory](../stage5_working_memory/) | **Stage 6: Full Memory** | — (Final Stage) | - -The **final stage** combining all features: **working memory**, **long-term memory tools**, and **visible ReAct reasoning**. - ---- - -## 🎯 Purpose - -This is the culmination of the progressive agents learning path. It combines: -- **Working Memory** (from Stage 5): Session-based conversation history -- **Long-term Memory Tools**: Explicit tools to store and query cross-session facts -- **ReAct Pattern** (from Stage 4): Visible reasoning - -**Key Learning**: "A production-ready agent combines working memory, long-term memory tools, and transparent reasoning." - -**Tools**: `search_courses`, `search_memories`, `store_memory` (3 tools) - ---- - -## 📚 Related Notebooks - -This stage demonstrates concepts from all notebook sections: - -| Notebook | Concepts Applied | Implementation in This Stage | -|----------|-----------------|------------------------------| -| [Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb) | ReAct pattern | `react_agent.py: ReActAgent` | -| [Section 3: Working and Long-term Memory](../../notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb) | Both memory types | `nodes.py`, `tools.py` | -| [Section 3: Combining Memory with Retrieved Context](../../notebooks/section-3-memory-systems/02_combining_memory_with_retrieved_context.ipynb) | Memory + RAG | Agent combines all sources | -| [Section 4: Building Course Advisor Agent](../../notebooks/section-4-tools-and-agents/02_building_course_advisor_agent.ipynb) | Multi-tool agents | 3 tools with decision-making | -| [Section 2: Crafting and Optimizing Context](../../notebooks/section-2-retrieved-context-engineering/02_crafting_and_optimizing_context.ipynb) | Progressive disclosure | `HierarchicalContextAssembler` | - -### Key Notebook Concepts Demonstrated - -**From Section 4, Notebook 1 - "Tools and LangGraph Fundamentals":** -- **ReAct Pattern**: Thought → Action → Observation loop -- **Visible Reasoning**: Debug-friendly decision traces - -**From Section 3, Notebooks 1-2 - Memory Systems:** -- **Working Memory**: Session-scoped conversation storage -- **Long-term Memory**: Cross-session preference persistence -- **Memory + RAG**: Combining all context sources - -**From Section 4, Notebook 2 - "Building Course Advisor Agent":** -- **Multi-Tool Decision Making**: LLM chooses between 3 tools -- **Tool Composition**: Combining memory + search in single turn - -**Study Path**: This stage integrates all previous concepts. Review earlier stages and notebooks to understand each component. - ---- - -## 🔄 What Changed from Stage 5 - -| Feature | Stage 5 (Working Memory) | Stage 6 (Full Memory) | -|---------|--------------------------|----------------------| -| **Working Memory** | Yes (session-based) | Yes (session-based) | -| **Long-term Memory Tools** | No (auto-extraction only) | **Yes (`search_memories`, `store_memory`)** | -| **Tools** | 1 (`search_courses`) | **3** (`search_courses`, `search_memories`, `store_memory`) | -| **Reasoning** | Visible (ReAct) | Visible (ReAct) | -| **Personalization** | Within session only | **Cross-session** | - ---- - -## 🏗️ Architecture - -```mermaid -graph TD - Q[Query] --> LM[Load Working Memory] - LM --> IC[Classify Intent] - IC -->|GREETING| HG[Handle Greeting] - IC -->|Other| RA[ReAct Agent] - - subgraph ReAct Loop - RA --> T1[💭 Thought: Analyze + plan] - T1 --> A1[🔧 Action: choose tool] - A1 --> O1[👁️ Observation: Results] - O1 --> T2[💭 Thought: Evaluate] - T2 --> |Need more| A1 - T2 --> |Done| F[✅ FINISH] - end - - subgraph Available Tools - A1 -->|search| SC[search_courses] - A1 -->|store| RM[remember_user_info] - A1 -->|recall| RC[recall_user_info] - end - - F --> SM[Save Working Memory] - HG --> SM - SM --> END[Response + Reasoning Trace] - - subgraph Memory Layer - LM -.->|Read| AMS[(Agent Memory Server)] - SM -.->|Write| AMS - RM -.->|Write| LTM[(Long-term Memory)] - RC -.->|Read| LTM - end -``` - -## 🔧 Available Tools - -| Tool | Purpose | Example Trigger | -|------|---------|-----------------| -| **search_courses** | Search course catalog | "Find ML courses" | -| **remember_user_info** | Store to long-term memory | "I prefer online courses" | -| **recall_user_info** | Search long-term memory | "What did I say I liked?" | - -## 🚀 Usage - -### Prerequisites - -1. **Install the package** (from repository root): - ```bash - pip install -e . - ``` - -2. **Set environment variables**: - ```bash - export OPENAI_API_KEY="your-openai-api-key" - export REDIS_URL="redis://localhost:6379" - export AGENT_MEMORY_URL="http://localhost:8088" # Optional, defaults to this - ``` - -3. **Start Agent Memory Server** (required for this stage): - ```bash - # Check if running - curl http://localhost:8088/v1/health - - # Start if needed (see main README for docker-compose setup) - docker-compose up -d agent-memory-server - ``` - -### Running the Agent - -From the repository root: - -```bash -cd progressive_agents/stage6_full_memory - -# Store a preference (uses store_memory tool) -python cli.py --student-id alice --show-reasoning "I prefer online courses" - -# Query using stored preference (uses search_memories + search_courses) -python cli.py --student-id alice --show-reasoning "What courses do you recommend?" - -# Interactive mode -python cli.py --student-id alice -``` - -## 📝 Example: Full Pipeline with Reasoning - -``` -User: "I prefer online courses. What ML courses do you recommend?" - -🧠 Reasoning Trace: -================================================================================ -💭 Thought: The user expressed a preference AND asked for recommendations. - I should store the preference first, then search for courses. - -🔧 Action: remember_user_info - Input: {"user_id": "alice", "info_type": "preference", "info": "prefers online courses"} -👁️ Observation: Successfully stored user preference. - -💭 Thought: Now I should search for ML courses, filtering for online format. - -🔧 Action: search_courses - Input: {"query": "machine learning", "intent": "GENERAL", "search_strategy": "hybrid"} -👁️ Observation: Found 5 courses: CS010 (ML Fundamentals), CS011 (Deep Learning), ... - -💭 Thought: I have courses and stored the preference. I can provide recommendations. - -✅ FINISH -================================================================================ - -Answer: I've noted your preference for online courses! Here are some ML courses available online: - 1. CS010 - Machine Learning Fundamentals (Advanced, 4 credits) - 2. CS011 - Deep Learning and Neural Networks (Advanced, 4 credits) - ... -``` - -## 📁 File Structure - -``` -stage6_full_memory/ -├── cli.py # CLI with --show-reasoning -├── README.md # This file -└── agent/ - ├── __init__.py - ├── react_agent.py # ReAct loop implementation - ├── react_parser.py # Thought/Action/Observation parser - ├── react_prompts.py # System prompt with 3 tools - ├── nodes.py # Memory nodes + react_agent_node - ├── tools.py # search_courses, remember, recall - ├── state.py # WorkflowState with reasoning_trace - ├── setup.py # Initialization - └── workflow.py # LangGraph graph -``` - -## ⬅️ Previous Stages - -- **Stage 5** (`stage5_working_memory/`): ReAct + working memory (no long-term tools) -- **Stage 4** (`stage4_hybrid_search/`): ReAct + hybrid search (no memory) -- **Stage 3** (`stage3_full_agent_without_memory/`): Basic agent with tool calling - -**Important:** `--student-id` is required for this stage! This identifies the student for long-term memory storage. - -### Example Conversations - -#### Session 1: Store Preferences - -``` -User: "Hi! I'm interested in machine learning. I prefer online courses." - -Agent: -1. store_memory("Student is interested in machine learning", topics=["interests", "ML"]) -2. store_memory("Student prefers online course format", topics=["preferences", "format"]) -3. search_courses("machine learning") - -Response: "I've noted that you're interested in machine learning and prefer online courses! -Here are some ML courses available online: [course list]" -``` - -#### Session 2: Personalized Recommendations (New Session) - -``` -User: "What courses would you recommend?" - -Agent: -1. search_memories("student preferences and interests") - → Returns: "interested in ML", "prefers online" -2. search_courses("machine learning", ...) - -Response: "Based on your interest in machine learning and preference for online courses, -I recommend: [personalized course list]" -``` - ---- - -## Testing - -### Run Memory Tools Test Suite - -```bash -python test_memory_tools.py -``` - -This tests: -- ✅ Storing student preferences -- ✅ Retrieving memories in new session -- ✅ Multi-tool decision-making -- ✅ Cross-session persistence - -### Run Simple Tests - -```bash -python test_simple.py -``` - ---- - -## Implementation Details - -### Memory Tools - -#### search_memories_tool - -```python -@tool("search_memories", args_schema=SearchMemoriesInput) -async def search_memories_tool(query: str, limit: int = 5) -> str: - """Search student's long-term memory for preferences and facts.""" -``` - -**Parameters:** -- `query`: Natural language query (e.g., "career goals", "preferences") -- `limit`: Max number of memories to return (default: 5) - -**Returns:** Formatted list of memories with topics - -#### store_memory_tool - -```python -@tool("store_memory", args_schema=StoreMemoryInput) -async def store_memory_tool( - text: str, - memory_type: str = "semantic", - topics: List[str] = [] -) -> str: - """Store important information to student's long-term memory.""" -``` - -**Parameters:** -- `text`: Information to store (e.g., "Student prefers online courses") -- `memory_type`: "semantic" (facts) or "episodic" (events) -- `topics`: Tags for organization (e.g., ["preferences", "format"]) - -**Returns:** Confirmation message - ---- - -## Educational Value - -### What This Stage Teaches - -1. **Long-term Memory Tools** - - How to implement memory search/store as LangChain tools - - When to use long-term vs working memory - - Memory types (semantic vs episodic) - -2. **Multi-Tool Decision Making** - - LLM decides between 3 tools - - Tool selection based on query intent - - Combining multiple tools in single turn - -3. **Personalization Patterns** - - Storing user preferences - - Retrieving context for personalization - - Cross-session continuity - -4. **Memory Management** - - What to store (preferences, goals, constraints) - - What NOT to store (temporary info, course details) - - Using topics for organization - ---- - -## Files Modified from Stage 5 - -| File | Changes | Lines Added | -|------|---------|-------------| -| `agent/tools.py` | Added 2 new tools + schemas | ~160 lines | -| `agent/nodes.py` | Updated tool binding + system prompt | ~30 lines | -| `agent/workflow.py` | Updated docstring | ~2 lines | -| `cli.py` | Updated titles | ~5 lines | - -**Total:** ~200 lines of code added - ---- - -## Troubleshooting - -### "Error: Student ID not set" - -**Cause:** `student_id` not passed to `run_agent_async()` - -**Solution:** Always provide `student_id` parameter: -```python -result = await run_agent_async( - agent=agent, - query=query, - session_id=session_id, - student_id="alice", # Required! - enable_caching=False, -) -``` - -### "No relevant memories found" - -**Cause:** No memories stored yet for this student - -**Solution:** First share preferences to store memories: -``` -User: "I prefer online courses and I'm interested in ML" -``` - -### Agent Memory Server not available - -**Cause:** Agent Memory Server not running - -**Solution:** Start the server: -```bash -# Check if running -curl http://localhost:8088/health - -# Start if needed (see Agent Memory Server docs) -``` - ---- - -## 🔍 Code References & Automatic Behaviors - -This section provides a comprehensive summary of all code references and automatic behaviors across the entire progressive agents learning path. - -### ReAct Loop Implementation - -**Code References:** - -| Concept | File | Lines | Description | -|---------|------|-------|-------------| -| ReAct Agent Node | `progressive_agents/stage6_full_memory/agent/react_agent.py` | 91-265 | `react_agent_node()` - main ReAct loop | -| Thought → Action → Observation | `progressive_agents/stage6_full_memory/agent/react_agent.py` | 153-226 | Loop iteration with parsing and execution | -| Tool Execution | `progressive_agents/stage6_full_memory/agent/react_agent.py` | 41-88 | `execute_react_tool()` - dispatches to tools | -| ReAct Prompts | `progressive_agents/stage6_full_memory/agent/react_prompts.py` | All | System prompt with ReAct format | -| Output Parser | `progressive_agents/stage6_full_memory/agent/react_parser.py` | All | Parses Thought/Action/Observation | -| Node Integration | `progressive_agents/stage6_full_memory/agent/nodes.py` | 1087-1090 | Imports and aliases `react_agent_node` | - -**ReAct Loop Pattern:** - -```python -# From progressive_agents/stage6_full_memory/agent/react_agent.py (lines 91-230) -async def react_agent_node(state: WorkflowState) -> WorkflowState: - """ReAct agent node with explicit Thought → Action → Observation loop.""" - - for iteration in range(max_iterations): - # 1. Get LLM response with Thought + Action - response = await llm.ainvoke(messages) - parsed = parse_react_output(response.content) - - # 2. Log Thought - if parsed["thought"]: - reasoning_trace.append({"type": "thought", "content": parsed["thought"]}) - - # 3. Check for FINISH action - if parsed["action"].upper() == "FINISH": - final_answer = extract_final_answer(parsed["action_input"]) - break - - # 4. Execute tool and get Observation - tool_result = await execute_react_tool(action, action_input, student_id) - observation = format_observation(tool_result, max_length=8000) - - # 5. Add to messages for next iteration - messages.append(AIMessage(content=response.content)) - messages.append(HumanMessage(content=f"\n{observation}\n")) -``` - -### Complete Automatic Behaviors Summary - -Stage 6 inherits all automatic behaviors from previous stages: - -| Behavior | Source | How It Works | -|----------|--------|--------------| -| **Progressive Disclosure** | Stage 3 (`HierarchicalContextAssembler`) | Summaries for all, details for top N | -| **"Lost in the Middle" Mitigation** | Stage 3 (context structure) | Header → Summaries → Details | -| **Hybrid Search Fallback** | Stage 4 (`search_courses_sync`) | Falls back to semantic if exact match fails | -| **Automatic Compression** | Stage 5 (Agent Memory Server) | Truncation, sliding window, summarization | -| **Automatic Extraction** | Stage 5 (Agent Memory Server) | Extracts facts from working to long-term memory | -| **Memory Deduplication** | Stage 6 (Agent Memory Server) | Prevents duplicate memories | -| **Semantic Indexing** | Stage 6 (Agent Memory Server) | Creates embeddings for memory search | - -### All Code References by Stage - -**Stage 3 - Progressive Disclosure:** -- `src/redis_context_course/hierarchical_context.py` (lines 16-100): `HierarchicalContextAssembler` - -**Stage 4 - Hybrid Search:** -- `progressive_agents/stage4_hybrid_search/agent/tools.py`: Search strategies - -**Stage 5 - Working Memory:** -- `progressive_agents/stage5_working_memory/agent/nodes.py`: Load/save memory nodes - -**Stage 6 - Full Memory (Working + Long-term) + ReAct:** -- `progressive_agents/stage6_full_memory/agent/tools.py`: Memory tools (`search_memories`, `store_memory`) -- `progressive_agents/stage6_full_memory/agent/react_agent.py`: ReAct implementation - -### Agent Memory Server Configuration - -The Agent Memory Server supports these configuration options (using defaults in progressive agents): - -```python -# Available but using defaults in progressive agents -MemoryStrategyConfig( - strategy="summary", # Compression strategy - max_summary_length=500, # Max tokens for summary - message_threshold=20, # Summarize after N messages - token_threshold=4000, # Summarize after N tokens - keep_recent=4, # Keep N recent messages -) - -# Environment variable for window size -WINDOW_SIZE=100 # Max messages in working memory -``` - -See **[Section 3, Notebook 3](../../notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb)** for detailed configuration examples. - ---- - -## 🔗 Related Resources - -### Learning Path Summary -This is the **final stage**. You've learned: -- **Stages 1-2**: Context engineering fundamentals -- **Stage 3**: LangGraph agent architecture + progressive disclosure -- **Stage 4**: Hybrid search with NER + ReAct visible reasoning -- **Stage 5**: Working memory + ReAct -- **Stage 6**: All features combined (long-term memory + ReAct) - -### Notebooks to Review -- **[Section 1: What is Context Engineering?](../../notebooks/section-1-context-engineering-foundations/01_what_is_context_engineering.ipynb)**: Foundation concepts -- **[Section 3: Working and Long-term Memory](../../notebooks/section-3-memory-systems/01_working_and_longterm_memory.ipynb)**: Memory fundamentals -- **[Section 3: Managing Long Conversations](../../notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb)**: Automatic compression behaviors -- **[Section 4: Tools and LangGraph Fundamentals](../../notebooks/section-4-tools-and-agents/01_tools_and_langgraph_fundamentals.ipynb)**: ReAct pattern -- **[Section 4: Building Course Advisor Agent](../../notebooks/section-4-tools-and-agents/02_building_course_advisor_agent.ipynb)**: Complete agent architecture - -### Technical Resources -- **Agent Memory Server**: https://github.com/redis/agent-memory-server -- **LangGraph Documentation**: https://langchain-ai.github.io/langgraph/ - -### What's Next? -After completing Stage 6, explore: -- **[Section 4: Semantic Tool Selection](../../notebooks/section-4-tools-and-agents/04_semantic_tool_selection.ipynb)**: Scaling to more tools (RedisVL SemanticRouter) -- **[Section 3: Managing Long Conversations](../../notebooks/section-3-memory-systems/03_manage_long_conversations_with_compression_strategies.ipynb)**: Explicit compression configuration -- **Reference Agent**: Production-ready implementation in `reference-agent/` - diff --git a/pyproject.toml b/pyproject.toml index 6ba4f7d..f4593d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,13 @@ generate-courses = "redis_context_course.scripts.generate_courses:main" generate-hierarchical-courses = "redis_context_course.scripts.generate_hierarchical_courses:main" ingest-courses = "redis_context_course.scripts.ingest_courses:main" load-hierarchical-courses = "redis_context_course.scripts.load_hierarchical_courses:main" +# Agent demo stages +1-baseline-rag = "demos.stage1_baseline_rag.cli:main" +2-context-engineered = "demos.stage2_context_engineered.cli:main" +3-langgraph-agent = "demos.stage3_full_agent_without_memory.cli:run" +4-hybrid-react = "demos.stage4_hybrid_search.cli:run" +5-working-memory = "demos.stage5_working_memory.cli:run" +6-full-memory = "demos.stage6_full_memory.cli:run" [project.urls] Homepage = "https://github.com/redis-developer/redis-ai-resources" @@ -97,7 +104,7 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] -packages = ["src/redis_context_course"] +packages = ["src/redis_context_course", "demos"] [tool.ruff] line-length = 88 diff --git a/src/redis_context_course/course_manager.py b/src/redis_context_course/course_manager.py index f73a8b0..2b6bcea 100644 --- a/src/redis_context_course/course_manager.py +++ b/src/redis_context_course/course_manager.py @@ -115,7 +115,7 @@ async def store_course(self, course: Course) -> str: return course.id - # EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use + # EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Code typically uses get_course_by_code() instead async def get_course(self, course_id: str) -> Optional[Course]: """Retrieve a course by ID.""" diff --git a/src/redis_context_course/hierarchical_context.py b/src/redis_context_course/hierarchical_context.py index 0fb0a0b..01764ca 100644 --- a/src/redis_context_course/hierarchical_context.py +++ b/src/redis_context_course/hierarchical_context.py @@ -184,13 +184,13 @@ def _format_details(self, details: CourseDetails) -> str: return "\n".join(sections) + "\n" - # EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use + # EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use def estimate_tokens(self, text: str) -> int: """Estimate token count (rough approximation).""" # Rough estimate: 1 token ≈ 4 characters return len(text) // 4 - # EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use + # EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use def assemble_with_budget( self, summaries: List[CourseSummary], @@ -226,7 +226,7 @@ def assemble_with_budget( return context, estimated -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use class FlatContextAssembler: """ Traditional flat context assembly (for comparison). diff --git a/src/redis_context_course/hierarchical_manager.py b/src/redis_context_course/hierarchical_manager.py index 4fa0a62..30d4ff0 100644 --- a/src/redis_context_course/hierarchical_manager.py +++ b/src/redis_context_course/hierarchical_manager.py @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # This class is used only by scripts/load_hierarchical_courses.py for data loading class HierarchicalCourseManager: """ diff --git a/src/redis_context_course/optimization_helpers.py b/src/redis_context_course/optimization_helpers.py index 97c2a07..4cd0d12 100644 --- a/src/redis_context_course/optimization_helpers.py +++ b/src/redis_context_course/optimization_helpers.py @@ -16,7 +16,7 @@ from langchain_openai import ChatOpenAI -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Token Counting (from Section 4, notebook 01_context_window_management.ipynb) # Notebooks implement inline versions for educational clarity def count_tokens(text: str, model: str = "gpt-4o") -> int: @@ -38,7 +38,7 @@ def count_tokens(text: str, model: str = "gpt-4o") -> int: return len(encoding.encode(text)) -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Notebooks implement inline versions for educational clarity def estimate_token_budget( system_prompt: str, @@ -88,7 +88,7 @@ def estimate_token_budget( } -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Retrieval Strategies (from Section 4, notebook 02_retrieval_strategies.ipynb) async def hybrid_retrieval( query: str, summary_view: str, search_function, limit: int = 3 @@ -120,7 +120,7 @@ async def hybrid_retrieval( return context -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Structured Views (from Section 4, notebook 05_crafting_data_for_llms.ipynb) async def create_summary_view( items: List[Any], @@ -169,7 +169,7 @@ async def create_summary_view( return "\n".join(summary_parts) -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use async def create_user_profile_view( user_data: Dict[str, Any], memories: List[Any], llm: ChatOpenAI ) -> str: @@ -229,7 +229,7 @@ async def create_user_profile_view( return "\n".join(profile_parts) -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Tool Optimization (from Section 4, notebook 04_tool_optimization.ipynb) def filter_tools_by_intent( query: str, tool_groups: Dict[str, List], default_group: str = "search" @@ -266,7 +266,7 @@ def filter_tools_by_intent( return tool_groups.get(default_group, []) -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use async def classify_intent_with_llm( query: str, intents: List[str], llm: ChatOpenAI ) -> str: @@ -310,7 +310,7 @@ async def classify_intent_with_llm( return intent -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Grounding Helpers (from Section 4, notebook 03_grounding_with_memory.ipynb) def extract_references(query: str) -> Dict[str, List[str]]: """ @@ -352,7 +352,7 @@ def extract_references(query: str) -> Dict[str, List[str]]: return references -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Utility Functions def format_context_for_llm( system_instructions: str, diff --git a/src/redis_context_course/redis_config.py b/src/redis_context_course/redis_config.py index 09f3acc..e412bf3 100644 --- a/src/redis_context_course/redis_config.py +++ b/src/redis_context_course/redis_config.py @@ -114,7 +114,7 @@ def health_check(self) -> bool: except Exception: return False - # EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use + # EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use def cleanup(self): """Clean up connections.""" if self._redis_client: diff --git a/src/redis_context_course/semantic_tool_selector.py b/src/redis_context_course/semantic_tool_selector.py index c29b1ca..50aab42 100644 --- a/src/redis_context_course/semantic_tool_selector.py +++ b/src/redis_context_course/semantic_tool_selector.py @@ -43,7 +43,7 @@ class ToolIntent: confidence_threshold: float = 0.6 -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Note: Notebooks implement their own inline version for educational clarity class SemanticToolSelector: """ @@ -348,7 +348,7 @@ def get_tool_coverage(self) -> Dict[str, Any]: } -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Utility function for easy integration async def create_semantic_selector(tools: List[BaseTool]) -> SemanticToolSelector: """ diff --git a/src/redis_context_course/tools.py b/src/redis_context_course/tools.py index f0f1297..d7024a4 100644 --- a/src/redis_context_course/tools.py +++ b/src/redis_context_course/tools.py @@ -2,7 +2,7 @@ Tools for the Redis University Class Agent. This module defines the tools that the agent can use to interact with -the course catalog and student data. These tools are used in the notebooks +the course catalog and student data. These tools are used in the workshop notebooks throughout the course. """ @@ -50,16 +50,16 @@ class CheckPrerequisitesInput(BaseModel): ) -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Notebooks and agents create tools inline for educational clarity # Course Tools def create_course_tools(course_manager: CourseManager): """ Create course-related tools. - These tools are demonstrated in Section 2 notebooks. + These tools are demonstrated in the workshop notebooks. - Note: This is experimental API surface. Notebooks and progressive_agents + Note: This is experimental API surface. Workshop notebooks and demos implement tools inline for educational purposes. """ @@ -182,7 +182,7 @@ async def check_prerequisites( return [search_courses, get_course_details, check_prerequisites] -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Memory Tools def create_memory_tools(memory_client: MemoryAPIClient, session_id: str, user_id: str): """ @@ -209,7 +209,7 @@ def create_memory_tools(memory_client: MemoryAPIClient, session_id: str, user_id ) -# EXPERIMENTAL: Not currently used in notebooks or progressive_agents but available for external use +# EXPERIMENTAL: Not currently used in workshop notebooks or demos but available for external use # Tool Selection Helpers (from Section 4, notebook 04_tool_optimization.ipynb) def select_tools_by_keywords(query: str, all_tools: dict) -> List: """ diff --git a/tests/test_tools.py b/tests/test_tools.py index 8b4579d..b8e6da1 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -66,4 +66,4 @@ def test_select_tools_by_keywords(): # NOTE: Agent-specific tool tests have been removed. # The tools are now available via create_agent_tools() in tools.py -# Use the progressive_agents stages for testing full agent functionality. +# Use the demos stages for testing full agent functionality. diff --git a/uv.lock b/uv.lock index 7ea5759..3ed1a6a 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 1 requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.14'", @@ -18,18 +18,18 @@ dependencies = [ { name = "pydantic" }, { name = "python-ulid" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c5/71/b14715ac459ef7a621dea7d03b1401577360fce26f834ac6f91c09588a34/agent_memory_client-0.13.0.tar.gz", hash = "sha256:bb0cccf55272b771c8fe67dcbba2e927341d6ef5e4a4ee86a6f30faf5abba9bc", size = 73493, upload-time = "2025-10-16T16:49:00.699Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/71/b14715ac459ef7a621dea7d03b1401577360fce26f834ac6f91c09588a34/agent_memory_client-0.13.0.tar.gz", hash = "sha256:bb0cccf55272b771c8fe67dcbba2e927341d6ef5e4a4ee86a6f30faf5abba9bc", size = 73493 } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/c0/ea9edfc29cbd617a3efb2309e83f667ad3b5d0aa2d1ed4b81a5ce65b42e8/agent_memory_client-0.13.0-py3-none-any.whl", hash = "sha256:401a8d06f99bc280f169dfb95876ae2dd90ec7e149af0897f26cac625202fd31", size = 39716, upload-time = "2025-10-16T16:48:59.26Z" }, + { url = "https://files.pythonhosted.org/packages/86/c0/ea9edfc29cbd617a3efb2309e83f667ad3b5d0aa2d1ed4b81a5ce65b42e8/agent_memory_client-0.13.0-py3-none-any.whl", hash = "sha256:401a8d06f99bc280f169dfb95876ae2dd90ec7e149af0897f26cac625202fd31", size = 39716 }, ] [[package]] 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 } 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 }, ] [[package]] @@ -46,110 +46,110 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994, upload-time = "2025-10-28T20:59:39.937Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/34/939730e66b716b76046dedfe0842995842fa906ccc4964bba414ff69e429/aiohttp-3.13.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2372b15a5f62ed37789a6b383ff7344fc5b9f243999b0cd9b629d8bc5f5b4155", size = 736471, upload-time = "2025-10-28T20:55:27.924Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/dcbdf2df7f6ca72b0bb4c0b4509701f2d8942cf54e29ca197389c214c07f/aiohttp-3.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7f8659a48995edee7229522984bd1009c1213929c769c2daa80b40fe49a180c", size = 493985, upload-time = "2025-10-28T20:55:29.456Z" }, - { url = "https://files.pythonhosted.org/packages/9d/87/71c8867e0a1d0882dcbc94af767784c3cb381c1c4db0943ab4aae4fed65e/aiohttp-3.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:939ced4a7add92296b0ad38892ce62b98c619288a081170695c6babe4f50e636", size = 489274, upload-time = "2025-10-28T20:55:31.134Z" }, - { url = "https://files.pythonhosted.org/packages/38/0f/46c24e8dae237295eaadd113edd56dee96ef6462adf19b88592d44891dc5/aiohttp-3.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6315fb6977f1d0dd41a107c527fee2ed5ab0550b7d885bc15fee20ccb17891da", size = 1668171, upload-time = "2025-10-28T20:55:36.065Z" }, - { url = "https://files.pythonhosted.org/packages/eb/c6/4cdfb4440d0e28483681a48f69841fa5e39366347d66ef808cbdadddb20e/aiohttp-3.13.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e7352512f763f760baaed2637055c49134fd1d35b37c2dedfac35bfe5cf8725", size = 1636036, upload-time = "2025-10-28T20:55:37.576Z" }, - { url = "https://files.pythonhosted.org/packages/84/37/8708cf678628216fb678ab327a4e1711c576d6673998f4f43e86e9ae90dd/aiohttp-3.13.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e09a0a06348a2dd73e7213353c90d709502d9786219f69b731f6caa0efeb46f5", size = 1727975, upload-time = "2025-10-28T20:55:39.457Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2e/3ebfe12fdcb9b5f66e8a0a42dffcd7636844c8a018f261efb2419f68220b/aiohttp-3.13.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a09a6d073fb5789456545bdee2474d14395792faa0527887f2f4ec1a486a59d3", size = 1815823, upload-time = "2025-10-28T20:55:40.958Z" }, - { url = "https://files.pythonhosted.org/packages/a1/4f/ca2ef819488cbb41844c6cf92ca6dd15b9441e6207c58e5ae0e0fc8d70ad/aiohttp-3.13.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b59d13c443f8e049d9e94099c7e412e34610f1f49be0f230ec656a10692a5802", size = 1669374, upload-time = "2025-10-28T20:55:42.745Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fe/1fe2e1179a0d91ce09c99069684aab619bf2ccde9b20bd6ca44f8837203e/aiohttp-3.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:20db2d67985d71ca033443a1ba2001c4b5693fe09b0e29f6d9358a99d4d62a8a", size = 1555315, upload-time = "2025-10-28T20:55:44.264Z" }, - { url = "https://files.pythonhosted.org/packages/5a/2b/f3781899b81c45d7cbc7140cddb8a3481c195e7cbff8e36374759d2ab5a5/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:960c2fc686ba27b535f9fd2b52d87ecd7e4fd1cf877f6a5cba8afb5b4a8bd204", size = 1639140, upload-time = "2025-10-28T20:55:46.626Z" }, - { url = "https://files.pythonhosted.org/packages/72/27/c37e85cd3ece6f6c772e549bd5a253d0c122557b25855fb274224811e4f2/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6c00dbcf5f0d88796151e264a8eab23de2997c9303dd7c0bf622e23b24d3ce22", size = 1645496, upload-time = "2025-10-28T20:55:48.933Z" }, - { url = "https://files.pythonhosted.org/packages/66/20/3af1ab663151bd3780b123e907761cdb86ec2c4e44b2d9b195ebc91fbe37/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fed38a5edb7945f4d1bcabe2fcd05db4f6ec7e0e82560088b754f7e08d93772d", size = 1697625, upload-time = "2025-10-28T20:55:50.377Z" }, - { url = "https://files.pythonhosted.org/packages/95/eb/ae5cab15efa365e13d56b31b0d085a62600298bf398a7986f8388f73b598/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:b395bbca716c38bef3c764f187860e88c724b342c26275bc03e906142fc5964f", size = 1542025, upload-time = "2025-10-28T20:55:51.861Z" }, - { url = "https://files.pythonhosted.org/packages/e9/2d/1683e8d67ec72d911397fe4e575688d2a9b8f6a6e03c8fdc9f3fd3d4c03f/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:204ffff2426c25dfda401ba08da85f9c59525cdc42bda26660463dd1cbcfec6f", size = 1714918, upload-time = "2025-10-28T20:55:53.515Z" }, - { url = "https://files.pythonhosted.org/packages/99/a2/ffe8e0e1c57c5e542d47ffa1fcf95ef2b3ea573bf7c4d2ee877252431efc/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05c4dd3c48fb5f15db31f57eb35374cb0c09afdde532e7fb70a75aede0ed30f6", size = 1656113, upload-time = "2025-10-28T20:55:55.438Z" }, - { url = "https://files.pythonhosted.org/packages/0d/42/d511aff5c3a2b06c09d7d214f508a4ad8ac7799817f7c3d23e7336b5e896/aiohttp-3.13.2-cp310-cp310-win32.whl", hash = "sha256:e574a7d61cf10351d734bcddabbe15ede0eaa8a02070d85446875dc11189a251", size = 432290, upload-time = "2025-10-28T20:55:56.96Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ea/1c2eb7098b5bad4532994f2b7a8228d27674035c9b3234fe02c37469ef14/aiohttp-3.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:364f55663085d658b8462a1c3f17b2b84a5c2e1ba858e1b79bff7b2e24ad1514", size = 455075, upload-time = "2025-10-28T20:55:58.373Z" }, - { url = "https://files.pythonhosted.org/packages/35/74/b321e7d7ca762638cdf8cdeceb39755d9c745aff7a64c8789be96ddf6e96/aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0", size = 743409, upload-time = "2025-10-28T20:56:00.354Z" }, - { url = "https://files.pythonhosted.org/packages/99/3d/91524b905ec473beaf35158d17f82ef5a38033e5809fe8742e3657cdbb97/aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb", size = 497006, upload-time = "2025-10-28T20:56:01.85Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d3/7f68bc02a67716fe80f063e19adbd80a642e30682ce74071269e17d2dba1/aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9", size = 493195, upload-time = "2025-10-28T20:56:03.314Z" }, - { url = "https://files.pythonhosted.org/packages/98/31/913f774a4708775433b7375c4f867d58ba58ead833af96c8af3621a0d243/aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613", size = 1747759, upload-time = "2025-10-28T20:56:04.904Z" }, - { url = "https://files.pythonhosted.org/packages/e8/63/04efe156f4326f31c7c4a97144f82132c3bb21859b7bb84748d452ccc17c/aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead", size = 1704456, upload-time = "2025-10-28T20:56:06.986Z" }, - { url = "https://files.pythonhosted.org/packages/8e/02/4e16154d8e0a9cf4ae76f692941fd52543bbb148f02f098ca73cab9b1c1b/aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780", size = 1807572, upload-time = "2025-10-28T20:56:08.558Z" }, - { url = "https://files.pythonhosted.org/packages/34/58/b0583defb38689e7f06798f0285b1ffb3a6fb371f38363ce5fd772112724/aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a", size = 1895954, upload-time = "2025-10-28T20:56:10.545Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f3/083907ee3437425b4e376aa58b2c915eb1a33703ec0dc30040f7ae3368c6/aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592", size = 1747092, upload-time = "2025-10-28T20:56:12.118Z" }, - { url = "https://files.pythonhosted.org/packages/ac/61/98a47319b4e425cc134e05e5f3fc512bf9a04bf65aafd9fdcda5d57ec693/aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab", size = 1606815, upload-time = "2025-10-28T20:56:14.191Z" }, - { url = "https://files.pythonhosted.org/packages/97/4b/e78b854d82f66bb974189135d31fce265dee0f5344f64dd0d345158a5973/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30", size = 1723789, upload-time = "2025-10-28T20:56:16.101Z" }, - { url = "https://files.pythonhosted.org/packages/ed/fc/9d2ccc794fc9b9acd1379d625c3a8c64a45508b5091c546dea273a41929e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40", size = 1718104, upload-time = "2025-10-28T20:56:17.655Z" }, - { url = "https://files.pythonhosted.org/packages/66/65/34564b8765ea5c7d79d23c9113135d1dd3609173da13084830f1507d56cf/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948", size = 1785584, upload-time = "2025-10-28T20:56:19.238Z" }, - { url = "https://files.pythonhosted.org/packages/30/be/f6a7a426e02fc82781afd62016417b3948e2207426d90a0e478790d1c8a4/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf", size = 1595126, upload-time = "2025-10-28T20:56:20.836Z" }, - { url = "https://files.pythonhosted.org/packages/e5/c7/8e22d5d28f94f67d2af496f14a83b3c155d915d1fe53d94b66d425ec5b42/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782", size = 1800665, upload-time = "2025-10-28T20:56:22.922Z" }, - { url = "https://files.pythonhosted.org/packages/d1/11/91133c8b68b1da9fc16555706aa7276fdf781ae2bb0876c838dd86b8116e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8", size = 1739532, upload-time = "2025-10-28T20:56:25.924Z" }, - { url = "https://files.pythonhosted.org/packages/17/6b/3747644d26a998774b21a616016620293ddefa4d63af6286f389aedac844/aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec", size = 431876, upload-time = "2025-10-28T20:56:27.524Z" }, - { url = "https://files.pythonhosted.org/packages/c3/63/688462108c1a00eb9f05765331c107f95ae86f6b197b865d29e930b7e462/aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c", size = 456205, upload-time = "2025-10-28T20:56:29.062Z" }, - { url = "https://files.pythonhosted.org/packages/29/9b/01f00e9856d0a73260e86dd8ed0c2234a466c5c1712ce1c281548df39777/aiohttp-3.13.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b1e56bab2e12b2b9ed300218c351ee2a3d8c8fdab5b1ec6193e11a817767e47b", size = 737623, upload-time = "2025-10-28T20:56:30.797Z" }, - { url = "https://files.pythonhosted.org/packages/5a/1b/4be39c445e2b2bd0aab4ba736deb649fabf14f6757f405f0c9685019b9e9/aiohttp-3.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:364e25edaabd3d37b1db1f0cbcee8c73c9a3727bfa262b83e5e4cf3489a2a9dc", size = 492664, upload-time = "2025-10-28T20:56:32.708Z" }, - { url = "https://files.pythonhosted.org/packages/28/66/d35dcfea8050e131cdd731dff36434390479b4045a8d0b9d7111b0a968f1/aiohttp-3.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c94825f744694c4b8db20b71dba9a257cd2ba8e010a803042123f3a25d50d7", size = 491808, upload-time = "2025-10-28T20:56:34.57Z" }, - { url = "https://files.pythonhosted.org/packages/00/29/8e4609b93e10a853b65f8291e64985de66d4f5848c5637cddc70e98f01f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba2715d842ffa787be87cbfce150d5e88c87a98e0b62e0f5aa489169a393dbbb", size = 1738863, upload-time = "2025-10-28T20:56:36.377Z" }, - { url = "https://files.pythonhosted.org/packages/9d/fa/4ebdf4adcc0def75ced1a0d2d227577cd7b1b85beb7edad85fcc87693c75/aiohttp-3.13.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:585542825c4bc662221fb257889e011a5aa00f1ae4d75d1d246a5225289183e3", size = 1700586, upload-time = "2025-10-28T20:56:38.034Z" }, - { url = "https://files.pythonhosted.org/packages/da/04/73f5f02ff348a3558763ff6abe99c223381b0bace05cd4530a0258e52597/aiohttp-3.13.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39d02cb6025fe1aabca329c5632f48c9532a3dabccd859e7e2f110668972331f", size = 1768625, upload-time = "2025-10-28T20:56:39.75Z" }, - { url = "https://files.pythonhosted.org/packages/f8/49/a825b79ffec124317265ca7d2344a86bcffeb960743487cb11988ffb3494/aiohttp-3.13.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e67446b19e014d37342f7195f592a2a948141d15a312fe0e700c2fd2f03124f6", size = 1867281, upload-time = "2025-10-28T20:56:41.471Z" }, - { url = "https://files.pythonhosted.org/packages/b9/48/adf56e05f81eac31edcfae45c90928f4ad50ef2e3ea72cb8376162a368f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4356474ad6333e41ccefd39eae869ba15a6c5299c9c01dfdcfdd5c107be4363e", size = 1752431, upload-time = "2025-10-28T20:56:43.162Z" }, - { url = "https://files.pythonhosted.org/packages/30/ab/593855356eead019a74e862f21523db09c27f12fd24af72dbc3555b9bfd9/aiohttp-3.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeacf451c99b4525f700f078becff32c32ec327b10dcf31306a8a52d78166de7", size = 1562846, upload-time = "2025-10-28T20:56:44.85Z" }, - { url = "https://files.pythonhosted.org/packages/39/0f/9f3d32271aa8dc35036e9668e31870a9d3b9542dd6b3e2c8a30931cb27ae/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8a9b889aeabd7a4e9af0b7f4ab5ad94d42e7ff679aaec6d0db21e3b639ad58d", size = 1699606, upload-time = "2025-10-28T20:56:46.519Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3c/52d2658c5699b6ef7692a3f7128b2d2d4d9775f2a68093f74bca06cf01e1/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fa89cb11bc71a63b69568d5b8a25c3ca25b6d54c15f907ca1c130d72f320b76b", size = 1720663, upload-time = "2025-10-28T20:56:48.528Z" }, - { url = "https://files.pythonhosted.org/packages/9b/d4/8f8f3ff1fb7fb9e3f04fcad4e89d8a1cd8fc7d05de67e3de5b15b33008ff/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8aa7c807df234f693fed0ecd507192fc97692e61fee5702cdc11155d2e5cadc8", size = 1737939, upload-time = "2025-10-28T20:56:50.77Z" }, - { url = "https://files.pythonhosted.org/packages/03/d3/ddd348f8a27a634daae39a1b8e291ff19c77867af438af844bf8b7e3231b/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9eb3e33fdbe43f88c3c75fa608c25e7c47bbd80f48d012763cb67c47f39a7e16", size = 1555132, upload-time = "2025-10-28T20:56:52.568Z" }, - { url = "https://files.pythonhosted.org/packages/39/b8/46790692dc46218406f94374903ba47552f2f9f90dad554eed61bfb7b64c/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9434bc0d80076138ea986833156c5a48c9c7a8abb0c96039ddbb4afc93184169", size = 1764802, upload-time = "2025-10-28T20:56:54.292Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e4/19ce547b58ab2a385e5f0b8aa3db38674785085abcf79b6e0edd1632b12f/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff15c147b2ad66da1f2cbb0622313f2242d8e6e8f9b79b5206c84523a4473248", size = 1719512, upload-time = "2025-10-28T20:56:56.428Z" }, - { url = "https://files.pythonhosted.org/packages/70/30/6355a737fed29dcb6dfdd48682d5790cb5eab050f7b4e01f49b121d3acad/aiohttp-3.13.2-cp312-cp312-win32.whl", hash = "sha256:27e569eb9d9e95dbd55c0fc3ec3a9335defbf1d8bc1d20171a49f3c4c607b93e", size = 426690, upload-time = "2025-10-28T20:56:58.736Z" }, - { url = "https://files.pythonhosted.org/packages/0a/0d/b10ac09069973d112de6ef980c1f6bb31cb7dcd0bc363acbdad58f927873/aiohttp-3.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:8709a0f05d59a71f33fd05c17fc11fcb8c30140506e13c2f5e8ee1b8964e1b45", size = 453465, upload-time = "2025-10-28T20:57:00.795Z" }, - { url = "https://files.pythonhosted.org/packages/bf/78/7e90ca79e5aa39f9694dcfd74f4720782d3c6828113bb1f3197f7e7c4a56/aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be", size = 732139, upload-time = "2025-10-28T20:57:02.455Z" }, - { url = "https://files.pythonhosted.org/packages/db/ed/1f59215ab6853fbaa5c8495fa6cbc39edfc93553426152b75d82a5f32b76/aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742", size = 490082, upload-time = "2025-10-28T20:57:04.784Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/fe0fe0f5e05e13629d893c760465173a15ad0039c0a5b0d0040995c8075e/aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293", size = 489035, upload-time = "2025-10-28T20:57:06.894Z" }, - { url = "https://files.pythonhosted.org/packages/d2/04/db5279e38471b7ac801d7d36a57d1230feeee130bbe2a74f72731b23c2b1/aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811", size = 1720387, upload-time = "2025-10-28T20:57:08.685Z" }, - { url = "https://files.pythonhosted.org/packages/31/07/8ea4326bd7dae2bd59828f69d7fdc6e04523caa55e4a70f4a8725a7e4ed2/aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a", size = 1688314, upload-time = "2025-10-28T20:57:10.693Z" }, - { url = "https://files.pythonhosted.org/packages/48/ab/3d98007b5b87ffd519d065225438cc3b668b2f245572a8cb53da5dd2b1bc/aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4", size = 1756317, upload-time = "2025-10-28T20:57:12.563Z" }, - { url = "https://files.pythonhosted.org/packages/97/3d/801ca172b3d857fafb7b50c7c03f91b72b867a13abca982ed6b3081774ef/aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a", size = 1858539, upload-time = "2025-10-28T20:57:14.623Z" }, - { url = "https://files.pythonhosted.org/packages/f7/0d/4764669bdf47bd472899b3d3db91fffbe925c8e3038ec591a2fd2ad6a14d/aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e", size = 1739597, upload-time = "2025-10-28T20:57:16.399Z" }, - { url = "https://files.pythonhosted.org/packages/c4/52/7bd3c6693da58ba16e657eb904a5b6decfc48ecd06e9ac098591653b1566/aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb", size = 1555006, upload-time = "2025-10-28T20:57:18.288Z" }, - { url = "https://files.pythonhosted.org/packages/48/30/9586667acec5993b6f41d2ebcf96e97a1255a85f62f3c653110a5de4d346/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded", size = 1683220, upload-time = "2025-10-28T20:57:20.241Z" }, - { url = "https://files.pythonhosted.org/packages/71/01/3afe4c96854cfd7b30d78333852e8e851dceaec1c40fd00fec90c6402dd2/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b", size = 1712570, upload-time = "2025-10-28T20:57:22.253Z" }, - { url = "https://files.pythonhosted.org/packages/11/2c/22799d8e720f4697a9e66fd9c02479e40a49de3de2f0bbe7f9f78a987808/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8", size = 1733407, upload-time = "2025-10-28T20:57:24.37Z" }, - { url = "https://files.pythonhosted.org/packages/34/cb/90f15dd029f07cebbd91f8238a8b363978b530cd128488085b5703683594/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04", size = 1550093, upload-time = "2025-10-28T20:57:26.257Z" }, - { url = "https://files.pythonhosted.org/packages/69/46/12dce9be9d3303ecbf4d30ad45a7683dc63d90733c2d9fe512be6716cd40/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476", size = 1758084, upload-time = "2025-10-28T20:57:28.349Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c8/0932b558da0c302ffd639fc6362a313b98fdf235dc417bc2493da8394df7/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23", size = 1716987, upload-time = "2025-10-28T20:57:30.233Z" }, - { url = "https://files.pythonhosted.org/packages/5d/8b/f5bd1a75003daed099baec373aed678f2e9b34f2ad40d85baa1368556396/aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254", size = 425859, upload-time = "2025-10-28T20:57:32.105Z" }, - { url = "https://files.pythonhosted.org/packages/5d/28/a8a9fc6957b2cee8902414e41816b5ab5536ecf43c3b1843c10e82c559b2/aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a", size = 452192, upload-time = "2025-10-28T20:57:34.166Z" }, - { url = "https://files.pythonhosted.org/packages/9b/36/e2abae1bd815f01c957cbf7be817b3043304e1c87bad526292a0410fdcf9/aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b", size = 735234, upload-time = "2025-10-28T20:57:36.415Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e3/1ee62dde9b335e4ed41db6bba02613295a0d5b41f74a783c142745a12763/aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61", size = 490733, upload-time = "2025-10-28T20:57:38.205Z" }, - { url = "https://files.pythonhosted.org/packages/1a/aa/7a451b1d6a04e8d15a362af3e9b897de71d86feac3babf8894545d08d537/aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4", size = 491303, upload-time = "2025-10-28T20:57:40.122Z" }, - { url = "https://files.pythonhosted.org/packages/57/1e/209958dbb9b01174870f6a7538cd1f3f28274fdbc88a750c238e2c456295/aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b", size = 1717965, upload-time = "2025-10-28T20:57:42.28Z" }, - { url = "https://files.pythonhosted.org/packages/08/aa/6a01848d6432f241416bc4866cae8dc03f05a5a884d2311280f6a09c73d6/aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694", size = 1667221, upload-time = "2025-10-28T20:57:44.869Z" }, - { url = "https://files.pythonhosted.org/packages/87/4f/36c1992432d31bbc789fa0b93c768d2e9047ec8c7177e5cd84ea85155f36/aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906", size = 1757178, upload-time = "2025-10-28T20:57:47.216Z" }, - { url = "https://files.pythonhosted.org/packages/ac/b4/8e940dfb03b7e0f68a82b88fd182b9be0a65cb3f35612fe38c038c3112cf/aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9", size = 1838001, upload-time = "2025-10-28T20:57:49.337Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ef/39f3448795499c440ab66084a9db7d20ca7662e94305f175a80f5b7e0072/aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011", size = 1716325, upload-time = "2025-10-28T20:57:51.327Z" }, - { url = "https://files.pythonhosted.org/packages/d7/51/b311500ffc860b181c05d91c59a1313bdd05c82960fdd4035a15740d431e/aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6", size = 1547978, upload-time = "2025-10-28T20:57:53.554Z" }, - { url = "https://files.pythonhosted.org/packages/31/64/b9d733296ef79815226dab8c586ff9e3df41c6aff2e16c06697b2d2e6775/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213", size = 1682042, upload-time = "2025-10-28T20:57:55.617Z" }, - { url = "https://files.pythonhosted.org/packages/3f/30/43d3e0f9d6473a6db7d472104c4eff4417b1e9df01774cb930338806d36b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49", size = 1680085, upload-time = "2025-10-28T20:57:57.59Z" }, - { url = "https://files.pythonhosted.org/packages/16/51/c709f352c911b1864cfd1087577760ced64b3e5bee2aa88b8c0c8e2e4972/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae", size = 1728238, upload-time = "2025-10-28T20:57:59.525Z" }, - { url = "https://files.pythonhosted.org/packages/19/e2/19bd4c547092b773caeb48ff5ae4b1ae86756a0ee76c16727fcfd281404b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa", size = 1544395, upload-time = "2025-10-28T20:58:01.914Z" }, - { url = "https://files.pythonhosted.org/packages/cf/87/860f2803b27dfc5ed7be532832a3498e4919da61299b4a1f8eb89b8ff44d/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4", size = 1742965, upload-time = "2025-10-28T20:58:03.972Z" }, - { url = "https://files.pythonhosted.org/packages/67/7f/db2fc7618925e8c7a601094d5cbe539f732df4fb570740be88ed9e40e99a/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a", size = 1697585, upload-time = "2025-10-28T20:58:06.189Z" }, - { url = "https://files.pythonhosted.org/packages/0c/07/9127916cb09bb38284db5036036042b7b2c514c8ebaeee79da550c43a6d6/aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940", size = 431621, upload-time = "2025-10-28T20:58:08.636Z" }, - { url = "https://files.pythonhosted.org/packages/fb/41/554a8a380df6d3a2bba8a7726429a23f4ac62aaf38de43bb6d6cde7b4d4d/aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4", size = 457627, upload-time = "2025-10-28T20:58:11Z" }, - { url = "https://files.pythonhosted.org/packages/c7/8e/3824ef98c039d3951cb65b9205a96dd2b20f22241ee17d89c5701557c826/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673", size = 767360, upload-time = "2025-10-28T20:58:13.358Z" }, - { url = "https://files.pythonhosted.org/packages/a4/0f/6a03e3fc7595421274fa34122c973bde2d89344f8a881b728fa8c774e4f1/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd", size = 504616, upload-time = "2025-10-28T20:58:15.339Z" }, - { url = "https://files.pythonhosted.org/packages/c6/aa/ed341b670f1bc8a6f2c6a718353d13b9546e2cef3544f573c6a1ff0da711/aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3", size = 509131, upload-time = "2025-10-28T20:58:17.693Z" }, - { url = "https://files.pythonhosted.org/packages/7f/f0/c68dac234189dae5c4bbccc0f96ce0cc16b76632cfc3a08fff180045cfa4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf", size = 1864168, upload-time = "2025-10-28T20:58:20.113Z" }, - { url = "https://files.pythonhosted.org/packages/8f/65/75a9a76db8364b5d0e52a0c20eabc5d52297385d9af9c35335b924fafdee/aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e", size = 1719200, upload-time = "2025-10-28T20:58:22.583Z" }, - { url = "https://files.pythonhosted.org/packages/f5/55/8df2ed78d7f41d232f6bd3ff866b6f617026551aa1d07e2f03458f964575/aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5", size = 1843497, upload-time = "2025-10-28T20:58:24.672Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e0/94d7215e405c5a02ccb6a35c7a3a6cfff242f457a00196496935f700cde5/aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad", size = 1935703, upload-time = "2025-10-28T20:58:26.758Z" }, - { url = "https://files.pythonhosted.org/packages/0b/78/1eeb63c3f9b2d1015a4c02788fb543141aad0a03ae3f7a7b669b2483f8d4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e", size = 1792738, upload-time = "2025-10-28T20:58:29.787Z" }, - { url = "https://files.pythonhosted.org/packages/41/75/aaf1eea4c188e51538c04cc568040e3082db263a57086ea74a7d38c39e42/aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61", size = 1624061, upload-time = "2025-10-28T20:58:32.529Z" }, - { url = "https://files.pythonhosted.org/packages/9b/c2/3b6034de81fbcc43de8aeb209073a2286dfb50b86e927b4efd81cf848197/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661", size = 1789201, upload-time = "2025-10-28T20:58:34.618Z" }, - { url = "https://files.pythonhosted.org/packages/c9/38/c15dcf6d4d890217dae79d7213988f4e5fe6183d43893a9cf2fe9e84ca8d/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98", size = 1776868, upload-time = "2025-10-28T20:58:38.835Z" }, - { url = "https://files.pythonhosted.org/packages/04/75/f74fd178ac81adf4f283a74847807ade5150e48feda6aef024403716c30c/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693", size = 1790660, upload-time = "2025-10-28T20:58:41.507Z" }, - { url = "https://files.pythonhosted.org/packages/e7/80/7368bd0d06b16b3aba358c16b919e9c46cf11587dc572091031b0e9e3ef0/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a", size = 1617548, upload-time = "2025-10-28T20:58:43.674Z" }, - { url = "https://files.pythonhosted.org/packages/7d/4b/a6212790c50483cb3212e507378fbe26b5086d73941e1ec4b56a30439688/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be", size = 1817240, upload-time = "2025-10-28T20:58:45.787Z" }, - { url = "https://files.pythonhosted.org/packages/ff/f7/ba5f0ba4ea8d8f3c32850912944532b933acbf0f3a75546b89269b9b7dde/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c", size = 1762334, upload-time = "2025-10-28T20:58:47.936Z" }, - { url = "https://files.pythonhosted.org/packages/7e/83/1a5a1856574588b1cad63609ea9ad75b32a8353ac995d830bf5da9357364/aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734", size = 464685, upload-time = "2025-10-28T20:58:50.642Z" }, - { url = "https://files.pythonhosted.org/packages/9f/4d/d22668674122c08f4d56972297c51a624e64b3ed1efaa40187607a7cb66e/aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f", size = 498093, upload-time = "2025-10-28T20:58:52.782Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/34/939730e66b716b76046dedfe0842995842fa906ccc4964bba414ff69e429/aiohttp-3.13.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2372b15a5f62ed37789a6b383ff7344fc5b9f243999b0cd9b629d8bc5f5b4155", size = 736471 }, + { url = "https://files.pythonhosted.org/packages/fd/cf/dcbdf2df7f6ca72b0bb4c0b4509701f2d8942cf54e29ca197389c214c07f/aiohttp-3.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7f8659a48995edee7229522984bd1009c1213929c769c2daa80b40fe49a180c", size = 493985 }, + { url = "https://files.pythonhosted.org/packages/9d/87/71c8867e0a1d0882dcbc94af767784c3cb381c1c4db0943ab4aae4fed65e/aiohttp-3.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:939ced4a7add92296b0ad38892ce62b98c619288a081170695c6babe4f50e636", size = 489274 }, + { url = "https://files.pythonhosted.org/packages/38/0f/46c24e8dae237295eaadd113edd56dee96ef6462adf19b88592d44891dc5/aiohttp-3.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6315fb6977f1d0dd41a107c527fee2ed5ab0550b7d885bc15fee20ccb17891da", size = 1668171 }, + { url = "https://files.pythonhosted.org/packages/eb/c6/4cdfb4440d0e28483681a48f69841fa5e39366347d66ef808cbdadddb20e/aiohttp-3.13.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e7352512f763f760baaed2637055c49134fd1d35b37c2dedfac35bfe5cf8725", size = 1636036 }, + { url = "https://files.pythonhosted.org/packages/84/37/8708cf678628216fb678ab327a4e1711c576d6673998f4f43e86e9ae90dd/aiohttp-3.13.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e09a0a06348a2dd73e7213353c90d709502d9786219f69b731f6caa0efeb46f5", size = 1727975 }, + { url = "https://files.pythonhosted.org/packages/e6/2e/3ebfe12fdcb9b5f66e8a0a42dffcd7636844c8a018f261efb2419f68220b/aiohttp-3.13.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a09a6d073fb5789456545bdee2474d14395792faa0527887f2f4ec1a486a59d3", size = 1815823 }, + { url = "https://files.pythonhosted.org/packages/a1/4f/ca2ef819488cbb41844c6cf92ca6dd15b9441e6207c58e5ae0e0fc8d70ad/aiohttp-3.13.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b59d13c443f8e049d9e94099c7e412e34610f1f49be0f230ec656a10692a5802", size = 1669374 }, + { url = "https://files.pythonhosted.org/packages/f8/fe/1fe2e1179a0d91ce09c99069684aab619bf2ccde9b20bd6ca44f8837203e/aiohttp-3.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:20db2d67985d71ca033443a1ba2001c4b5693fe09b0e29f6d9358a99d4d62a8a", size = 1555315 }, + { url = "https://files.pythonhosted.org/packages/5a/2b/f3781899b81c45d7cbc7140cddb8a3481c195e7cbff8e36374759d2ab5a5/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:960c2fc686ba27b535f9fd2b52d87ecd7e4fd1cf877f6a5cba8afb5b4a8bd204", size = 1639140 }, + { url = "https://files.pythonhosted.org/packages/72/27/c37e85cd3ece6f6c772e549bd5a253d0c122557b25855fb274224811e4f2/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6c00dbcf5f0d88796151e264a8eab23de2997c9303dd7c0bf622e23b24d3ce22", size = 1645496 }, + { url = "https://files.pythonhosted.org/packages/66/20/3af1ab663151bd3780b123e907761cdb86ec2c4e44b2d9b195ebc91fbe37/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fed38a5edb7945f4d1bcabe2fcd05db4f6ec7e0e82560088b754f7e08d93772d", size = 1697625 }, + { url = "https://files.pythonhosted.org/packages/95/eb/ae5cab15efa365e13d56b31b0d085a62600298bf398a7986f8388f73b598/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:b395bbca716c38bef3c764f187860e88c724b342c26275bc03e906142fc5964f", size = 1542025 }, + { url = "https://files.pythonhosted.org/packages/e9/2d/1683e8d67ec72d911397fe4e575688d2a9b8f6a6e03c8fdc9f3fd3d4c03f/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:204ffff2426c25dfda401ba08da85f9c59525cdc42bda26660463dd1cbcfec6f", size = 1714918 }, + { url = "https://files.pythonhosted.org/packages/99/a2/ffe8e0e1c57c5e542d47ffa1fcf95ef2b3ea573bf7c4d2ee877252431efc/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05c4dd3c48fb5f15db31f57eb35374cb0c09afdde532e7fb70a75aede0ed30f6", size = 1656113 }, + { url = "https://files.pythonhosted.org/packages/0d/42/d511aff5c3a2b06c09d7d214f508a4ad8ac7799817f7c3d23e7336b5e896/aiohttp-3.13.2-cp310-cp310-win32.whl", hash = "sha256:e574a7d61cf10351d734bcddabbe15ede0eaa8a02070d85446875dc11189a251", size = 432290 }, + { url = "https://files.pythonhosted.org/packages/8b/ea/1c2eb7098b5bad4532994f2b7a8228d27674035c9b3234fe02c37469ef14/aiohttp-3.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:364f55663085d658b8462a1c3f17b2b84a5c2e1ba858e1b79bff7b2e24ad1514", size = 455075 }, + { url = "https://files.pythonhosted.org/packages/35/74/b321e7d7ca762638cdf8cdeceb39755d9c745aff7a64c8789be96ddf6e96/aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0", size = 743409 }, + { url = "https://files.pythonhosted.org/packages/99/3d/91524b905ec473beaf35158d17f82ef5a38033e5809fe8742e3657cdbb97/aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb", size = 497006 }, + { url = "https://files.pythonhosted.org/packages/eb/d3/7f68bc02a67716fe80f063e19adbd80a642e30682ce74071269e17d2dba1/aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9", size = 493195 }, + { url = "https://files.pythonhosted.org/packages/98/31/913f774a4708775433b7375c4f867d58ba58ead833af96c8af3621a0d243/aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613", size = 1747759 }, + { url = "https://files.pythonhosted.org/packages/e8/63/04efe156f4326f31c7c4a97144f82132c3bb21859b7bb84748d452ccc17c/aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead", size = 1704456 }, + { url = "https://files.pythonhosted.org/packages/8e/02/4e16154d8e0a9cf4ae76f692941fd52543bbb148f02f098ca73cab9b1c1b/aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780", size = 1807572 }, + { url = "https://files.pythonhosted.org/packages/34/58/b0583defb38689e7f06798f0285b1ffb3a6fb371f38363ce5fd772112724/aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a", size = 1895954 }, + { url = "https://files.pythonhosted.org/packages/6b/f3/083907ee3437425b4e376aa58b2c915eb1a33703ec0dc30040f7ae3368c6/aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592", size = 1747092 }, + { url = "https://files.pythonhosted.org/packages/ac/61/98a47319b4e425cc134e05e5f3fc512bf9a04bf65aafd9fdcda5d57ec693/aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab", size = 1606815 }, + { url = "https://files.pythonhosted.org/packages/97/4b/e78b854d82f66bb974189135d31fce265dee0f5344f64dd0d345158a5973/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30", size = 1723789 }, + { url = "https://files.pythonhosted.org/packages/ed/fc/9d2ccc794fc9b9acd1379d625c3a8c64a45508b5091c546dea273a41929e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40", size = 1718104 }, + { url = "https://files.pythonhosted.org/packages/66/65/34564b8765ea5c7d79d23c9113135d1dd3609173da13084830f1507d56cf/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948", size = 1785584 }, + { url = "https://files.pythonhosted.org/packages/30/be/f6a7a426e02fc82781afd62016417b3948e2207426d90a0e478790d1c8a4/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf", size = 1595126 }, + { url = "https://files.pythonhosted.org/packages/e5/c7/8e22d5d28f94f67d2af496f14a83b3c155d915d1fe53d94b66d425ec5b42/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782", size = 1800665 }, + { url = "https://files.pythonhosted.org/packages/d1/11/91133c8b68b1da9fc16555706aa7276fdf781ae2bb0876c838dd86b8116e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8", size = 1739532 }, + { url = "https://files.pythonhosted.org/packages/17/6b/3747644d26a998774b21a616016620293ddefa4d63af6286f389aedac844/aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec", size = 431876 }, + { url = "https://files.pythonhosted.org/packages/c3/63/688462108c1a00eb9f05765331c107f95ae86f6b197b865d29e930b7e462/aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c", size = 456205 }, + { url = "https://files.pythonhosted.org/packages/29/9b/01f00e9856d0a73260e86dd8ed0c2234a466c5c1712ce1c281548df39777/aiohttp-3.13.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b1e56bab2e12b2b9ed300218c351ee2a3d8c8fdab5b1ec6193e11a817767e47b", size = 737623 }, + { url = "https://files.pythonhosted.org/packages/5a/1b/4be39c445e2b2bd0aab4ba736deb649fabf14f6757f405f0c9685019b9e9/aiohttp-3.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:364e25edaabd3d37b1db1f0cbcee8c73c9a3727bfa262b83e5e4cf3489a2a9dc", size = 492664 }, + { url = "https://files.pythonhosted.org/packages/28/66/d35dcfea8050e131cdd731dff36434390479b4045a8d0b9d7111b0a968f1/aiohttp-3.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c94825f744694c4b8db20b71dba9a257cd2ba8e010a803042123f3a25d50d7", size = 491808 }, + { url = "https://files.pythonhosted.org/packages/00/29/8e4609b93e10a853b65f8291e64985de66d4f5848c5637cddc70e98f01f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba2715d842ffa787be87cbfce150d5e88c87a98e0b62e0f5aa489169a393dbbb", size = 1738863 }, + { url = "https://files.pythonhosted.org/packages/9d/fa/4ebdf4adcc0def75ced1a0d2d227577cd7b1b85beb7edad85fcc87693c75/aiohttp-3.13.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:585542825c4bc662221fb257889e011a5aa00f1ae4d75d1d246a5225289183e3", size = 1700586 }, + { url = "https://files.pythonhosted.org/packages/da/04/73f5f02ff348a3558763ff6abe99c223381b0bace05cd4530a0258e52597/aiohttp-3.13.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39d02cb6025fe1aabca329c5632f48c9532a3dabccd859e7e2f110668972331f", size = 1768625 }, + { url = "https://files.pythonhosted.org/packages/f8/49/a825b79ffec124317265ca7d2344a86bcffeb960743487cb11988ffb3494/aiohttp-3.13.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e67446b19e014d37342f7195f592a2a948141d15a312fe0e700c2fd2f03124f6", size = 1867281 }, + { url = "https://files.pythonhosted.org/packages/b9/48/adf56e05f81eac31edcfae45c90928f4ad50ef2e3ea72cb8376162a368f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4356474ad6333e41ccefd39eae869ba15a6c5299c9c01dfdcfdd5c107be4363e", size = 1752431 }, + { url = "https://files.pythonhosted.org/packages/30/ab/593855356eead019a74e862f21523db09c27f12fd24af72dbc3555b9bfd9/aiohttp-3.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeacf451c99b4525f700f078becff32c32ec327b10dcf31306a8a52d78166de7", size = 1562846 }, + { url = "https://files.pythonhosted.org/packages/39/0f/9f3d32271aa8dc35036e9668e31870a9d3b9542dd6b3e2c8a30931cb27ae/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8a9b889aeabd7a4e9af0b7f4ab5ad94d42e7ff679aaec6d0db21e3b639ad58d", size = 1699606 }, + { url = "https://files.pythonhosted.org/packages/2c/3c/52d2658c5699b6ef7692a3f7128b2d2d4d9775f2a68093f74bca06cf01e1/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fa89cb11bc71a63b69568d5b8a25c3ca25b6d54c15f907ca1c130d72f320b76b", size = 1720663 }, + { url = "https://files.pythonhosted.org/packages/9b/d4/8f8f3ff1fb7fb9e3f04fcad4e89d8a1cd8fc7d05de67e3de5b15b33008ff/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8aa7c807df234f693fed0ecd507192fc97692e61fee5702cdc11155d2e5cadc8", size = 1737939 }, + { url = "https://files.pythonhosted.org/packages/03/d3/ddd348f8a27a634daae39a1b8e291ff19c77867af438af844bf8b7e3231b/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9eb3e33fdbe43f88c3c75fa608c25e7c47bbd80f48d012763cb67c47f39a7e16", size = 1555132 }, + { url = "https://files.pythonhosted.org/packages/39/b8/46790692dc46218406f94374903ba47552f2f9f90dad554eed61bfb7b64c/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9434bc0d80076138ea986833156c5a48c9c7a8abb0c96039ddbb4afc93184169", size = 1764802 }, + { url = "https://files.pythonhosted.org/packages/ba/e4/19ce547b58ab2a385e5f0b8aa3db38674785085abcf79b6e0edd1632b12f/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff15c147b2ad66da1f2cbb0622313f2242d8e6e8f9b79b5206c84523a4473248", size = 1719512 }, + { url = "https://files.pythonhosted.org/packages/70/30/6355a737fed29dcb6dfdd48682d5790cb5eab050f7b4e01f49b121d3acad/aiohttp-3.13.2-cp312-cp312-win32.whl", hash = "sha256:27e569eb9d9e95dbd55c0fc3ec3a9335defbf1d8bc1d20171a49f3c4c607b93e", size = 426690 }, + { url = "https://files.pythonhosted.org/packages/0a/0d/b10ac09069973d112de6ef980c1f6bb31cb7dcd0bc363acbdad58f927873/aiohttp-3.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:8709a0f05d59a71f33fd05c17fc11fcb8c30140506e13c2f5e8ee1b8964e1b45", size = 453465 }, + { url = "https://files.pythonhosted.org/packages/bf/78/7e90ca79e5aa39f9694dcfd74f4720782d3c6828113bb1f3197f7e7c4a56/aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be", size = 732139 }, + { url = "https://files.pythonhosted.org/packages/db/ed/1f59215ab6853fbaa5c8495fa6cbc39edfc93553426152b75d82a5f32b76/aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742", size = 490082 }, + { url = "https://files.pythonhosted.org/packages/68/7b/fe0fe0f5e05e13629d893c760465173a15ad0039c0a5b0d0040995c8075e/aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293", size = 489035 }, + { url = "https://files.pythonhosted.org/packages/d2/04/db5279e38471b7ac801d7d36a57d1230feeee130bbe2a74f72731b23c2b1/aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811", size = 1720387 }, + { url = "https://files.pythonhosted.org/packages/31/07/8ea4326bd7dae2bd59828f69d7fdc6e04523caa55e4a70f4a8725a7e4ed2/aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a", size = 1688314 }, + { url = "https://files.pythonhosted.org/packages/48/ab/3d98007b5b87ffd519d065225438cc3b668b2f245572a8cb53da5dd2b1bc/aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4", size = 1756317 }, + { url = "https://files.pythonhosted.org/packages/97/3d/801ca172b3d857fafb7b50c7c03f91b72b867a13abca982ed6b3081774ef/aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a", size = 1858539 }, + { url = "https://files.pythonhosted.org/packages/f7/0d/4764669bdf47bd472899b3d3db91fffbe925c8e3038ec591a2fd2ad6a14d/aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e", size = 1739597 }, + { url = "https://files.pythonhosted.org/packages/c4/52/7bd3c6693da58ba16e657eb904a5b6decfc48ecd06e9ac098591653b1566/aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb", size = 1555006 }, + { url = "https://files.pythonhosted.org/packages/48/30/9586667acec5993b6f41d2ebcf96e97a1255a85f62f3c653110a5de4d346/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded", size = 1683220 }, + { url = "https://files.pythonhosted.org/packages/71/01/3afe4c96854cfd7b30d78333852e8e851dceaec1c40fd00fec90c6402dd2/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b", size = 1712570 }, + { url = "https://files.pythonhosted.org/packages/11/2c/22799d8e720f4697a9e66fd9c02479e40a49de3de2f0bbe7f9f78a987808/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8", size = 1733407 }, + { url = "https://files.pythonhosted.org/packages/34/cb/90f15dd029f07cebbd91f8238a8b363978b530cd128488085b5703683594/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04", size = 1550093 }, + { url = "https://files.pythonhosted.org/packages/69/46/12dce9be9d3303ecbf4d30ad45a7683dc63d90733c2d9fe512be6716cd40/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476", size = 1758084 }, + { url = "https://files.pythonhosted.org/packages/f9/c8/0932b558da0c302ffd639fc6362a313b98fdf235dc417bc2493da8394df7/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23", size = 1716987 }, + { url = "https://files.pythonhosted.org/packages/5d/8b/f5bd1a75003daed099baec373aed678f2e9b34f2ad40d85baa1368556396/aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254", size = 425859 }, + { url = "https://files.pythonhosted.org/packages/5d/28/a8a9fc6957b2cee8902414e41816b5ab5536ecf43c3b1843c10e82c559b2/aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a", size = 452192 }, + { url = "https://files.pythonhosted.org/packages/9b/36/e2abae1bd815f01c957cbf7be817b3043304e1c87bad526292a0410fdcf9/aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b", size = 735234 }, + { url = "https://files.pythonhosted.org/packages/ca/e3/1ee62dde9b335e4ed41db6bba02613295a0d5b41f74a783c142745a12763/aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61", size = 490733 }, + { url = "https://files.pythonhosted.org/packages/1a/aa/7a451b1d6a04e8d15a362af3e9b897de71d86feac3babf8894545d08d537/aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4", size = 491303 }, + { url = "https://files.pythonhosted.org/packages/57/1e/209958dbb9b01174870f6a7538cd1f3f28274fdbc88a750c238e2c456295/aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b", size = 1717965 }, + { url = "https://files.pythonhosted.org/packages/08/aa/6a01848d6432f241416bc4866cae8dc03f05a5a884d2311280f6a09c73d6/aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694", size = 1667221 }, + { url = "https://files.pythonhosted.org/packages/87/4f/36c1992432d31bbc789fa0b93c768d2e9047ec8c7177e5cd84ea85155f36/aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906", size = 1757178 }, + { url = "https://files.pythonhosted.org/packages/ac/b4/8e940dfb03b7e0f68a82b88fd182b9be0a65cb3f35612fe38c038c3112cf/aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9", size = 1838001 }, + { url = "https://files.pythonhosted.org/packages/d7/ef/39f3448795499c440ab66084a9db7d20ca7662e94305f175a80f5b7e0072/aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011", size = 1716325 }, + { url = "https://files.pythonhosted.org/packages/d7/51/b311500ffc860b181c05d91c59a1313bdd05c82960fdd4035a15740d431e/aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6", size = 1547978 }, + { url = "https://files.pythonhosted.org/packages/31/64/b9d733296ef79815226dab8c586ff9e3df41c6aff2e16c06697b2d2e6775/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213", size = 1682042 }, + { url = "https://files.pythonhosted.org/packages/3f/30/43d3e0f9d6473a6db7d472104c4eff4417b1e9df01774cb930338806d36b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49", size = 1680085 }, + { url = "https://files.pythonhosted.org/packages/16/51/c709f352c911b1864cfd1087577760ced64b3e5bee2aa88b8c0c8e2e4972/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae", size = 1728238 }, + { url = "https://files.pythonhosted.org/packages/19/e2/19bd4c547092b773caeb48ff5ae4b1ae86756a0ee76c16727fcfd281404b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa", size = 1544395 }, + { url = "https://files.pythonhosted.org/packages/cf/87/860f2803b27dfc5ed7be532832a3498e4919da61299b4a1f8eb89b8ff44d/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4", size = 1742965 }, + { url = "https://files.pythonhosted.org/packages/67/7f/db2fc7618925e8c7a601094d5cbe539f732df4fb570740be88ed9e40e99a/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a", size = 1697585 }, + { url = "https://files.pythonhosted.org/packages/0c/07/9127916cb09bb38284db5036036042b7b2c514c8ebaeee79da550c43a6d6/aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940", size = 431621 }, + { url = "https://files.pythonhosted.org/packages/fb/41/554a8a380df6d3a2bba8a7726429a23f4ac62aaf38de43bb6d6cde7b4d4d/aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4", size = 457627 }, + { url = "https://files.pythonhosted.org/packages/c7/8e/3824ef98c039d3951cb65b9205a96dd2b20f22241ee17d89c5701557c826/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673", size = 767360 }, + { url = "https://files.pythonhosted.org/packages/a4/0f/6a03e3fc7595421274fa34122c973bde2d89344f8a881b728fa8c774e4f1/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd", size = 504616 }, + { url = "https://files.pythonhosted.org/packages/c6/aa/ed341b670f1bc8a6f2c6a718353d13b9546e2cef3544f573c6a1ff0da711/aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3", size = 509131 }, + { url = "https://files.pythonhosted.org/packages/7f/f0/c68dac234189dae5c4bbccc0f96ce0cc16b76632cfc3a08fff180045cfa4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf", size = 1864168 }, + { url = "https://files.pythonhosted.org/packages/8f/65/75a9a76db8364b5d0e52a0c20eabc5d52297385d9af9c35335b924fafdee/aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e", size = 1719200 }, + { url = "https://files.pythonhosted.org/packages/f5/55/8df2ed78d7f41d232f6bd3ff866b6f617026551aa1d07e2f03458f964575/aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5", size = 1843497 }, + { url = "https://files.pythonhosted.org/packages/e9/e0/94d7215e405c5a02ccb6a35c7a3a6cfff242f457a00196496935f700cde5/aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad", size = 1935703 }, + { url = "https://files.pythonhosted.org/packages/0b/78/1eeb63c3f9b2d1015a4c02788fb543141aad0a03ae3f7a7b669b2483f8d4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e", size = 1792738 }, + { url = "https://files.pythonhosted.org/packages/41/75/aaf1eea4c188e51538c04cc568040e3082db263a57086ea74a7d38c39e42/aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61", size = 1624061 }, + { url = "https://files.pythonhosted.org/packages/9b/c2/3b6034de81fbcc43de8aeb209073a2286dfb50b86e927b4efd81cf848197/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661", size = 1789201 }, + { url = "https://files.pythonhosted.org/packages/c9/38/c15dcf6d4d890217dae79d7213988f4e5fe6183d43893a9cf2fe9e84ca8d/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98", size = 1776868 }, + { url = "https://files.pythonhosted.org/packages/04/75/f74fd178ac81adf4f283a74847807ade5150e48feda6aef024403716c30c/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693", size = 1790660 }, + { url = "https://files.pythonhosted.org/packages/e7/80/7368bd0d06b16b3aba358c16b919e9c46cf11587dc572091031b0e9e3ef0/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a", size = 1617548 }, + { url = "https://files.pythonhosted.org/packages/7d/4b/a6212790c50483cb3212e507378fbe26b5086d73941e1ec4b56a30439688/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be", size = 1817240 }, + { url = "https://files.pythonhosted.org/packages/ff/f7/ba5f0ba4ea8d8f3c32850912944532b933acbf0f3a75546b89269b9b7dde/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c", size = 1762334 }, + { url = "https://files.pythonhosted.org/packages/7e/83/1a5a1856574588b1cad63609ea9ad75b32a8353ac995d830bf5da9357364/aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734", size = 464685 }, + { url = "https://files.pythonhosted.org/packages/9f/4d/d22668674122c08f4d56972297c51a624e64b3ed1efaa40187607a7cb66e/aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f", size = 498093 }, ] [[package]] @@ -160,18 +160,18 @@ dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -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 } 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 }, ] [[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 } 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 }, ] [[package]] @@ -184,18 +184,18 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094 } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097 }, ] [[package]] name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, ] [[package]] @@ -205,9 +205,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, ] [[package]] @@ -217,33 +217,33 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/3c0a35f46e52108d4707c44b95cfe2afcafc50800b5450c197454569b776/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f", size = 54393, upload-time = "2025-07-30T10:01:40.97Z" }, - { url = "https://files.pythonhosted.org/packages/9d/f4/98bbd6ee89febd4f212696f13c03ca302b8552e7dbf9c8efa11ea4a388c3/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b", size = 29328, upload-time = "2025-07-30T10:01:41.916Z" }, - { url = "https://files.pythonhosted.org/packages/43/24/90a01c0ef12ac91a6be05969f29944643bc1e5e461155ae6559befa8f00b/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a", size = 31269, upload-time = "2025-07-30T10:01:42.716Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/942aa10782b2697eee7af5e12eeff5ebb325ccfb86dd8abda54174e377e4/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44", size = 86558, upload-time = "2025-07-30T10:01:43.943Z" }, - { url = "https://files.pythonhosted.org/packages/0d/82/b484f702fec5536e71836fc2dbc8c5267b3f6e78d2d539b4eaa6f0db8bf8/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb", size = 92364, upload-time = "2025-07-30T10:01:44.887Z" }, - { url = "https://files.pythonhosted.org/packages/c9/c1/a606ff83b3f1735f3759ad0f2cd9e038a0ad11a3de3b6c673aa41c24bb7b/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92", size = 85637, upload-time = "2025-07-30T10:01:46.225Z" }, - { url = "https://files.pythonhosted.org/packages/44/b4/678503f12aceb0262f84fa201f6027ed77d71c5019ae03b399b97caa2f19/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85", size = 91934, upload-time = "2025-07-30T10:01:47.203Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c7/f36bd08ef9bd9f0a9cff9428406651f5937ce27b6c5b07b92d41f91ae541/argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f", size = 28158, upload-time = "2025-07-30T10:01:48.341Z" }, - { url = "https://files.pythonhosted.org/packages/b3/80/0106a7448abb24a2c467bf7d527fe5413b7fdfa4ad6d6a96a43a62ef3988/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6", size = 32597, upload-time = "2025-07-30T10:01:49.112Z" }, - { url = "https://files.pythonhosted.org/packages/05/b8/d663c9caea07e9180b2cb662772865230715cbd573ba3b5e81793d580316/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623", size = 28231, upload-time = "2025-07-30T10:01:49.92Z" }, - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, - { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549, upload-time = "2025-07-30T10:02:00.101Z" }, - { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539, upload-time = "2025-07-30T10:02:00.929Z" }, - { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467, upload-time = "2025-07-30T10:02:02.08Z" }, - { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355, upload-time = "2025-07-30T10:02:02.867Z" }, - { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187, upload-time = "2025-07-30T10:02:03.674Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/3c0a35f46e52108d4707c44b95cfe2afcafc50800b5450c197454569b776/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f", size = 54393 }, + { url = "https://files.pythonhosted.org/packages/9d/f4/98bbd6ee89febd4f212696f13c03ca302b8552e7dbf9c8efa11ea4a388c3/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b", size = 29328 }, + { url = "https://files.pythonhosted.org/packages/43/24/90a01c0ef12ac91a6be05969f29944643bc1e5e461155ae6559befa8f00b/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a", size = 31269 }, + { url = "https://files.pythonhosted.org/packages/d4/d3/942aa10782b2697eee7af5e12eeff5ebb325ccfb86dd8abda54174e377e4/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44", size = 86558 }, + { url = "https://files.pythonhosted.org/packages/0d/82/b484f702fec5536e71836fc2dbc8c5267b3f6e78d2d539b4eaa6f0db8bf8/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb", size = 92364 }, + { url = "https://files.pythonhosted.org/packages/c9/c1/a606ff83b3f1735f3759ad0f2cd9e038a0ad11a3de3b6c673aa41c24bb7b/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92", size = 85637 }, + { url = "https://files.pythonhosted.org/packages/44/b4/678503f12aceb0262f84fa201f6027ed77d71c5019ae03b399b97caa2f19/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85", size = 91934 }, + { url = "https://files.pythonhosted.org/packages/f0/c7/f36bd08ef9bd9f0a9cff9428406651f5937ce27b6c5b07b92d41f91ae541/argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f", size = 28158 }, + { url = "https://files.pythonhosted.org/packages/b3/80/0106a7448abb24a2c467bf7d527fe5413b7fdfa4ad6d6a96a43a62ef3988/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6", size = 32597 }, + { url = "https://files.pythonhosted.org/packages/05/b8/d663c9caea07e9180b2cb662772865230715cbd573ba3b5e81793d580316/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623", size = 28231 }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, + { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549 }, + { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539 }, + { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467 }, + { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355 }, + { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187 }, ] [[package]] @@ -254,18 +254,18 @@ dependencies = [ { name = "python-dateutil" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797 }, ] [[package]] name = "asttokens" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, ] [[package]] @@ -275,9 +275,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069 }, ] [[package]] @@ -287,9 +287,9 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] -sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } +sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721 }, ] [[package]] @@ -299,36 +299,36 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version == '3.11.*'", ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, ] [[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 } 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 }, ] [[package]] name = "babel" version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, ] [[package]] name = "backports-asyncio-runner" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, + { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313 }, ] [[package]] @@ -339,9 +339,9 @@ dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822 } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" }, + { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392 }, ] [[package]] @@ -358,29 +358,29 @@ dependencies = [ { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669, upload-time = "2025-11-10T01:53:50.558Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/d2/6caccbc96f9311e8ec3378c296d4f4809429c43a6cd2394e3c390e86816d/black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e", size = 1743501, upload-time = "2025-11-10T01:59:06.202Z" }, - { url = "https://files.pythonhosted.org/packages/69/35/b986d57828b3f3dccbf922e2864223197ba32e74c5004264b1c62bc9f04d/black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0", size = 1597308, upload-time = "2025-11-10T01:57:58.633Z" }, - { url = "https://files.pythonhosted.org/packages/39/8e/8b58ef4b37073f52b64a7b2dd8c9a96c84f45d6f47d878d0aa557e9a2d35/black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37", size = 1656194, upload-time = "2025-11-10T01:57:10.909Z" }, - { url = "https://files.pythonhosted.org/packages/8d/30/9c2267a7955ecc545306534ab88923769a979ac20a27cf618d370091e5dd/black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03", size = 1347996, upload-time = "2025-11-10T01:57:22.391Z" }, - { url = "https://files.pythonhosted.org/packages/c4/62/d304786b75ab0c530b833a89ce7d997924579fb7484ecd9266394903e394/black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a", size = 1727891, upload-time = "2025-11-10T02:01:40.507Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/ffe8a006aa522c9e3f430e7b93568a7b2163f4b3f16e8feb6d8c3552761a/black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170", size = 1581875, upload-time = "2025-11-10T01:57:51.192Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c8/7c8bda3108d0bb57387ac41b4abb5c08782b26da9f9c4421ef6694dac01a/black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc", size = 1642716, upload-time = "2025-11-10T01:56:51.589Z" }, - { url = "https://files.pythonhosted.org/packages/34/b9/f17dea34eecb7cc2609a89627d480fb6caea7b86190708eaa7eb15ed25e7/black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e", size = 1352904, upload-time = "2025-11-10T01:59:26.252Z" }, - { url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac", size = 1772831, upload-time = "2025-11-10T02:03:47Z" }, - { url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96", size = 1608520, upload-time = "2025-11-10T01:58:46.895Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd", size = 1682719, upload-time = "2025-11-10T01:56:55.24Z" }, - { url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409", size = 1362684, upload-time = "2025-11-10T01:57:07.639Z" }, - { url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b", size = 1772446, upload-time = "2025-11-10T02:02:16.181Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd", size = 1607983, upload-time = "2025-11-10T02:02:52.502Z" }, - { url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993", size = 1682481, upload-time = "2025-11-10T01:57:12.35Z" }, - { url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c", size = 1363869, upload-time = "2025-11-10T01:58:24.608Z" }, - { url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170", size = 1771358, upload-time = "2025-11-10T02:03:33.331Z" }, - { url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545", size = 1612902, upload-time = "2025-11-10T01:59:33.382Z" }, - { url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda", size = 1680571, upload-time = "2025-11-10T01:57:04.239Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664", size = 1382599, upload-time = "2025-11-10T01:57:57.427Z" }, - { url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b", size = 204918, upload-time = "2025-11-10T01:53:48.917Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/d2/6caccbc96f9311e8ec3378c296d4f4809429c43a6cd2394e3c390e86816d/black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e", size = 1743501 }, + { url = "https://files.pythonhosted.org/packages/69/35/b986d57828b3f3dccbf922e2864223197ba32e74c5004264b1c62bc9f04d/black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0", size = 1597308 }, + { url = "https://files.pythonhosted.org/packages/39/8e/8b58ef4b37073f52b64a7b2dd8c9a96c84f45d6f47d878d0aa557e9a2d35/black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37", size = 1656194 }, + { url = "https://files.pythonhosted.org/packages/8d/30/9c2267a7955ecc545306534ab88923769a979ac20a27cf618d370091e5dd/black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03", size = 1347996 }, + { url = "https://files.pythonhosted.org/packages/c4/62/d304786b75ab0c530b833a89ce7d997924579fb7484ecd9266394903e394/black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a", size = 1727891 }, + { url = "https://files.pythonhosted.org/packages/82/5d/ffe8a006aa522c9e3f430e7b93568a7b2163f4b3f16e8feb6d8c3552761a/black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170", size = 1581875 }, + { url = "https://files.pythonhosted.org/packages/cb/c8/7c8bda3108d0bb57387ac41b4abb5c08782b26da9f9c4421ef6694dac01a/black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc", size = 1642716 }, + { url = "https://files.pythonhosted.org/packages/34/b9/f17dea34eecb7cc2609a89627d480fb6caea7b86190708eaa7eb15ed25e7/black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e", size = 1352904 }, + { url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac", size = 1772831 }, + { url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96", size = 1608520 }, + { url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd", size = 1682719 }, + { url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409", size = 1362684 }, + { url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b", size = 1772446 }, + { url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd", size = 1607983 }, + { url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993", size = 1682481 }, + { url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c", size = 1363869 }, + { url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170", size = 1771358 }, + { url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545", size = 1612902 }, + { url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda", size = 1680571 }, + { url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664", size = 1382599 }, + { url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b", size = 204918 }, ] [[package]] @@ -390,9 +390,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437 }, ] [package.optional-dependencies] @@ -404,9 +404,9 @@ css = [ name = "certifi" version = "2025.11.12" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538 } wheels = [ - { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438 }, ] [[package]] @@ -416,168 +416,168 @@ 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/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, - { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, - { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, - { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, - { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283 }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504 }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811 }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402 }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217 }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079 }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475 }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829 }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211 }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184 }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790 }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344 }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560 }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613 }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476 }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374 }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597 }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574 }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971 }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972 }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078 }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076 }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820 }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635 }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271 }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048 }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529 }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097 }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519 }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572 }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963 }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361 }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932 }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557 }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909 }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402 }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328 }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650 }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487 }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726 }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195 }, ] [[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/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, - { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, - { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, - { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, - { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, - { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, - { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, - { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, - { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, - { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, - { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, - { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, - { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, - { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, - { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, - { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, - { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, - { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, - { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, - { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, - { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, - { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, - { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, - { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, - { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, - { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, - { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, - { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, - { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, - { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, - { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, - { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, - { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, - { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, - { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, - { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, - { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, - { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, - { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, - { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709 }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814 }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467 }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280 }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454 }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609 }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586 }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290 }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663 }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964 }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064 }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015 }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792 }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198 }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262 }, + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988 }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324 }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742 }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863 }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837 }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550 }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162 }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019 }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310 }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022 }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098 }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991 }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456 }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978 }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969 }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425 }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162 }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558 }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497 }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240 }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471 }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864 }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647 }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110 }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839 }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667 }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535 }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816 }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694 }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131 }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404 }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092 }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940 }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104 }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743 }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, ] [[package]] @@ -587,27 +587,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 } 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 }, ] [[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 } 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 }, ] [[package]] name = "comm" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, ] [[package]] @@ -679,7 +679,7 @@ requires-dist = [ { name = "openai", specifier = ">=1.0.0" }, { name = "pandas", specifier = ">=2.0.0" }, { name = "pydantic", specifier = ">=2.0.0" }, - { name = "pypdf", specifier = ">=6.4.1" }, + { name = "pypdf" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, { name = "python-dotenv", specifier = ">=1.0.0" }, @@ -701,65 +701,65 @@ dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227, upload-time = "2024-06-09T16:20:19.103Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, + { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686 }, ] [[package]] name = "debugpy" version = "1.8.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129, upload-time = "2025-09-17T16:33:20.633Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/36/b57c6e818d909f6e59c0182252921cf435e0951126a97e11de37e72ab5e1/debugpy-1.8.17-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:c41d2ce8bbaddcc0009cc73f65318eedfa3dbc88a8298081deb05389f1ab5542", size = 2098021, upload-time = "2025-09-17T16:33:22.556Z" }, - { url = "https://files.pythonhosted.org/packages/be/01/0363c7efdd1e9febd090bb13cee4fb1057215b157b2979a4ca5ccb678217/debugpy-1.8.17-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:1440fd514e1b815edd5861ca394786f90eb24960eb26d6f7200994333b1d79e3", size = 3087399, upload-time = "2025-09-17T16:33:24.292Z" }, - { url = "https://files.pythonhosted.org/packages/79/bc/4a984729674aa9a84856650438b9665f9a1d5a748804ac6f37932ce0d4aa/debugpy-1.8.17-cp310-cp310-win32.whl", hash = "sha256:3a32c0af575749083d7492dc79f6ab69f21b2d2ad4cd977a958a07d5865316e4", size = 5230292, upload-time = "2025-09-17T16:33:26.137Z" }, - { url = "https://files.pythonhosted.org/packages/5d/19/2b9b3092d0cf81a5aa10c86271999453030af354d1a5a7d6e34c574515d7/debugpy-1.8.17-cp310-cp310-win_amd64.whl", hash = "sha256:a3aad0537cf4d9c1996434be68c6c9a6d233ac6f76c2a482c7803295b4e4f99a", size = 5261885, upload-time = "2025-09-17T16:33:27.592Z" }, - { url = "https://files.pythonhosted.org/packages/d8/53/3af72b5c159278c4a0cf4cffa518675a0e73bdb7d1cac0239b815502d2ce/debugpy-1.8.17-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:d3fce3f0e3de262a3b67e69916d001f3e767661c6e1ee42553009d445d1cd840", size = 2207154, upload-time = "2025-09-17T16:33:29.457Z" }, - { url = "https://files.pythonhosted.org/packages/8f/6d/204f407df45600e2245b4a39860ed4ba32552330a0b3f5f160ae4cc30072/debugpy-1.8.17-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:c6bdf134457ae0cac6fb68205776be635d31174eeac9541e1d0c062165c6461f", size = 3170322, upload-time = "2025-09-17T16:33:30.837Z" }, - { url = "https://files.pythonhosted.org/packages/f2/13/1b8f87d39cf83c6b713de2620c31205299e6065622e7dd37aff4808dd410/debugpy-1.8.17-cp311-cp311-win32.whl", hash = "sha256:e79a195f9e059edfe5d8bf6f3749b2599452d3e9380484cd261f6b7cd2c7c4da", size = 5155078, upload-time = "2025-09-17T16:33:33.331Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c5/c012c60a2922cc91caa9675d0ddfbb14ba59e1e36228355f41cab6483469/debugpy-1.8.17-cp311-cp311-win_amd64.whl", hash = "sha256:b532282ad4eca958b1b2d7dbcb2b7218e02cb934165859b918e3b6ba7772d3f4", size = 5179011, upload-time = "2025-09-17T16:33:35.711Z" }, - { url = "https://files.pythonhosted.org/packages/08/2b/9d8e65beb2751876c82e1aceb32f328c43ec872711fa80257c7674f45650/debugpy-1.8.17-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:f14467edef672195c6f6b8e27ce5005313cb5d03c9239059bc7182b60c176e2d", size = 2549522, upload-time = "2025-09-17T16:33:38.466Z" }, - { url = "https://files.pythonhosted.org/packages/b4/78/eb0d77f02971c05fca0eb7465b18058ba84bd957062f5eec82f941ac792a/debugpy-1.8.17-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:24693179ef9dfa20dca8605905a42b392be56d410c333af82f1c5dff807a64cc", size = 4309417, upload-time = "2025-09-17T16:33:41.299Z" }, - { url = "https://files.pythonhosted.org/packages/37/42/c40f1d8cc1fed1e75ea54298a382395b8b937d923fcf41ab0797a554f555/debugpy-1.8.17-cp312-cp312-win32.whl", hash = "sha256:6a4e9dacf2cbb60d2514ff7b04b4534b0139facbf2abdffe0639ddb6088e59cf", size = 5277130, upload-time = "2025-09-17T16:33:43.554Z" }, - { url = "https://files.pythonhosted.org/packages/72/22/84263b205baad32b81b36eac076de0cdbe09fe2d0637f5b32243dc7c925b/debugpy-1.8.17-cp312-cp312-win_amd64.whl", hash = "sha256:e8f8f61c518952fb15f74a302e068b48d9c4691768ade433e4adeea961993464", size = 5319053, upload-time = "2025-09-17T16:33:53.033Z" }, - { url = "https://files.pythonhosted.org/packages/50/76/597e5cb97d026274ba297af8d89138dfd9e695767ba0e0895edb20963f40/debugpy-1.8.17-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:857c1dd5d70042502aef1c6d1c2801211f3ea7e56f75e9c335f434afb403e464", size = 2538386, upload-time = "2025-09-17T16:33:54.594Z" }, - { url = "https://files.pythonhosted.org/packages/5f/60/ce5c34fcdfec493701f9d1532dba95b21b2f6394147234dce21160bd923f/debugpy-1.8.17-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:3bea3b0b12f3946e098cce9b43c3c46e317b567f79570c3f43f0b96d00788088", size = 4292100, upload-time = "2025-09-17T16:33:56.353Z" }, - { url = "https://files.pythonhosted.org/packages/e8/95/7873cf2146577ef71d2a20bf553f12df865922a6f87b9e8ee1df04f01785/debugpy-1.8.17-cp313-cp313-win32.whl", hash = "sha256:e34ee844c2f17b18556b5bbe59e1e2ff4e86a00282d2a46edab73fd7f18f4a83", size = 5277002, upload-time = "2025-09-17T16:33:58.231Z" }, - { url = "https://files.pythonhosted.org/packages/46/11/18c79a1cee5ff539a94ec4aa290c1c069a5580fd5cfd2fb2e282f8e905da/debugpy-1.8.17-cp313-cp313-win_amd64.whl", hash = "sha256:6c5cd6f009ad4fca8e33e5238210dc1e5f42db07d4b6ab21ac7ffa904a196420", size = 5319047, upload-time = "2025-09-17T16:34:00.586Z" }, - { url = "https://files.pythonhosted.org/packages/de/45/115d55b2a9da6de812696064ceb505c31e952c5d89c4ed1d9bb983deec34/debugpy-1.8.17-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:045290c010bcd2d82bc97aa2daf6837443cd52f6328592698809b4549babcee1", size = 2536899, upload-time = "2025-09-17T16:34:02.657Z" }, - { url = "https://files.pythonhosted.org/packages/5a/73/2aa00c7f1f06e997ef57dc9b23d61a92120bec1437a012afb6d176585197/debugpy-1.8.17-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:b69b6bd9dba6a03632534cdf67c760625760a215ae289f7489a452af1031fe1f", size = 4268254, upload-time = "2025-09-17T16:34:04.486Z" }, - { url = "https://files.pythonhosted.org/packages/86/b5/ed3e65c63c68a6634e3ba04bd10255c8e46ec16ebed7d1c79e4816d8a760/debugpy-1.8.17-cp314-cp314-win32.whl", hash = "sha256:5c59b74aa5630f3a5194467100c3b3d1c77898f9ab27e3f7dc5d40fc2f122670", size = 5277203, upload-time = "2025-09-17T16:34:06.65Z" }, - { url = "https://files.pythonhosted.org/packages/b0/26/394276b71c7538445f29e792f589ab7379ae70fd26ff5577dfde71158e96/debugpy-1.8.17-cp314-cp314-win_amd64.whl", hash = "sha256:893cba7bb0f55161de4365584b025f7064e1f88913551bcd23be3260b231429c", size = 5318493, upload-time = "2025-09-17T16:34:08.483Z" }, - { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210, upload-time = "2025-09-17T16:34:25.835Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/36/b57c6e818d909f6e59c0182252921cf435e0951126a97e11de37e72ab5e1/debugpy-1.8.17-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:c41d2ce8bbaddcc0009cc73f65318eedfa3dbc88a8298081deb05389f1ab5542", size = 2098021 }, + { url = "https://files.pythonhosted.org/packages/be/01/0363c7efdd1e9febd090bb13cee4fb1057215b157b2979a4ca5ccb678217/debugpy-1.8.17-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:1440fd514e1b815edd5861ca394786f90eb24960eb26d6f7200994333b1d79e3", size = 3087399 }, + { url = "https://files.pythonhosted.org/packages/79/bc/4a984729674aa9a84856650438b9665f9a1d5a748804ac6f37932ce0d4aa/debugpy-1.8.17-cp310-cp310-win32.whl", hash = "sha256:3a32c0af575749083d7492dc79f6ab69f21b2d2ad4cd977a958a07d5865316e4", size = 5230292 }, + { url = "https://files.pythonhosted.org/packages/5d/19/2b9b3092d0cf81a5aa10c86271999453030af354d1a5a7d6e34c574515d7/debugpy-1.8.17-cp310-cp310-win_amd64.whl", hash = "sha256:a3aad0537cf4d9c1996434be68c6c9a6d233ac6f76c2a482c7803295b4e4f99a", size = 5261885 }, + { url = "https://files.pythonhosted.org/packages/d8/53/3af72b5c159278c4a0cf4cffa518675a0e73bdb7d1cac0239b815502d2ce/debugpy-1.8.17-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:d3fce3f0e3de262a3b67e69916d001f3e767661c6e1ee42553009d445d1cd840", size = 2207154 }, + { url = "https://files.pythonhosted.org/packages/8f/6d/204f407df45600e2245b4a39860ed4ba32552330a0b3f5f160ae4cc30072/debugpy-1.8.17-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:c6bdf134457ae0cac6fb68205776be635d31174eeac9541e1d0c062165c6461f", size = 3170322 }, + { url = "https://files.pythonhosted.org/packages/f2/13/1b8f87d39cf83c6b713de2620c31205299e6065622e7dd37aff4808dd410/debugpy-1.8.17-cp311-cp311-win32.whl", hash = "sha256:e79a195f9e059edfe5d8bf6f3749b2599452d3e9380484cd261f6b7cd2c7c4da", size = 5155078 }, + { url = "https://files.pythonhosted.org/packages/c2/c5/c012c60a2922cc91caa9675d0ddfbb14ba59e1e36228355f41cab6483469/debugpy-1.8.17-cp311-cp311-win_amd64.whl", hash = "sha256:b532282ad4eca958b1b2d7dbcb2b7218e02cb934165859b918e3b6ba7772d3f4", size = 5179011 }, + { url = "https://files.pythonhosted.org/packages/08/2b/9d8e65beb2751876c82e1aceb32f328c43ec872711fa80257c7674f45650/debugpy-1.8.17-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:f14467edef672195c6f6b8e27ce5005313cb5d03c9239059bc7182b60c176e2d", size = 2549522 }, + { url = "https://files.pythonhosted.org/packages/b4/78/eb0d77f02971c05fca0eb7465b18058ba84bd957062f5eec82f941ac792a/debugpy-1.8.17-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:24693179ef9dfa20dca8605905a42b392be56d410c333af82f1c5dff807a64cc", size = 4309417 }, + { url = "https://files.pythonhosted.org/packages/37/42/c40f1d8cc1fed1e75ea54298a382395b8b937d923fcf41ab0797a554f555/debugpy-1.8.17-cp312-cp312-win32.whl", hash = "sha256:6a4e9dacf2cbb60d2514ff7b04b4534b0139facbf2abdffe0639ddb6088e59cf", size = 5277130 }, + { url = "https://files.pythonhosted.org/packages/72/22/84263b205baad32b81b36eac076de0cdbe09fe2d0637f5b32243dc7c925b/debugpy-1.8.17-cp312-cp312-win_amd64.whl", hash = "sha256:e8f8f61c518952fb15f74a302e068b48d9c4691768ade433e4adeea961993464", size = 5319053 }, + { url = "https://files.pythonhosted.org/packages/50/76/597e5cb97d026274ba297af8d89138dfd9e695767ba0e0895edb20963f40/debugpy-1.8.17-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:857c1dd5d70042502aef1c6d1c2801211f3ea7e56f75e9c335f434afb403e464", size = 2538386 }, + { url = "https://files.pythonhosted.org/packages/5f/60/ce5c34fcdfec493701f9d1532dba95b21b2f6394147234dce21160bd923f/debugpy-1.8.17-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:3bea3b0b12f3946e098cce9b43c3c46e317b567f79570c3f43f0b96d00788088", size = 4292100 }, + { url = "https://files.pythonhosted.org/packages/e8/95/7873cf2146577ef71d2a20bf553f12df865922a6f87b9e8ee1df04f01785/debugpy-1.8.17-cp313-cp313-win32.whl", hash = "sha256:e34ee844c2f17b18556b5bbe59e1e2ff4e86a00282d2a46edab73fd7f18f4a83", size = 5277002 }, + { url = "https://files.pythonhosted.org/packages/46/11/18c79a1cee5ff539a94ec4aa290c1c069a5580fd5cfd2fb2e282f8e905da/debugpy-1.8.17-cp313-cp313-win_amd64.whl", hash = "sha256:6c5cd6f009ad4fca8e33e5238210dc1e5f42db07d4b6ab21ac7ffa904a196420", size = 5319047 }, + { url = "https://files.pythonhosted.org/packages/de/45/115d55b2a9da6de812696064ceb505c31e952c5d89c4ed1d9bb983deec34/debugpy-1.8.17-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:045290c010bcd2d82bc97aa2daf6837443cd52f6328592698809b4549babcee1", size = 2536899 }, + { url = "https://files.pythonhosted.org/packages/5a/73/2aa00c7f1f06e997ef57dc9b23d61a92120bec1437a012afb6d176585197/debugpy-1.8.17-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:b69b6bd9dba6a03632534cdf67c760625760a215ae289f7489a452af1031fe1f", size = 4268254 }, + { url = "https://files.pythonhosted.org/packages/86/b5/ed3e65c63c68a6634e3ba04bd10255c8e46ec16ebed7d1c79e4816d8a760/debugpy-1.8.17-cp314-cp314-win32.whl", hash = "sha256:5c59b74aa5630f3a5194467100c3b3d1c77898f9ab27e3f7dc5d40fc2f122670", size = 5277203 }, + { url = "https://files.pythonhosted.org/packages/b0/26/394276b71c7538445f29e792f589ab7379ae70fd26ff5577dfde71158e96/debugpy-1.8.17-cp314-cp314-win_amd64.whl", hash = "sha256:893cba7bb0f55161de4365584b025f7064e1f88913551bcd23be3260b231429c", size = 5318493 }, + { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210 }, ] [[package]] name = "decorator" version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, ] [[package]] name = "defusedxml" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, ] [[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 } 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 }, ] [[package]] @@ -769,18 +769,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, ] [[package]] name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, ] [[package]] @@ -790,265 +790,265 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/64/27/022d4dbd4c20567b4c294f79a133cc2f05240ea61e0d515ead18c995c249/faker-38.2.0.tar.gz", hash = "sha256:20672803db9c7cb97f9b56c18c54b915b6f1d8991f63d1d673642dc43f5ce7ab", size = 1941469, upload-time = "2025-11-19T16:37:31.892Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/27/022d4dbd4c20567b4c294f79a133cc2f05240ea61e0d515ead18c995c249/faker-38.2.0.tar.gz", hash = "sha256:20672803db9c7cb97f9b56c18c54b915b6f1d8991f63d1d673642dc43f5ce7ab", size = 1941469 } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/93/00c94d45f55c336434a15f98d906387e87ce28f9918e4444829a8fda432d/faker-38.2.0-py3-none-any.whl", hash = "sha256:35fe4a0a79dee0dc4103a6083ee9224941e7d3594811a50e3969e547b0d2ee65", size = 1980505, upload-time = "2025-11-19T16:37:30.208Z" }, + { url = "https://files.pythonhosted.org/packages/17/93/00c94d45f55c336434a15f98d906387e87ce28f9918e4444829a8fda432d/faker-38.2.0-py3-none-any.whl", hash = "sha256:35fe4a0a79dee0dc4103a6083ee9224941e7d3594811a50e3969e547b0d2ee65", size = 1980505 }, ] [[package]] name = "fastjsonschema" version = "2.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024 }, ] [[package]] name = "filelock" version = "3.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, + { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054 }, ] [[package]] name = "fqdn" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121 }, ] [[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/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, - { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, - { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, - { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, - { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, - { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, - { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, - { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, - { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, - { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, - { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, - { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, - { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, - { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, - { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, - { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, - { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, - { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, - { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, - { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, - { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, - { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, - { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, - { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, - { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, - { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, - { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, - { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, - { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230 }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621 }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889 }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464 }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649 }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188 }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748 }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351 }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767 }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887 }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785 }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312 }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650 }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659 }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837 }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989 }, + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912 }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046 }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119 }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067 }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160 }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544 }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797 }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923 }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886 }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731 }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544 }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806 }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382 }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647 }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064 }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937 }, + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782 }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594 }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448 }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411 }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014 }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909 }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049 }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485 }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619 }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320 }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820 }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518 }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096 }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985 }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591 }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628 }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882 }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492 }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034 }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536 }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330 }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676 }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451 }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507 }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, ] [[package]] name = "fsspec" version = "2025.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285 } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966 }, ] [[package]] name = "greenlet" version = "3.2.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/ed/6bfa4109fcb23a58819600392564fea69cdc6551ffd5e69ccf1d52a40cbc/greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c", size = 271061, upload-time = "2025-08-07T13:17:15.373Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fc/102ec1a2fc015b3a7652abab7acf3541d58c04d3d17a8d3d6a44adae1eb1/greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590", size = 629475, upload-time = "2025-08-07T13:42:54.009Z" }, - { url = "https://files.pythonhosted.org/packages/c5/26/80383131d55a4ac0fb08d71660fd77e7660b9db6bdb4e8884f46d9f2cc04/greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c", size = 640802, upload-time = "2025-08-07T13:45:25.52Z" }, - { url = "https://files.pythonhosted.org/packages/9f/7c/e7833dbcd8f376f3326bd728c845d31dcde4c84268d3921afcae77d90d08/greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b", size = 636703, upload-time = "2025-08-07T13:53:12.622Z" }, - { url = "https://files.pythonhosted.org/packages/e9/49/547b93b7c0428ede7b3f309bc965986874759f7d89e4e04aeddbc9699acb/greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31", size = 635417, upload-time = "2025-08-07T13:18:25.189Z" }, - { url = "https://files.pythonhosted.org/packages/7f/91/ae2eb6b7979e2f9b035a9f612cf70f1bf54aad4e1d125129bef1eae96f19/greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d", size = 584358, upload-time = "2025-08-07T13:18:23.708Z" }, - { url = "https://files.pythonhosted.org/packages/f7/85/433de0c9c0252b22b16d413c9407e6cb3b41df7389afc366ca204dbc1393/greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5", size = 1113550, upload-time = "2025-08-07T13:42:37.467Z" }, - { url = "https://files.pythonhosted.org/packages/a1/8d/88f3ebd2bc96bf7747093696f4335a0a8a4c5acfcf1b757717c0d2474ba3/greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f", size = 1137126, upload-time = "2025-08-07T13:18:20.239Z" }, - { url = "https://files.pythonhosted.org/packages/f1/29/74242b7d72385e29bcc5563fba67dad94943d7cd03552bac320d597f29b2/greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7", size = 1544904, upload-time = "2025-11-04T12:42:04.763Z" }, - { url = "https://files.pythonhosted.org/packages/c8/e2/1572b8eeab0f77df5f6729d6ab6b141e4a84ee8eb9bc8c1e7918f94eda6d/greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8", size = 1611228, upload-time = "2025-11-04T12:42:08.423Z" }, - { url = "https://files.pythonhosted.org/packages/d6/6f/b60b0291d9623c496638c582297ead61f43c4b72eef5e9c926ef4565ec13/greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c", size = 298654, upload-time = "2025-08-07T13:50:00.469Z" }, - { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" }, - { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646, upload-time = "2025-08-07T13:45:26.523Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519, upload-time = "2025-08-07T13:53:13.928Z" }, - { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707, upload-time = "2025-08-07T13:18:27.146Z" }, - { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" }, - { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" }, - { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" }, - { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385, upload-time = "2025-11-04T12:42:11.067Z" }, - { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329, upload-time = "2025-11-04T12:42:12.928Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" }, - { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" }, - { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" }, - { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" }, - { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" }, - { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" }, - { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" }, - { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" }, - { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" }, - { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" }, - { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, - { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, - { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, - { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" }, - { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, - { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, - { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, - { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, - { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" }, - { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, - { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, - { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, - { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, - { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, - { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" }, - { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/ed/6bfa4109fcb23a58819600392564fea69cdc6551ffd5e69ccf1d52a40cbc/greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c", size = 271061 }, + { url = "https://files.pythonhosted.org/packages/2a/fc/102ec1a2fc015b3a7652abab7acf3541d58c04d3d17a8d3d6a44adae1eb1/greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590", size = 629475 }, + { url = "https://files.pythonhosted.org/packages/c5/26/80383131d55a4ac0fb08d71660fd77e7660b9db6bdb4e8884f46d9f2cc04/greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c", size = 640802 }, + { url = "https://files.pythonhosted.org/packages/9f/7c/e7833dbcd8f376f3326bd728c845d31dcde4c84268d3921afcae77d90d08/greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b", size = 636703 }, + { url = "https://files.pythonhosted.org/packages/e9/49/547b93b7c0428ede7b3f309bc965986874759f7d89e4e04aeddbc9699acb/greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31", size = 635417 }, + { url = "https://files.pythonhosted.org/packages/7f/91/ae2eb6b7979e2f9b035a9f612cf70f1bf54aad4e1d125129bef1eae96f19/greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d", size = 584358 }, + { url = "https://files.pythonhosted.org/packages/f7/85/433de0c9c0252b22b16d413c9407e6cb3b41df7389afc366ca204dbc1393/greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5", size = 1113550 }, + { url = "https://files.pythonhosted.org/packages/a1/8d/88f3ebd2bc96bf7747093696f4335a0a8a4c5acfcf1b757717c0d2474ba3/greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f", size = 1137126 }, + { url = "https://files.pythonhosted.org/packages/f1/29/74242b7d72385e29bcc5563fba67dad94943d7cd03552bac320d597f29b2/greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7", size = 1544904 }, + { url = "https://files.pythonhosted.org/packages/c8/e2/1572b8eeab0f77df5f6729d6ab6b141e4a84ee8eb9bc8c1e7918f94eda6d/greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8", size = 1611228 }, + { url = "https://files.pythonhosted.org/packages/d6/6f/b60b0291d9623c496638c582297ead61f43c4b72eef5e9c926ef4565ec13/greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c", size = 298654 }, + { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305 }, + { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472 }, + { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646 }, + { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519 }, + { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707 }, + { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684 }, + { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647 }, + { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073 }, + { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385 }, + { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329 }, + { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100 }, + { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079 }, + { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997 }, + { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185 }, + { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926 }, + { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839 }, + { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586 }, + { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281 }, + { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142 }, + { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846 }, + { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814 }, + { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899 }, + { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814 }, + { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073 }, + { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191 }, + { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516 }, + { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169 }, + { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497 }, + { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662 }, + { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210 }, + { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759 }, + { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288 }, + { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685 }, + { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586 }, + { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346 }, + { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218 }, + { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659 }, + { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355 }, + { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512 }, + { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508 }, + { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760 }, + { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425 }, ] [[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 } 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 }, ] [[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 } +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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735 }, ] [[package]] @@ -1059,9 +1059,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 } 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 }, ] [[package]] @@ -1074,18 +1074,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 } 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 }, ] [[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 } 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 }, ] [[package]] @@ -1102,27 +1102,27 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" }, + { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094 }, ] [[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 } 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 }, ] [[package]] name = "iniconfig" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484 }, ] [[package]] @@ -1145,9 +1145,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968 }, ] [[package]] @@ -1170,9 +1170,9 @@ dependencies = [ { name = "traitlets", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088, upload-time = "2025-05-31T16:39:09.613Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088 } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2", size = 831864, upload-time = "2025-05-31T16:39:06.38Z" }, + { url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2", size = 831864 }, ] [[package]] @@ -1198,9 +1198,9 @@ dependencies = [ { name = "traitlets", marker = "python_full_version >= '3.11'" }, { name = "typing-extensions", marker = "python_full_version == '3.11.*'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/29/e6/48c74d54039241a456add616464ea28c6ebf782e4110d419411b83dae06f/ipython-9.7.0.tar.gz", hash = "sha256:5f6de88c905a566c6a9d6c400a8fed54a638e1f7543d17aae2551133216b1e4e", size = 4422115, upload-time = "2025-11-05T12:18:54.646Z" } +sdist = { url = "https://files.pythonhosted.org/packages/29/e6/48c74d54039241a456add616464ea28c6ebf782e4110d419411b83dae06f/ipython-9.7.0.tar.gz", hash = "sha256:5f6de88c905a566c6a9d6c400a8fed54a638e1f7543d17aae2551133216b1e4e", size = 4422115 } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/aa/62893d6a591d337aa59dcc4c6f6c842f1fe20cd72c8c5c1f980255243252/ipython-9.7.0-py3-none-any.whl", hash = "sha256:bce8ac85eb9521adc94e1845b4c03d88365fd6ac2f4908ec4ed1eb1b0a065f9f", size = 618911, upload-time = "2025-11-05T12:18:52.484Z" }, + { url = "https://files.pythonhosted.org/packages/05/aa/62893d6a591d337aa59dcc4c6f6c842f1fe20cd72c8c5c1f980255243252/ipython-9.7.0-py3-none-any.whl", hash = "sha256:bce8ac85eb9521adc94e1845b4c03d88365fd6ac2f4908ec4ed1eb1b0a065f9f", size = 618911 }, ] [[package]] @@ -1210,9 +1210,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments", marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074 }, ] [[package]] @@ -1227,9 +1227,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808 }, ] [[package]] @@ -1239,18 +1239,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arrow" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, ] [[package]] name = "isort" version = "7.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/53/4f3c058e3bace40282876f9b553343376ee687f3c35a525dc79dbd450f88/isort-7.0.0.tar.gz", hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187", size = 805049, upload-time = "2025-10-11T13:30:59.107Z" } +sdist = { url = "https://files.pythonhosted.org/packages/63/53/4f3c058e3bace40282876f9b553343376ee687f3c35a525dc79dbd450f88/isort-7.0.0.tar.gz", hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187", size = 805049 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672, upload-time = "2025-10-11T13:30:57.665Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672 }, ] [[package]] @@ -1260,9 +1260,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, ] [[package]] @@ -1272,124 +1272,116 @@ 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 } 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 }, ] [[package]] name = "jiter" version = "0.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294, upload-time = "2025-11-09T20:49:23.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652, upload-time = "2025-11-09T20:46:41.021Z" }, - { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829, upload-time = "2025-11-09T20:46:43.281Z" }, - { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568, upload-time = "2025-11-09T20:46:45.075Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052, upload-time = "2025-11-09T20:46:46.818Z" }, - { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585, upload-time = "2025-11-09T20:46:48.319Z" }, - { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541, upload-time = "2025-11-09T20:46:49.643Z" }, - { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423, upload-time = "2025-11-09T20:46:51.731Z" }, - { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958, upload-time = "2025-11-09T20:46:53.432Z" }, - { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084, upload-time = "2025-11-09T20:46:54.848Z" }, - { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054, upload-time = "2025-11-09T20:46:56.487Z" }, - { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368, upload-time = "2025-11-09T20:46:58.638Z" }, - { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847, upload-time = "2025-11-09T20:47:00.295Z" }, - { url = "https://files.pythonhosted.org/packages/32/f9/eaca4633486b527ebe7e681c431f529b63fe2709e7c5242fc0f43f77ce63/jiter-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8f8a7e317190b2c2d60eb2e8aa835270b008139562d70fe732e1c0020ec53c9", size = 316435, upload-time = "2025-11-09T20:47:02.087Z" }, - { url = "https://files.pythonhosted.org/packages/10/c1/40c9f7c22f5e6ff715f28113ebaba27ab85f9af2660ad6e1dd6425d14c19/jiter-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2218228a077e784c6c8f1a8e5d6b8cb1dea62ce25811c356364848554b2056cd", size = 320548, upload-time = "2025-11-09T20:47:03.409Z" }, - { url = "https://files.pythonhosted.org/packages/6b/1b/efbb68fe87e7711b00d2cfd1f26bb4bfc25a10539aefeaa7727329ffb9cb/jiter-0.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9354ccaa2982bf2188fd5f57f79f800ef622ec67beb8329903abf6b10da7d423", size = 351915, upload-time = "2025-11-09T20:47:05.171Z" }, - { url = "https://files.pythonhosted.org/packages/15/2d/c06e659888c128ad1e838123d0638f0efad90cc30860cb5f74dd3f2fc0b3/jiter-0.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f2607185ea89b4af9a604d4c7ec40e45d3ad03ee66998b031134bc510232bb7", size = 368966, upload-time = "2025-11-09T20:47:06.508Z" }, - { url = "https://files.pythonhosted.org/packages/6b/20/058db4ae5fb07cf6a4ab2e9b9294416f606d8e467fb74c2184b2a1eeacba/jiter-0.12.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a585a5e42d25f2e71db5f10b171f5e5ea641d3aa44f7df745aa965606111cc2", size = 482047, upload-time = "2025-11-09T20:47:08.382Z" }, - { url = "https://files.pythonhosted.org/packages/49/bb/dc2b1c122275e1de2eb12905015d61e8316b2f888bdaac34221c301495d6/jiter-0.12.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd9e21d34edff5a663c631f850edcb786719c960ce887a5661e9c828a53a95d9", size = 380835, upload-time = "2025-11-09T20:47:09.81Z" }, - { url = "https://files.pythonhosted.org/packages/23/7d/38f9cd337575349de16da575ee57ddb2d5a64d425c9367f5ef9e4612e32e/jiter-0.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a612534770470686cd5431478dc5a1b660eceb410abade6b1b74e320ca98de6", size = 364587, upload-time = "2025-11-09T20:47:11.529Z" }, - { url = "https://files.pythonhosted.org/packages/f0/a3/b13e8e61e70f0bb06085099c4e2462647f53cc2ca97614f7fedcaa2bb9f3/jiter-0.12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3985aea37d40a908f887b34d05111e0aae822943796ebf8338877fee2ab67725", size = 390492, upload-time = "2025-11-09T20:47:12.993Z" }, - { url = "https://files.pythonhosted.org/packages/07/71/e0d11422ed027e21422f7bc1883c61deba2d9752b720538430c1deadfbca/jiter-0.12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b1207af186495f48f72529f8d86671903c8c10127cac6381b11dddc4aaa52df6", size = 522046, upload-time = "2025-11-09T20:47:14.6Z" }, - { url = "https://files.pythonhosted.org/packages/9f/59/b968a9aa7102a8375dbbdfbd2aeebe563c7e5dddf0f47c9ef1588a97e224/jiter-0.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef2fb241de583934c9915a33120ecc06d94aa3381a134570f59eed784e87001e", size = 513392, upload-time = "2025-11-09T20:47:16.011Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e4/7df62002499080dbd61b505c5cb351aa09e9959d176cac2aa8da6f93b13b/jiter-0.12.0-cp311-cp311-win32.whl", hash = "sha256:453b6035672fecce8007465896a25b28a6b59cfe8fbc974b2563a92f5a92a67c", size = 206096, upload-time = "2025-11-09T20:47:17.344Z" }, - { url = "https://files.pythonhosted.org/packages/bb/60/1032b30ae0572196b0de0e87dce3b6c26a1eff71aad5fe43dee3082d32e0/jiter-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:ca264b9603973c2ad9435c71a8ec8b49f8f715ab5ba421c85a51cde9887e421f", size = 204899, upload-time = "2025-11-09T20:47:19.365Z" }, - { url = "https://files.pythonhosted.org/packages/49/d5/c145e526fccdb834063fb45c071df78b0cc426bbaf6de38b0781f45d956f/jiter-0.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:cb00ef392e7d684f2754598c02c409f376ddcef857aae796d559e6cacc2d78a5", size = 188070, upload-time = "2025-11-09T20:47:20.75Z" }, - { url = "https://files.pythonhosted.org/packages/92/c9/5b9f7b4983f1b542c64e84165075335e8a236fa9e2ea03a0c79780062be8/jiter-0.12.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:305e061fa82f4680607a775b2e8e0bcb071cd2205ac38e6ef48c8dd5ebe1cf37", size = 314449, upload-time = "2025-11-09T20:47:22.999Z" }, - { url = "https://files.pythonhosted.org/packages/98/6e/e8efa0e78de00db0aee82c0cf9e8b3f2027efd7f8a71f859d8f4be8e98ef/jiter-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c1860627048e302a528333c9307c818c547f214d8659b0705d2195e1a94b274", size = 319855, upload-time = "2025-11-09T20:47:24.779Z" }, - { url = "https://files.pythonhosted.org/packages/20/26/894cd88e60b5d58af53bec5c6759d1292bd0b37a8b5f60f07abf7a63ae5f/jiter-0.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df37577a4f8408f7e0ec3205d2a8f87672af8f17008358063a4d6425b6081ce3", size = 350171, upload-time = "2025-11-09T20:47:26.469Z" }, - { url = "https://files.pythonhosted.org/packages/f5/27/a7b818b9979ac31b3763d25f3653ec3a954044d5e9f5d87f2f247d679fd1/jiter-0.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fdd787356c1c13a4f40b43c2156276ef7a71eb487d98472476476d803fb2cf", size = 365590, upload-time = "2025-11-09T20:47:27.918Z" }, - { url = "https://files.pythonhosted.org/packages/ba/7e/e46195801a97673a83746170b17984aa8ac4a455746354516d02ca5541b4/jiter-0.12.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1eb5db8d9c65b112aacf14fcd0faae9913d07a8afea5ed06ccdd12b724e966a1", size = 479462, upload-time = "2025-11-09T20:47:29.654Z" }, - { url = "https://files.pythonhosted.org/packages/ca/75/f833bfb009ab4bd11b1c9406d333e3b4357709ed0570bb48c7c06d78c7dd/jiter-0.12.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73c568cc27c473f82480abc15d1301adf333a7ea4f2e813d6a2c7d8b6ba8d0df", size = 378983, upload-time = "2025-11-09T20:47:31.026Z" }, - { url = "https://files.pythonhosted.org/packages/71/b3/7a69d77943cc837d30165643db753471aff5df39692d598da880a6e51c24/jiter-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4321e8a3d868919bcb1abb1db550d41f2b5b326f72df29e53b2df8b006eb9403", size = 361328, upload-time = "2025-11-09T20:47:33.286Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ac/a78f90caf48d65ba70d8c6efc6f23150bc39dc3389d65bbec2a95c7bc628/jiter-0.12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a51bad79f8cc9cac2b4b705039f814049142e0050f30d91695a2d9a6611f126", size = 386740, upload-time = "2025-11-09T20:47:34.703Z" }, - { url = "https://files.pythonhosted.org/packages/39/b6/5d31c2cc8e1b6a6bcf3c5721e4ca0a3633d1ab4754b09bc7084f6c4f5327/jiter-0.12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a67b678f6a5f1dd6c36d642d7db83e456bc8b104788262aaefc11a22339f5a9", size = 520875, upload-time = "2025-11-09T20:47:36.058Z" }, - { url = "https://files.pythonhosted.org/packages/30/b5/4df540fae4e9f68c54b8dab004bd8c943a752f0b00efd6e7d64aa3850339/jiter-0.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efe1a211fe1fd14762adea941e3cfd6c611a136e28da6c39272dbb7a1bbe6a86", size = 511457, upload-time = "2025-11-09T20:47:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/07/65/86b74010e450a1a77b2c1aabb91d4a91dd3cd5afce99f34d75fd1ac64b19/jiter-0.12.0-cp312-cp312-win32.whl", hash = "sha256:d779d97c834b4278276ec703dc3fc1735fca50af63eb7262f05bdb4e62203d44", size = 204546, upload-time = "2025-11-09T20:47:40.47Z" }, - { url = "https://files.pythonhosted.org/packages/1c/c7/6659f537f9562d963488e3e55573498a442503ced01f7e169e96a6110383/jiter-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8269062060212b373316fe69236096aaf4c49022d267c6736eebd66bbbc60bb", size = 205196, upload-time = "2025-11-09T20:47:41.794Z" }, - { url = "https://files.pythonhosted.org/packages/21/f4/935304f5169edadfec7f9c01eacbce4c90bb9a82035ac1de1f3bd2d40be6/jiter-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:06cb970936c65de926d648af0ed3d21857f026b1cf5525cb2947aa5e01e05789", size = 186100, upload-time = "2025-11-09T20:47:43.007Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a6/97209693b177716e22576ee1161674d1d58029eb178e01866a0422b69224/jiter-0.12.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6cc49d5130a14b732e0612bc76ae8db3b49898732223ef8b7599aa8d9810683e", size = 313658, upload-time = "2025-11-09T20:47:44.424Z" }, - { url = "https://files.pythonhosted.org/packages/06/4d/125c5c1537c7d8ee73ad3d530a442d6c619714b95027143f1b61c0b4dfe0/jiter-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37f27a32ce36364d2fa4f7fdc507279db604d27d239ea2e044c8f148410defe1", size = 318605, upload-time = "2025-11-09T20:47:45.973Z" }, - { url = "https://files.pythonhosted.org/packages/99/bf/a840b89847885064c41a5f52de6e312e91fa84a520848ee56c97e4fa0205/jiter-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc0944aa3d4b4773e348cda635252824a78f4ba44328e042ef1ff3f6080d1cf", size = 349803, upload-time = "2025-11-09T20:47:47.535Z" }, - { url = "https://files.pythonhosted.org/packages/8a/88/e63441c28e0db50e305ae23e19c1d8fae012d78ed55365da392c1f34b09c/jiter-0.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da25c62d4ee1ffbacb97fac6dfe4dcd6759ebdc9015991e92a6eae5816287f44", size = 365120, upload-time = "2025-11-09T20:47:49.284Z" }, - { url = "https://files.pythonhosted.org/packages/0a/7c/49b02714af4343970eb8aca63396bc1c82fa01197dbb1e9b0d274b550d4e/jiter-0.12.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:048485c654b838140b007390b8182ba9774621103bd4d77c9c3f6f117474ba45", size = 479918, upload-time = "2025-11-09T20:47:50.807Z" }, - { url = "https://files.pythonhosted.org/packages/69/ba/0a809817fdd5a1db80490b9150645f3aae16afad166960bcd562be194f3b/jiter-0.12.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:635e737fbb7315bef0037c19b88b799143d2d7d3507e61a76751025226b3ac87", size = 379008, upload-time = "2025-11-09T20:47:52.211Z" }, - { url = "https://files.pythonhosted.org/packages/5f/c3/c9fc0232e736c8877d9e6d83d6eeb0ba4e90c6c073835cc2e8f73fdeef51/jiter-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e017c417b1ebda911bd13b1e40612704b1f5420e30695112efdbed8a4b389ed", size = 361785, upload-time = "2025-11-09T20:47:53.512Z" }, - { url = "https://files.pythonhosted.org/packages/96/61/61f69b7e442e97ca6cd53086ddc1cf59fb830549bc72c0a293713a60c525/jiter-0.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:89b0bfb8b2bf2351fba36bb211ef8bfceba73ef58e7f0c68fb67b5a2795ca2f9", size = 386108, upload-time = "2025-11-09T20:47:54.893Z" }, - { url = "https://files.pythonhosted.org/packages/e9/2e/76bb3332f28550c8f1eba3bf6e5efe211efda0ddbbaf24976bc7078d42a5/jiter-0.12.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:f5aa5427a629a824a543672778c9ce0c5e556550d1569bb6ea28a85015287626", size = 519937, upload-time = "2025-11-09T20:47:56.253Z" }, - { url = "https://files.pythonhosted.org/packages/84/d6/fa96efa87dc8bff2094fb947f51f66368fa56d8d4fc9e77b25d7fbb23375/jiter-0.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed53b3d6acbcb0fd0b90f20c7cb3b24c357fe82a3518934d4edfa8c6898e498c", size = 510853, upload-time = "2025-11-09T20:47:58.32Z" }, - { url = "https://files.pythonhosted.org/packages/8a/28/93f67fdb4d5904a708119a6ab58a8f1ec226ff10a94a282e0215402a8462/jiter-0.12.0-cp313-cp313-win32.whl", hash = "sha256:4747de73d6b8c78f2e253a2787930f4fffc68da7fa319739f57437f95963c4de", size = 204699, upload-time = "2025-11-09T20:47:59.686Z" }, - { url = "https://files.pythonhosted.org/packages/c4/1f/30b0eb087045a0abe2a5c9c0c0c8da110875a1d3be83afd4a9a4e548be3c/jiter-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e25012eb0c456fcc13354255d0338cd5397cce26c77b2832b3c4e2e255ea5d9a", size = 204258, upload-time = "2025-11-09T20:48:01.01Z" }, - { url = "https://files.pythonhosted.org/packages/2c/f4/2b4daf99b96bce6fc47971890b14b2a36aef88d7beb9f057fafa032c6141/jiter-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:c97b92c54fe6110138c872add030a1f99aea2401ddcdaa21edf74705a646dd60", size = 185503, upload-time = "2025-11-09T20:48:02.35Z" }, - { url = "https://files.pythonhosted.org/packages/39/ca/67bb15a7061d6fe20b9b2a2fd783e296a1e0f93468252c093481a2f00efa/jiter-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53839b35a38f56b8be26a7851a48b89bc47e5d88e900929df10ed93b95fea3d6", size = 317965, upload-time = "2025-11-09T20:48:03.783Z" }, - { url = "https://files.pythonhosted.org/packages/18/af/1788031cd22e29c3b14bc6ca80b16a39a0b10e611367ffd480c06a259831/jiter-0.12.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f669548e55c91ab47fef8bddd9c954dab1938644e715ea49d7e117015110a4", size = 345831, upload-time = "2025-11-09T20:48:05.55Z" }, - { url = "https://files.pythonhosted.org/packages/05/17/710bf8472d1dff0d3caf4ced6031060091c1320f84ee7d5dcbed1f352417/jiter-0.12.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:351d54f2b09a41600ffea43d081522d792e81dcfb915f6d2d242744c1cc48beb", size = 361272, upload-time = "2025-11-09T20:48:06.951Z" }, - { url = "https://files.pythonhosted.org/packages/fb/f1/1dcc4618b59761fef92d10bcbb0b038b5160be653b003651566a185f1a5c/jiter-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2a5e90604620f94bf62264e7c2c038704d38217b7465b863896c6d7c902b06c7", size = 204604, upload-time = "2025-11-09T20:48:08.328Z" }, - { url = "https://files.pythonhosted.org/packages/d9/32/63cb1d9f1c5c6632a783c0052cde9ef7ba82688f7065e2f0d5f10a7e3edb/jiter-0.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:88ef757017e78d2860f96250f9393b7b577b06a956ad102c29c8237554380db3", size = 185628, upload-time = "2025-11-09T20:48:09.572Z" }, - { url = "https://files.pythonhosted.org/packages/a8/99/45c9f0dbe4a1416b2b9a8a6d1236459540f43d7fb8883cff769a8db0612d/jiter-0.12.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c46d927acd09c67a9fb1416df45c5a04c27e83aae969267e98fba35b74e99525", size = 312478, upload-time = "2025-11-09T20:48:10.898Z" }, - { url = "https://files.pythonhosted.org/packages/4c/a7/54ae75613ba9e0f55fcb0bc5d1f807823b5167cc944e9333ff322e9f07dd/jiter-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:774ff60b27a84a85b27b88cd5583899c59940bcc126caca97eb2a9df6aa00c49", size = 318706, upload-time = "2025-11-09T20:48:12.266Z" }, - { url = "https://files.pythonhosted.org/packages/59/31/2aa241ad2c10774baf6c37f8b8e1f39c07db358f1329f4eb40eba179c2a2/jiter-0.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5433fab222fb072237df3f637d01b81f040a07dcac1cb4a5c75c7aa9ed0bef1", size = 351894, upload-time = "2025-11-09T20:48:13.673Z" }, - { url = "https://files.pythonhosted.org/packages/54/4f/0f2759522719133a9042781b18cc94e335b6d290f5e2d3e6899d6af933e3/jiter-0.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8c593c6e71c07866ec6bfb790e202a833eeec885022296aff6b9e0b92d6a70e", size = 365714, upload-time = "2025-11-09T20:48:15.083Z" }, - { url = "https://files.pythonhosted.org/packages/dc/6f/806b895f476582c62a2f52c453151edd8a0fde5411b0497baaa41018e878/jiter-0.12.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d32894d4c6877a87ae00c6b915b609406819dce8bc0d4e962e4de2784e567e", size = 478989, upload-time = "2025-11-09T20:48:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/86/6c/012d894dc6e1033acd8db2b8346add33e413ec1c7c002598915278a37f79/jiter-0.12.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:798e46eed9eb10c3adbbacbd3bdb5ecd4cf7064e453d00dbef08802dae6937ff", size = 378615, upload-time = "2025-11-09T20:48:18.614Z" }, - { url = "https://files.pythonhosted.org/packages/87/30/d718d599f6700163e28e2c71c0bbaf6dace692e7df2592fd793ac9276717/jiter-0.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f1368f0a6719ea80013a4eb90ba72e75d7ea67cfc7846db2ca504f3df0169a", size = 364745, upload-time = "2025-11-09T20:48:20.117Z" }, - { url = "https://files.pythonhosted.org/packages/8f/85/315b45ce4b6ddc7d7fceca24068543b02bdc8782942f4ee49d652e2cc89f/jiter-0.12.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65f04a9d0b4406f7e51279710b27484af411896246200e461d80d3ba0caa901a", size = 386502, upload-time = "2025-11-09T20:48:21.543Z" }, - { url = "https://files.pythonhosted.org/packages/74/0b/ce0434fb40c5b24b368fe81b17074d2840748b4952256bab451b72290a49/jiter-0.12.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:fd990541982a24281d12b67a335e44f117e4c6cbad3c3b75c7dea68bf4ce3a67", size = 519845, upload-time = "2025-11-09T20:48:22.964Z" }, - { url = "https://files.pythonhosted.org/packages/e8/a3/7a7a4488ba052767846b9c916d208b3ed114e3eb670ee984e4c565b9cf0d/jiter-0.12.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b111b0e9152fa7df870ecaebb0bd30240d9f7fff1f2003bcb4ed0f519941820b", size = 510701, upload-time = "2025-11-09T20:48:24.483Z" }, - { url = "https://files.pythonhosted.org/packages/c3/16/052ffbf9d0467b70af24e30f91e0579e13ded0c17bb4a8eb2aed3cb60131/jiter-0.12.0-cp314-cp314-win32.whl", hash = "sha256:a78befb9cc0a45b5a5a0d537b06f8544c2ebb60d19d02c41ff15da28a9e22d42", size = 205029, upload-time = "2025-11-09T20:48:25.749Z" }, - { url = "https://files.pythonhosted.org/packages/e4/18/3cf1f3f0ccc789f76b9a754bdb7a6977e5d1d671ee97a9e14f7eb728d80e/jiter-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:e1fe01c082f6aafbe5c8faf0ff074f38dfb911d53f07ec333ca03f8f6226debf", size = 204960, upload-time = "2025-11-09T20:48:27.415Z" }, - { url = "https://files.pythonhosted.org/packages/02/68/736821e52ecfdeeb0f024b8ab01b5a229f6b9293bbdb444c27efade50b0f/jiter-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:d72f3b5a432a4c546ea4bedc84cce0c3404874f1d1676260b9c7f048a9855451", size = 185529, upload-time = "2025-11-09T20:48:29.125Z" }, - { url = "https://files.pythonhosted.org/packages/30/61/12ed8ee7a643cce29ac97c2281f9ce3956eb76b037e88d290f4ed0d41480/jiter-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e6ded41aeba3603f9728ed2b6196e4df875348ab97b28fc8afff115ed42ba7a7", size = 318974, upload-time = "2025-11-09T20:48:30.87Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c6/f3041ede6d0ed5e0e79ff0de4c8f14f401bbf196f2ef3971cdbe5fd08d1d/jiter-0.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a947920902420a6ada6ad51892082521978e9dd44a802663b001436e4b771684", size = 345932, upload-time = "2025-11-09T20:48:32.658Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5d/4d94835889edd01ad0e2dbfc05f7bdfaed46292e7b504a6ac7839aa00edb/jiter-0.12.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:add5e227e0554d3a52cf390a7635edaffdf4f8fce4fdbcef3cc2055bb396a30c", size = 367243, upload-time = "2025-11-09T20:48:34.093Z" }, - { url = "https://files.pythonhosted.org/packages/fd/76/0051b0ac2816253a99d27baf3dda198663aff882fa6ea7deeb94046da24e/jiter-0.12.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9b1cda8fcb736250d7e8711d4580ebf004a46771432be0ae4796944b5dfa5d", size = 479315, upload-time = "2025-11-09T20:48:35.507Z" }, - { url = "https://files.pythonhosted.org/packages/70/ae/83f793acd68e5cb24e483f44f482a1a15601848b9b6f199dacb970098f77/jiter-0.12.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb12a2223fe0135c7ff1356a143d57f95bbf1f4a66584f1fc74df21d86b993", size = 380714, upload-time = "2025-11-09T20:48:40.014Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/4808a88338ad2c228b1126b93fcd8ba145e919e886fe910d578230dabe3b/jiter-0.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c596cc0f4cb574877550ce4ecd51f8037469146addd676d7c1a30ebe6391923f", size = 365168, upload-time = "2025-11-09T20:48:41.462Z" }, - { url = "https://files.pythonhosted.org/packages/0c/d4/04619a9e8095b42aef436b5aeb4c0282b4ff1b27d1db1508df9f5dc82750/jiter-0.12.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ab4c823b216a4aeab3fdbf579c5843165756bd9ad87cc6b1c65919c4715f783", size = 387893, upload-time = "2025-11-09T20:48:42.921Z" }, - { url = "https://files.pythonhosted.org/packages/17/ea/d3c7e62e4546fdc39197fa4a4315a563a89b95b6d54c0d25373842a59cbe/jiter-0.12.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e427eee51149edf962203ff8db75a7514ab89be5cb623fb9cea1f20b54f1107b", size = 520828, upload-time = "2025-11-09T20:48:44.278Z" }, - { url = "https://files.pythonhosted.org/packages/cc/0b/c6d3562a03fd767e31cb119d9041ea7958c3c80cb3d753eafb19b3b18349/jiter-0.12.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:edb868841f84c111255ba5e80339d386d937ec1fdce419518ce1bd9370fac5b6", size = 511009, upload-time = "2025-11-09T20:48:45.726Z" }, - { url = "https://files.pythonhosted.org/packages/aa/51/2cb4468b3448a8385ebcd15059d325c9ce67df4e2758d133ab9442b19834/jiter-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8bbcfe2791dfdb7c5e48baf646d37a6a3dcb5a97a032017741dea9f817dca183", size = 205110, upload-time = "2025-11-09T20:48:47.033Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c5/ae5ec83dec9c2d1af805fd5fe8f74ebded9c8670c5210ec7820ce0dbeb1e/jiter-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2fa940963bf02e1d8226027ef461e36af472dea85d36054ff835aeed944dd873", size = 205223, upload-time = "2025-11-09T20:48:49.076Z" }, - { url = "https://files.pythonhosted.org/packages/97/9a/3c5391907277f0e55195550cf3fa8e293ae9ee0c00fb402fec1e38c0c82f/jiter-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:506c9708dd29b27288f9f8f1140c3cb0e3d8ddb045956d7757b1fa0e0f39a473", size = 185564, upload-time = "2025-11-09T20:48:50.376Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/5339ef1ecaa881c6948669956567a64d2670941925f245c434f494ffb0e5/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8", size = 311144, upload-time = "2025-11-09T20:49:10.503Z" }, - { url = "https://files.pythonhosted.org/packages/27/74/3446c652bffbd5e81ab354e388b1b5fc1d20daac34ee0ed11ff096b1b01a/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3", size = 305877, upload-time = "2025-11-09T20:49:12.269Z" }, - { url = "https://files.pythonhosted.org/packages/a1/f4/ed76ef9043450f57aac2d4fbeb27175aa0eb9c38f833be6ef6379b3b9a86/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e", size = 340419, upload-time = "2025-11-09T20:49:13.803Z" }, - { url = "https://files.pythonhosted.org/packages/21/01/857d4608f5edb0664aa791a3d45702e1a5bcfff9934da74035e7b9803846/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d", size = 347212, upload-time = "2025-11-09T20:49:15.643Z" }, - { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974, upload-time = "2025-11-09T20:49:17.187Z" }, - { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233, upload-time = "2025-11-09T20:49:18.734Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537, upload-time = "2025-11-09T20:49:20.317Z" }, - { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110, upload-time = "2025-11-09T20:49:21.817Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652 }, + { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829 }, + { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568 }, + { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052 }, + { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585 }, + { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541 }, + { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423 }, + { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958 }, + { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084 }, + { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054 }, + { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368 }, + { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847 }, + { url = "https://files.pythonhosted.org/packages/32/f9/eaca4633486b527ebe7e681c431f529b63fe2709e7c5242fc0f43f77ce63/jiter-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8f8a7e317190b2c2d60eb2e8aa835270b008139562d70fe732e1c0020ec53c9", size = 316435 }, + { url = "https://files.pythonhosted.org/packages/10/c1/40c9f7c22f5e6ff715f28113ebaba27ab85f9af2660ad6e1dd6425d14c19/jiter-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2218228a077e784c6c8f1a8e5d6b8cb1dea62ce25811c356364848554b2056cd", size = 320548 }, + { url = "https://files.pythonhosted.org/packages/6b/1b/efbb68fe87e7711b00d2cfd1f26bb4bfc25a10539aefeaa7727329ffb9cb/jiter-0.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9354ccaa2982bf2188fd5f57f79f800ef622ec67beb8329903abf6b10da7d423", size = 351915 }, + { url = "https://files.pythonhosted.org/packages/15/2d/c06e659888c128ad1e838123d0638f0efad90cc30860cb5f74dd3f2fc0b3/jiter-0.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f2607185ea89b4af9a604d4c7ec40e45d3ad03ee66998b031134bc510232bb7", size = 368966 }, + { url = "https://files.pythonhosted.org/packages/6b/20/058db4ae5fb07cf6a4ab2e9b9294416f606d8e467fb74c2184b2a1eeacba/jiter-0.12.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a585a5e42d25f2e71db5f10b171f5e5ea641d3aa44f7df745aa965606111cc2", size = 482047 }, + { url = "https://files.pythonhosted.org/packages/49/bb/dc2b1c122275e1de2eb12905015d61e8316b2f888bdaac34221c301495d6/jiter-0.12.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd9e21d34edff5a663c631f850edcb786719c960ce887a5661e9c828a53a95d9", size = 380835 }, + { url = "https://files.pythonhosted.org/packages/23/7d/38f9cd337575349de16da575ee57ddb2d5a64d425c9367f5ef9e4612e32e/jiter-0.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a612534770470686cd5431478dc5a1b660eceb410abade6b1b74e320ca98de6", size = 364587 }, + { url = "https://files.pythonhosted.org/packages/f0/a3/b13e8e61e70f0bb06085099c4e2462647f53cc2ca97614f7fedcaa2bb9f3/jiter-0.12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3985aea37d40a908f887b34d05111e0aae822943796ebf8338877fee2ab67725", size = 390492 }, + { url = "https://files.pythonhosted.org/packages/07/71/e0d11422ed027e21422f7bc1883c61deba2d9752b720538430c1deadfbca/jiter-0.12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b1207af186495f48f72529f8d86671903c8c10127cac6381b11dddc4aaa52df6", size = 522046 }, + { url = "https://files.pythonhosted.org/packages/9f/59/b968a9aa7102a8375dbbdfbd2aeebe563c7e5dddf0f47c9ef1588a97e224/jiter-0.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef2fb241de583934c9915a33120ecc06d94aa3381a134570f59eed784e87001e", size = 513392 }, + { url = "https://files.pythonhosted.org/packages/ca/e4/7df62002499080dbd61b505c5cb351aa09e9959d176cac2aa8da6f93b13b/jiter-0.12.0-cp311-cp311-win32.whl", hash = "sha256:453b6035672fecce8007465896a25b28a6b59cfe8fbc974b2563a92f5a92a67c", size = 206096 }, + { url = "https://files.pythonhosted.org/packages/bb/60/1032b30ae0572196b0de0e87dce3b6c26a1eff71aad5fe43dee3082d32e0/jiter-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:ca264b9603973c2ad9435c71a8ec8b49f8f715ab5ba421c85a51cde9887e421f", size = 204899 }, + { url = "https://files.pythonhosted.org/packages/49/d5/c145e526fccdb834063fb45c071df78b0cc426bbaf6de38b0781f45d956f/jiter-0.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:cb00ef392e7d684f2754598c02c409f376ddcef857aae796d559e6cacc2d78a5", size = 188070 }, + { url = "https://files.pythonhosted.org/packages/92/c9/5b9f7b4983f1b542c64e84165075335e8a236fa9e2ea03a0c79780062be8/jiter-0.12.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:305e061fa82f4680607a775b2e8e0bcb071cd2205ac38e6ef48c8dd5ebe1cf37", size = 314449 }, + { url = "https://files.pythonhosted.org/packages/98/6e/e8efa0e78de00db0aee82c0cf9e8b3f2027efd7f8a71f859d8f4be8e98ef/jiter-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c1860627048e302a528333c9307c818c547f214d8659b0705d2195e1a94b274", size = 319855 }, + { url = "https://files.pythonhosted.org/packages/20/26/894cd88e60b5d58af53bec5c6759d1292bd0b37a8b5f60f07abf7a63ae5f/jiter-0.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df37577a4f8408f7e0ec3205d2a8f87672af8f17008358063a4d6425b6081ce3", size = 350171 }, + { url = "https://files.pythonhosted.org/packages/f5/27/a7b818b9979ac31b3763d25f3653ec3a954044d5e9f5d87f2f247d679fd1/jiter-0.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fdd787356c1c13a4f40b43c2156276ef7a71eb487d98472476476d803fb2cf", size = 365590 }, + { url = "https://files.pythonhosted.org/packages/ba/7e/e46195801a97673a83746170b17984aa8ac4a455746354516d02ca5541b4/jiter-0.12.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1eb5db8d9c65b112aacf14fcd0faae9913d07a8afea5ed06ccdd12b724e966a1", size = 479462 }, + { url = "https://files.pythonhosted.org/packages/ca/75/f833bfb009ab4bd11b1c9406d333e3b4357709ed0570bb48c7c06d78c7dd/jiter-0.12.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73c568cc27c473f82480abc15d1301adf333a7ea4f2e813d6a2c7d8b6ba8d0df", size = 378983 }, + { url = "https://files.pythonhosted.org/packages/71/b3/7a69d77943cc837d30165643db753471aff5df39692d598da880a6e51c24/jiter-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4321e8a3d868919bcb1abb1db550d41f2b5b326f72df29e53b2df8b006eb9403", size = 361328 }, + { url = "https://files.pythonhosted.org/packages/b0/ac/a78f90caf48d65ba70d8c6efc6f23150bc39dc3389d65bbec2a95c7bc628/jiter-0.12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a51bad79f8cc9cac2b4b705039f814049142e0050f30d91695a2d9a6611f126", size = 386740 }, + { url = "https://files.pythonhosted.org/packages/39/b6/5d31c2cc8e1b6a6bcf3c5721e4ca0a3633d1ab4754b09bc7084f6c4f5327/jiter-0.12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a67b678f6a5f1dd6c36d642d7db83e456bc8b104788262aaefc11a22339f5a9", size = 520875 }, + { url = "https://files.pythonhosted.org/packages/30/b5/4df540fae4e9f68c54b8dab004bd8c943a752f0b00efd6e7d64aa3850339/jiter-0.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efe1a211fe1fd14762adea941e3cfd6c611a136e28da6c39272dbb7a1bbe6a86", size = 511457 }, + { url = "https://files.pythonhosted.org/packages/07/65/86b74010e450a1a77b2c1aabb91d4a91dd3cd5afce99f34d75fd1ac64b19/jiter-0.12.0-cp312-cp312-win32.whl", hash = "sha256:d779d97c834b4278276ec703dc3fc1735fca50af63eb7262f05bdb4e62203d44", size = 204546 }, + { url = "https://files.pythonhosted.org/packages/1c/c7/6659f537f9562d963488e3e55573498a442503ced01f7e169e96a6110383/jiter-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8269062060212b373316fe69236096aaf4c49022d267c6736eebd66bbbc60bb", size = 205196 }, + { url = "https://files.pythonhosted.org/packages/21/f4/935304f5169edadfec7f9c01eacbce4c90bb9a82035ac1de1f3bd2d40be6/jiter-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:06cb970936c65de926d648af0ed3d21857f026b1cf5525cb2947aa5e01e05789", size = 186100 }, + { url = "https://files.pythonhosted.org/packages/3d/a6/97209693b177716e22576ee1161674d1d58029eb178e01866a0422b69224/jiter-0.12.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6cc49d5130a14b732e0612bc76ae8db3b49898732223ef8b7599aa8d9810683e", size = 313658 }, + { url = "https://files.pythonhosted.org/packages/06/4d/125c5c1537c7d8ee73ad3d530a442d6c619714b95027143f1b61c0b4dfe0/jiter-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37f27a32ce36364d2fa4f7fdc507279db604d27d239ea2e044c8f148410defe1", size = 318605 }, + { url = "https://files.pythonhosted.org/packages/99/bf/a840b89847885064c41a5f52de6e312e91fa84a520848ee56c97e4fa0205/jiter-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc0944aa3d4b4773e348cda635252824a78f4ba44328e042ef1ff3f6080d1cf", size = 349803 }, + { url = "https://files.pythonhosted.org/packages/8a/88/e63441c28e0db50e305ae23e19c1d8fae012d78ed55365da392c1f34b09c/jiter-0.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da25c62d4ee1ffbacb97fac6dfe4dcd6759ebdc9015991e92a6eae5816287f44", size = 365120 }, + { url = "https://files.pythonhosted.org/packages/0a/7c/49b02714af4343970eb8aca63396bc1c82fa01197dbb1e9b0d274b550d4e/jiter-0.12.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:048485c654b838140b007390b8182ba9774621103bd4d77c9c3f6f117474ba45", size = 479918 }, + { url = "https://files.pythonhosted.org/packages/69/ba/0a809817fdd5a1db80490b9150645f3aae16afad166960bcd562be194f3b/jiter-0.12.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:635e737fbb7315bef0037c19b88b799143d2d7d3507e61a76751025226b3ac87", size = 379008 }, + { url = "https://files.pythonhosted.org/packages/5f/c3/c9fc0232e736c8877d9e6d83d6eeb0ba4e90c6c073835cc2e8f73fdeef51/jiter-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e017c417b1ebda911bd13b1e40612704b1f5420e30695112efdbed8a4b389ed", size = 361785 }, + { url = "https://files.pythonhosted.org/packages/96/61/61f69b7e442e97ca6cd53086ddc1cf59fb830549bc72c0a293713a60c525/jiter-0.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:89b0bfb8b2bf2351fba36bb211ef8bfceba73ef58e7f0c68fb67b5a2795ca2f9", size = 386108 }, + { url = "https://files.pythonhosted.org/packages/e9/2e/76bb3332f28550c8f1eba3bf6e5efe211efda0ddbbaf24976bc7078d42a5/jiter-0.12.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:f5aa5427a629a824a543672778c9ce0c5e556550d1569bb6ea28a85015287626", size = 519937 }, + { url = "https://files.pythonhosted.org/packages/84/d6/fa96efa87dc8bff2094fb947f51f66368fa56d8d4fc9e77b25d7fbb23375/jiter-0.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed53b3d6acbcb0fd0b90f20c7cb3b24c357fe82a3518934d4edfa8c6898e498c", size = 510853 }, + { url = "https://files.pythonhosted.org/packages/8a/28/93f67fdb4d5904a708119a6ab58a8f1ec226ff10a94a282e0215402a8462/jiter-0.12.0-cp313-cp313-win32.whl", hash = "sha256:4747de73d6b8c78f2e253a2787930f4fffc68da7fa319739f57437f95963c4de", size = 204699 }, + { url = "https://files.pythonhosted.org/packages/c4/1f/30b0eb087045a0abe2a5c9c0c0c8da110875a1d3be83afd4a9a4e548be3c/jiter-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e25012eb0c456fcc13354255d0338cd5397cce26c77b2832b3c4e2e255ea5d9a", size = 204258 }, + { url = "https://files.pythonhosted.org/packages/2c/f4/2b4daf99b96bce6fc47971890b14b2a36aef88d7beb9f057fafa032c6141/jiter-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:c97b92c54fe6110138c872add030a1f99aea2401ddcdaa21edf74705a646dd60", size = 185503 }, + { url = "https://files.pythonhosted.org/packages/39/ca/67bb15a7061d6fe20b9b2a2fd783e296a1e0f93468252c093481a2f00efa/jiter-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53839b35a38f56b8be26a7851a48b89bc47e5d88e900929df10ed93b95fea3d6", size = 317965 }, + { url = "https://files.pythonhosted.org/packages/18/af/1788031cd22e29c3b14bc6ca80b16a39a0b10e611367ffd480c06a259831/jiter-0.12.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f669548e55c91ab47fef8bddd9c954dab1938644e715ea49d7e117015110a4", size = 345831 }, + { url = "https://files.pythonhosted.org/packages/05/17/710bf8472d1dff0d3caf4ced6031060091c1320f84ee7d5dcbed1f352417/jiter-0.12.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:351d54f2b09a41600ffea43d081522d792e81dcfb915f6d2d242744c1cc48beb", size = 361272 }, + { url = "https://files.pythonhosted.org/packages/fb/f1/1dcc4618b59761fef92d10bcbb0b038b5160be653b003651566a185f1a5c/jiter-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2a5e90604620f94bf62264e7c2c038704d38217b7465b863896c6d7c902b06c7", size = 204604 }, + { url = "https://files.pythonhosted.org/packages/d9/32/63cb1d9f1c5c6632a783c0052cde9ef7ba82688f7065e2f0d5f10a7e3edb/jiter-0.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:88ef757017e78d2860f96250f9393b7b577b06a956ad102c29c8237554380db3", size = 185628 }, + { url = "https://files.pythonhosted.org/packages/a8/99/45c9f0dbe4a1416b2b9a8a6d1236459540f43d7fb8883cff769a8db0612d/jiter-0.12.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c46d927acd09c67a9fb1416df45c5a04c27e83aae969267e98fba35b74e99525", size = 312478 }, + { url = "https://files.pythonhosted.org/packages/4c/a7/54ae75613ba9e0f55fcb0bc5d1f807823b5167cc944e9333ff322e9f07dd/jiter-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:774ff60b27a84a85b27b88cd5583899c59940bcc126caca97eb2a9df6aa00c49", size = 318706 }, + { url = "https://files.pythonhosted.org/packages/59/31/2aa241ad2c10774baf6c37f8b8e1f39c07db358f1329f4eb40eba179c2a2/jiter-0.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5433fab222fb072237df3f637d01b81f040a07dcac1cb4a5c75c7aa9ed0bef1", size = 351894 }, + { url = "https://files.pythonhosted.org/packages/54/4f/0f2759522719133a9042781b18cc94e335b6d290f5e2d3e6899d6af933e3/jiter-0.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8c593c6e71c07866ec6bfb790e202a833eeec885022296aff6b9e0b92d6a70e", size = 365714 }, + { url = "https://files.pythonhosted.org/packages/dc/6f/806b895f476582c62a2f52c453151edd8a0fde5411b0497baaa41018e878/jiter-0.12.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d32894d4c6877a87ae00c6b915b609406819dce8bc0d4e962e4de2784e567e", size = 478989 }, + { url = "https://files.pythonhosted.org/packages/86/6c/012d894dc6e1033acd8db2b8346add33e413ec1c7c002598915278a37f79/jiter-0.12.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:798e46eed9eb10c3adbbacbd3bdb5ecd4cf7064e453d00dbef08802dae6937ff", size = 378615 }, + { url = "https://files.pythonhosted.org/packages/87/30/d718d599f6700163e28e2c71c0bbaf6dace692e7df2592fd793ac9276717/jiter-0.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f1368f0a6719ea80013a4eb90ba72e75d7ea67cfc7846db2ca504f3df0169a", size = 364745 }, + { url = "https://files.pythonhosted.org/packages/8f/85/315b45ce4b6ddc7d7fceca24068543b02bdc8782942f4ee49d652e2cc89f/jiter-0.12.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65f04a9d0b4406f7e51279710b27484af411896246200e461d80d3ba0caa901a", size = 386502 }, + { url = "https://files.pythonhosted.org/packages/74/0b/ce0434fb40c5b24b368fe81b17074d2840748b4952256bab451b72290a49/jiter-0.12.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:fd990541982a24281d12b67a335e44f117e4c6cbad3c3b75c7dea68bf4ce3a67", size = 519845 }, + { url = "https://files.pythonhosted.org/packages/e8/a3/7a7a4488ba052767846b9c916d208b3ed114e3eb670ee984e4c565b9cf0d/jiter-0.12.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b111b0e9152fa7df870ecaebb0bd30240d9f7fff1f2003bcb4ed0f519941820b", size = 510701 }, + { url = "https://files.pythonhosted.org/packages/c3/16/052ffbf9d0467b70af24e30f91e0579e13ded0c17bb4a8eb2aed3cb60131/jiter-0.12.0-cp314-cp314-win32.whl", hash = "sha256:a78befb9cc0a45b5a5a0d537b06f8544c2ebb60d19d02c41ff15da28a9e22d42", size = 205029 }, + { url = "https://files.pythonhosted.org/packages/e4/18/3cf1f3f0ccc789f76b9a754bdb7a6977e5d1d671ee97a9e14f7eb728d80e/jiter-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:e1fe01c082f6aafbe5c8faf0ff074f38dfb911d53f07ec333ca03f8f6226debf", size = 204960 }, + { url = "https://files.pythonhosted.org/packages/02/68/736821e52ecfdeeb0f024b8ab01b5a229f6b9293bbdb444c27efade50b0f/jiter-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:d72f3b5a432a4c546ea4bedc84cce0c3404874f1d1676260b9c7f048a9855451", size = 185529 }, + { url = "https://files.pythonhosted.org/packages/30/61/12ed8ee7a643cce29ac97c2281f9ce3956eb76b037e88d290f4ed0d41480/jiter-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e6ded41aeba3603f9728ed2b6196e4df875348ab97b28fc8afff115ed42ba7a7", size = 318974 }, + { url = "https://files.pythonhosted.org/packages/2d/c6/f3041ede6d0ed5e0e79ff0de4c8f14f401bbf196f2ef3971cdbe5fd08d1d/jiter-0.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a947920902420a6ada6ad51892082521978e9dd44a802663b001436e4b771684", size = 345932 }, + { url = "https://files.pythonhosted.org/packages/d5/5d/4d94835889edd01ad0e2dbfc05f7bdfaed46292e7b504a6ac7839aa00edb/jiter-0.12.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:add5e227e0554d3a52cf390a7635edaffdf4f8fce4fdbcef3cc2055bb396a30c", size = 367243 }, + { url = "https://files.pythonhosted.org/packages/fd/76/0051b0ac2816253a99d27baf3dda198663aff882fa6ea7deeb94046da24e/jiter-0.12.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9b1cda8fcb736250d7e8711d4580ebf004a46771432be0ae4796944b5dfa5d", size = 479315 }, + { url = "https://files.pythonhosted.org/packages/70/ae/83f793acd68e5cb24e483f44f482a1a15601848b9b6f199dacb970098f77/jiter-0.12.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb12a2223fe0135c7ff1356a143d57f95bbf1f4a66584f1fc74df21d86b993", size = 380714 }, + { url = "https://files.pythonhosted.org/packages/b1/5e/4808a88338ad2c228b1126b93fcd8ba145e919e886fe910d578230dabe3b/jiter-0.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c596cc0f4cb574877550ce4ecd51f8037469146addd676d7c1a30ebe6391923f", size = 365168 }, + { url = "https://files.pythonhosted.org/packages/0c/d4/04619a9e8095b42aef436b5aeb4c0282b4ff1b27d1db1508df9f5dc82750/jiter-0.12.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ab4c823b216a4aeab3fdbf579c5843165756bd9ad87cc6b1c65919c4715f783", size = 387893 }, + { url = "https://files.pythonhosted.org/packages/17/ea/d3c7e62e4546fdc39197fa4a4315a563a89b95b6d54c0d25373842a59cbe/jiter-0.12.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e427eee51149edf962203ff8db75a7514ab89be5cb623fb9cea1f20b54f1107b", size = 520828 }, + { url = "https://files.pythonhosted.org/packages/cc/0b/c6d3562a03fd767e31cb119d9041ea7958c3c80cb3d753eafb19b3b18349/jiter-0.12.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:edb868841f84c111255ba5e80339d386d937ec1fdce419518ce1bd9370fac5b6", size = 511009 }, + { url = "https://files.pythonhosted.org/packages/aa/51/2cb4468b3448a8385ebcd15059d325c9ce67df4e2758d133ab9442b19834/jiter-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8bbcfe2791dfdb7c5e48baf646d37a6a3dcb5a97a032017741dea9f817dca183", size = 205110 }, + { url = "https://files.pythonhosted.org/packages/b2/c5/ae5ec83dec9c2d1af805fd5fe8f74ebded9c8670c5210ec7820ce0dbeb1e/jiter-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2fa940963bf02e1d8226027ef461e36af472dea85d36054ff835aeed944dd873", size = 205223 }, + { url = "https://files.pythonhosted.org/packages/97/9a/3c5391907277f0e55195550cf3fa8e293ae9ee0c00fb402fec1e38c0c82f/jiter-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:506c9708dd29b27288f9f8f1140c3cb0e3d8ddb045956d7757b1fa0e0f39a473", size = 185564 }, ] [[package]] name = "joblib" version = "1.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396 }, ] [[package]] name = "json5" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/ae/929aee9619e9eba9015207a9d2c1c54db18311da7eb4dcf6d41ad6f0eb67/json5-0.12.1.tar.gz", hash = "sha256:b2743e77b3242f8d03c143dd975a6ec7c52e2f2afe76ed934e53503dd4ad4990", size = 52191, upload-time = "2025-08-12T19:47:42.583Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/ae/929aee9619e9eba9015207a9d2c1c54db18311da7eb4dcf6d41ad6f0eb67/json5-0.12.1.tar.gz", hash = "sha256:b2743e77b3242f8d03c143dd975a6ec7c52e2f2afe76ed934e53503dd4ad4990", size = 52191 } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/e2/05328bd2621be49a6fed9e3030b1e51a2d04537d3f816d211b9cc53c5262/json5-0.12.1-py3-none-any.whl", hash = "sha256:d9c9b3bc34a5f54d43c35e11ef7cb87d8bdd098c6ace87117a7b7e83e705c1d5", size = 36119, upload-time = "2025-08-12T19:47:41.131Z" }, + { url = "https://files.pythonhosted.org/packages/85/e2/05328bd2621be49a6fed9e3030b1e51a2d04537d3f816d211b9cc53c5262/json5-0.12.1-py3-none-any.whl", hash = "sha256:d9c9b3bc34a5f54d43c35e11ef7cb87d8bdd098c6ace87117a7b7e83e705c1d5", size = 36119 }, ] [[package]] @@ -1399,9 +1391,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpointer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" }, + { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898 }, ] [[package]] @@ -1411,18 +1403,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ply" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/86/08646239a313f895186ff0a4573452038eed8c86f54380b3ebac34d32fb2/jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c", size = 37838, upload-time = "2024-10-11T15:41:42.404Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/86/08646239a313f895186ff0a4573452038eed8c86f54380b3ebac34d32fb2/jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c", size = 37838 } wheels = [ - { url = "https://files.pythonhosted.org/packages/35/5a/73ecb3d82f8615f32ccdadeb9356726d6cae3a4bbc840b437ceb95708063/jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6", size = 30105, upload-time = "2024-11-20T17:58:30.418Z" }, + { url = "https://files.pythonhosted.org/packages/35/5a/73ecb3d82f8615f32ccdadeb9356726d6cae3a4bbc840b437ceb95708063/jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6", size = 30105 }, ] [[package]] name = "jsonpointer" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114 } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595 }, ] [[package]] @@ -1435,9 +1427,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040 }, ] [package.optional-dependencies] @@ -1460,9 +1452,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 } 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 }, ] [[package]] @@ -1477,9 +1469,9 @@ dependencies = [ { name = "nbconvert" }, { name = "notebook" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657 }, ] [[package]] @@ -1493,9 +1485,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019 } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105 }, ] [[package]] @@ -1513,9 +1505,9 @@ dependencies = [ { name = "pyzmq" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510 }, ] [[package]] @@ -1526,9 +1518,9 @@ dependencies = [ { name = "platformdirs" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, ] [[package]] @@ -1545,9 +1537,9 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, ] [[package]] @@ -1557,9 +1549,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687 }, ] [[package]] @@ -1587,9 +1579,9 @@ dependencies = [ { name = "traitlets" }, { name = "websocket-client" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221 }, ] [[package]] @@ -1600,9 +1592,9 @@ dependencies = [ { name = "pywinpty", marker = "os_name == 'nt'" }, { name = "terminado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, + { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656 }, ] [[package]] @@ -1625,18 +1617,18 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/e5/4fa382a796a6d8e2cd867816b64f1ff27f906e43a7a83ad9eb389e448cd8/jupyterlab-4.5.0.tar.gz", hash = "sha256:aec33d6d8f1225b495ee2cf20f0514f45e6df8e360bdd7ac9bace0b7ac5177ea", size = 23989880, upload-time = "2025-11-18T13:19:00.365Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/e5/4fa382a796a6d8e2cd867816b64f1ff27f906e43a7a83ad9eb389e448cd8/jupyterlab-4.5.0.tar.gz", hash = "sha256:aec33d6d8f1225b495ee2cf20f0514f45e6df8e360bdd7ac9bace0b7ac5177ea", size = 23989880 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/1e/5a4d5498eba382fee667ed797cf64ae5d1b13b04356df62f067f48bb0f61/jupyterlab-4.5.0-py3-none-any.whl", hash = "sha256:88e157c75c1afff64c7dc4b801ec471450b922a4eae4305211ddd40da8201c8a", size = 12380641, upload-time = "2025-11-18T13:18:56.252Z" }, + { url = "https://files.pythonhosted.org/packages/6c/1e/5a4d5498eba382fee667ed797cf64ae5d1b13b04356df62f067f48bb0f61/jupyterlab-4.5.0-py3-none-any.whl", hash = "sha256:88e157c75c1afff64c7dc4b801ec471450b922a4eae4305211ddd40da8201c8a", size = 12380641 }, ] [[package]] name = "jupyterlab-pygments" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, ] [[package]] @@ -1652,18 +1644,18 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830 }, ] [[package]] name = "jupyterlab-widgets" version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, ] [[package]] @@ -1675,9 +1667,9 @@ dependencies = [ { name = "langgraph" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/06/be7273c6c15f5a7e64788ed2aa6329dd019170a176977acff7bcde2cdea2/langchain-1.1.0.tar.gz", hash = "sha256:583c892f59873c0329dbe04169fb3234ac794c50780e7c6fb62a61c7b86a981b", size = 528416, upload-time = "2025-11-24T15:31:24.47Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/06/be7273c6c15f5a7e64788ed2aa6329dd019170a176977acff7bcde2cdea2/langchain-1.1.0.tar.gz", hash = "sha256:583c892f59873c0329dbe04169fb3234ac794c50780e7c6fb62a61c7b86a981b", size = 528416 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/6f/889c01d22c84934615fa3f2dcf94c2fe76fd0afa7a7d01f9b798059f0ecc/langchain-1.1.0-py3-none-any.whl", hash = "sha256:af080f3a4a779bfa5925de7aacb6dfab83249d4aab9a08f7aa7b9bec3766d8ea", size = 101797, upload-time = "2025-11-24T15:31:23.401Z" }, + { url = "https://files.pythonhosted.org/packages/0b/6f/889c01d22c84934615fa3f2dcf94c2fe76fd0afa7a7d01f9b798059f0ecc/langchain-1.1.0-py3-none-any.whl", hash = "sha256:af080f3a4a779bfa5925de7aacb6dfab83249d4aab9a08f7aa7b9bec3766d8ea", size = 101797 }, ] [[package]] @@ -1694,9 +1686,9 @@ dependencies = [ { name = "requests" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/b1/a66babeccb2c05ed89690a534296688c0349bee7a71641e91ecc2afd72fd/langchain_classic-1.0.0.tar.gz", hash = "sha256:a63655609254ebc36d660eb5ad7c06c778b2e6733c615ffdac3eac4fbe2b12c5", size = 10514930, upload-time = "2025-10-17T16:02:47.887Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/b1/a66babeccb2c05ed89690a534296688c0349bee7a71641e91ecc2afd72fd/langchain_classic-1.0.0.tar.gz", hash = "sha256:a63655609254ebc36d660eb5ad7c06c778b2e6733c615ffdac3eac4fbe2b12c5", size = 10514930 } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/74/246f809a3741c21982f985ca0113ec92d3c84896308561cc4414823f6951/langchain_classic-1.0.0-py3-none-any.whl", hash = "sha256:97f71f150c10123f5511c08873f030e35ede52311d729a7688c721b4e1e01f33", size = 1040701, upload-time = "2025-10-17T16:02:46.35Z" }, + { url = "https://files.pythonhosted.org/packages/74/74/246f809a3741c21982f985ca0113ec92d3c84896308561cc4414823f6951/langchain_classic-1.0.0-py3-none-any.whl", hash = "sha256:97f71f150c10123f5511c08873f030e35ede52311d729a7688c721b4e1e01f33", size = 1040701 }, ] [[package]] @@ -1718,9 +1710,9 @@ dependencies = [ { name = "sqlalchemy" }, { name = "tenacity" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/97/a03585d42b9bdb6fbd935282d6e3348b10322a24e6ce12d0c99eb461d9af/langchain_community-0.4.1.tar.gz", hash = "sha256:f3b211832728ee89f169ddce8579b80a085222ddb4f4ed445a46e977d17b1e85", size = 33241144, upload-time = "2025-10-27T15:20:32.504Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/97/a03585d42b9bdb6fbd935282d6e3348b10322a24e6ce12d0c99eb461d9af/langchain_community-0.4.1.tar.gz", hash = "sha256:f3b211832728ee89f169ddce8579b80a085222ddb4f4ed445a46e977d17b1e85", size = 33241144 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/a4/c4fde67f193401512337456cabc2148f2c43316e445f5decd9f8806e2992/langchain_community-0.4.1-py3-none-any.whl", hash = "sha256:2135abb2c7748a35c84613108f7ebf30f8505b18c3c18305ffaecfc7651f6c6a", size = 2533285, upload-time = "2025-10-27T15:20:30.767Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a4/c4fde67f193401512337456cabc2148f2c43316e445f5decd9f8806e2992/langchain_community-0.4.1-py3-none-any.whl", hash = "sha256:2135abb2c7748a35c84613108f7ebf30f8505b18c3c18305ffaecfc7651f6c6a", size = 2533285 }, ] [[package]] @@ -1736,9 +1728,9 @@ dependencies = [ { name = "tenacity" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/17/67c1cc2ace919e2b02dd9d783154d7fb3f1495a4ef835d9cd163b7855ac2/langchain_core-1.1.0.tar.gz", hash = "sha256:2b76a82d427922c8bc51c08404af4fc2a29e9f161dfe2297cb05091e810201e7", size = 781995, upload-time = "2025-11-21T21:01:26.958Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/17/67c1cc2ace919e2b02dd9d783154d7fb3f1495a4ef835d9cd163b7855ac2/langchain_core-1.1.0.tar.gz", hash = "sha256:2b76a82d427922c8bc51c08404af4fc2a29e9f161dfe2297cb05091e810201e7", size = 781995 } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/1e/e129fc471a2d2a7b3804480a937b5ab9319cab9f4142624fcb115f925501/langchain_core-1.1.0-py3-none-any.whl", hash = "sha256:2c9f27dadc6d21ed4aa46506a37a56e6a7e2d2f9141922dc5c251ba921822ee6", size = 473752, upload-time = "2025-11-21T21:01:25.841Z" }, + { url = "https://files.pythonhosted.org/packages/71/1e/e129fc471a2d2a7b3804480a937b5ab9319cab9f4142624fcb115f925501/langchain_core-1.1.0-py3-none-any.whl", hash = "sha256:2c9f27dadc6d21ed4aa46506a37a56e6a7e2d2f9141922dc5c251ba921822ee6", size = 473752 }, ] [[package]] @@ -1749,9 +1741,9 @@ dependencies = [ { name = "langchain-community" }, { name = "langchain-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/ed/7015b38cdc0c5b3c24d163217a6f557e876fe5f5de8b5780e260279c30da/langchain_experimental-0.4.0.tar.gz", hash = "sha256:16bb5c9810e1908c0e2d82cd000bb434bb437b8977507e4dbfe5f25800f431fd", size = 169936, upload-time = "2025-11-10T16:34:02.981Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/ed/7015b38cdc0c5b3c24d163217a6f557e876fe5f5de8b5780e260279c30da/langchain_experimental-0.4.0.tar.gz", hash = "sha256:16bb5c9810e1908c0e2d82cd000bb434bb437b8977507e4dbfe5f25800f431fd", size = 169936 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/37/1a87bc4374a00dfdc73ff5b2d6bc63454421db280dc582cadd3c26dd92d3/langchain_experimental-0.4.0-py3-none-any.whl", hash = "sha256:50306e75218e3a3f002de3dd879d719addd6481284b1a282292fac46a130f4a1", size = 209615, upload-time = "2025-11-10T16:34:01.992Z" }, + { url = "https://files.pythonhosted.org/packages/3a/37/1a87bc4374a00dfdc73ff5b2d6bc63454421db280dc582cadd3c26dd92d3/langchain_experimental-0.4.0-py3-none-any.whl", hash = "sha256:50306e75218e3a3f002de3dd879d719addd6481284b1a282292fac46a130f4a1", size = 209615 }, ] [[package]] @@ -1763,9 +1755,9 @@ dependencies = [ { name = "langchain-core" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/d7/ffcf97cd977c535df2c621c59eafa82df73f801323f670d88819c23fc304/langchain_huggingface-1.1.0.tar.gz", hash = "sha256:43c3b06413158b0cd1edcdbadf545c24d5f64f180bb71c80dc960959a728c1fd", size = 252295, upload-time = "2025-11-24T14:18:30.366Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/d7/ffcf97cd977c535df2c621c59eafa82df73f801323f670d88819c23fc304/langchain_huggingface-1.1.0.tar.gz", hash = "sha256:43c3b06413158b0cd1edcdbadf545c24d5f64f180bb71c80dc960959a728c1fd", size = 252295 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/4b/2bdd63464a7bb3aa7911777636cff8e54a2a1edc7b7a85a4acb7decebb23/langchain_huggingface-1.1.0-py3-none-any.whl", hash = "sha256:a3a5218a839062941cb616992bcbc4fe73352454727bafc351a452e76aead1a8", size = 29925, upload-time = "2025-11-24T14:18:29.036Z" }, + { url = "https://files.pythonhosted.org/packages/b1/4b/2bdd63464a7bb3aa7911777636cff8e54a2a1edc7b7a85a4acb7decebb23/langchain_huggingface-1.1.0-py3-none-any.whl", hash = "sha256:a3a5218a839062941cb616992bcbc4fe73352454727bafc351a452e76aead1a8", size = 29925 }, ] [[package]] @@ -1777,9 +1769,9 @@ dependencies = [ { name = "openai" }, { name = "tiktoken" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/18/29/cc7a7d1c42d19c903efa3ef9c9f00042942d28a00da1af12be5b7035375d/langchain_openai-1.1.0.tar.gz", hash = "sha256:9a33280c2e8315d013d64e6b15e583be347beb0d0f281755c335ae504ad0c184", size = 1034339, upload-time = "2025-11-24T14:20:48.929Z" } +sdist = { url = "https://files.pythonhosted.org/packages/18/29/cc7a7d1c42d19c903efa3ef9c9f00042942d28a00da1af12be5b7035375d/langchain_openai-1.1.0.tar.gz", hash = "sha256:9a33280c2e8315d013d64e6b15e583be347beb0d0f281755c335ae504ad0c184", size = 1034339 } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/ff/82699ef76f36818d86571a0b086ce07af5503a63d7430fc49e7d6aeb5dc1/langchain_openai-1.1.0-py3-none-any.whl", hash = "sha256:243bb345d0260ea1326c2b6ac2237ec29f082ab457c59e9306bac349df4577e8", size = 84282, upload-time = "2025-11-24T14:20:47.717Z" }, + { url = "https://files.pythonhosted.org/packages/da/ff/82699ef76f36818d86571a0b086ce07af5503a63d7430fc49e7d6aeb5dc1/langchain_openai-1.1.0-py3-none-any.whl", hash = "sha256:243bb345d0260ea1326c2b6ac2237ec29f082ab457c59e9306bac349df4577e8", size = 84282 }, ] [[package]] @@ -1789,9 +1781,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/2e/c833dcc379c1c086453708ef5eef7d4d1f808559ca4458bd6569d5d83ad7/langchain_text_splitters-1.0.0.tar.gz", hash = "sha256:d8580a20ad7ed10b432feb273e5758b2cc0902d094919629cec0e1ad691a6744", size = 264257, upload-time = "2025-10-17T14:33:41.743Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/2e/c833dcc379c1c086453708ef5eef7d4d1f808559ca4458bd6569d5d83ad7/langchain_text_splitters-1.0.0.tar.gz", hash = "sha256:d8580a20ad7ed10b432feb273e5758b2cc0902d094919629cec0e1ad691a6744", size = 264257 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/97/d362353ab04f865af6f81d4d46e7aa428734aa032de0017934b771fc34b7/langchain_text_splitters-1.0.0-py3-none-any.whl", hash = "sha256:f00c8219d3468f2c5bd951b708b6a7dd9bc3c62d0cfb83124c377f7170f33b2e", size = 33851, upload-time = "2025-10-17T14:33:40.46Z" }, + { url = "https://files.pythonhosted.org/packages/1e/97/d362353ab04f865af6f81d4d46e7aa428734aa032de0017934b771fc34b7/langchain_text_splitters-1.0.0-py3-none-any.whl", hash = "sha256:f00c8219d3468f2c5bd951b708b6a7dd9bc3c62d0cfb83124c377f7170f33b2e", size = 33851 }, ] [[package]] @@ -1806,9 +1798,9 @@ dependencies = [ { name = "pydantic" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/3c/af87902d300c1f467165558c8966d8b1e1f896dace271d3f35a410a5c26a/langgraph-1.0.4.tar.gz", hash = "sha256:86d08e25d7244340f59c5200fa69fdd11066aa999b3164b531e2a20036fac156", size = 484397, upload-time = "2025-11-25T20:31:48.608Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/3c/af87902d300c1f467165558c8966d8b1e1f896dace271d3f35a410a5c26a/langgraph-1.0.4.tar.gz", hash = "sha256:86d08e25d7244340f59c5200fa69fdd11066aa999b3164b531e2a20036fac156", size = 484397 } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/52/4eb25a3f60399da34ba34adff1b3e324cf0d87eb7a08cebf1882a9b5e0d5/langgraph-1.0.4-py3-none-any.whl", hash = "sha256:b1a835ceb0a8d69b9db48075e1939e28b1ad70ee23fa3fa8f90149904778bacf", size = 157271, upload-time = "2025-11-25T20:31:47.518Z" }, + { url = "https://files.pythonhosted.org/packages/14/52/4eb25a3f60399da34ba34adff1b3e324cf0d87eb7a08cebf1882a9b5e0d5/langgraph-1.0.4-py3-none-any.whl", hash = "sha256:b1a835ceb0a8d69b9db48075e1939e28b1ad70ee23fa3fa8f90149904778bacf", size = 157271 }, ] [[package]] @@ -1819,9 +1811,9 @@ dependencies = [ { name = "langchain-core" }, { name = "ormsgpack" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0f/07/2b1c042fa87d40cf2db5ca27dc4e8dd86f9a0436a10aa4361a8982718ae7/langgraph_checkpoint-3.0.1.tar.gz", hash = "sha256:59222f875f85186a22c494aedc65c4e985a3df27e696e5016ba0b98a5ed2cee0", size = 137785, upload-time = "2025-11-04T21:55:47.774Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/07/2b1c042fa87d40cf2db5ca27dc4e8dd86f9a0436a10aa4361a8982718ae7/langgraph_checkpoint-3.0.1.tar.gz", hash = "sha256:59222f875f85186a22c494aedc65c4e985a3df27e696e5016ba0b98a5ed2cee0", size = 137785 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl", hash = "sha256:9b04a8d0edc0474ce4eaf30c5d731cee38f11ddff50a6177eead95b5c4e4220b", size = 46249, upload-time = "2025-11-04T21:55:46.472Z" }, + { url = "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl", hash = "sha256:9b04a8d0edc0474ce4eaf30c5d731cee38f11ddff50a6177eead95b5c4e4220b", size = 46249 }, ] [[package]] @@ -1835,9 +1827,9 @@ dependencies = [ { name = "redisvl" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/26/ca/0f7b8e64ee4492eadd106ec3aef4376f23e278be787394183eb0f27a4a27/langgraph_checkpoint_redis-0.2.1.tar.gz", hash = "sha256:dc9812e00089d894935dc1cff0f30487e57b2f95ba86743f5b31cfb5322cacf0", size = 85479, upload-time = "2025-11-20T18:01:51.622Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/ca/0f7b8e64ee4492eadd106ec3aef4376f23e278be787394183eb0f27a4a27/langgraph_checkpoint_redis-0.2.1.tar.gz", hash = "sha256:dc9812e00089d894935dc1cff0f30487e57b2f95ba86743f5b31cfb5322cacf0", size = 85479 } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/df/c454bdd78ea182bc172d61b588ea0dd41e669ae9a699880c2bea375cd4e3/langgraph_checkpoint_redis-0.2.1-py3-none-any.whl", hash = "sha256:69013715c3a196543a256944238b6f1f8ece9c27dec7dc06f383aae153ab1b44", size = 90512, upload-time = "2025-11-20T18:01:50.2Z" }, + { url = "https://files.pythonhosted.org/packages/06/df/c454bdd78ea182bc172d61b588ea0dd41e669ae9a699880c2bea375cd4e3/langgraph_checkpoint_redis-0.2.1-py3-none-any.whl", hash = "sha256:69013715c3a196543a256944238b6f1f8ece9c27dec7dc06f383aae153ab1b44", size = 90512 }, ] [[package]] @@ -1848,9 +1840,9 @@ dependencies = [ { name = "langchain-core" }, { name = "langgraph-checkpoint" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/f9/54f8891b32159e4542236817aea2ee83de0de18bce28e9bdba08c7f93001/langgraph_prebuilt-1.0.5.tar.gz", hash = "sha256:85802675ad778cc7240fd02d47db1e0b59c0c86d8369447d77ce47623845db2d", size = 144453, upload-time = "2025-11-20T16:47:39.23Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/f9/54f8891b32159e4542236817aea2ee83de0de18bce28e9bdba08c7f93001/langgraph_prebuilt-1.0.5.tar.gz", hash = "sha256:85802675ad778cc7240fd02d47db1e0b59c0c86d8369447d77ce47623845db2d", size = 144453 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/5e/aeba4a5b39fe6e874e0dd003a82da71c7153e671312671a8dacc5cb7c1af/langgraph_prebuilt-1.0.5-py3-none-any.whl", hash = "sha256:22369563e1848862ace53fbc11b027c28dd04a9ac39314633bb95f2a7e258496", size = 35072, upload-time = "2025-11-20T16:47:38.187Z" }, + { url = "https://files.pythonhosted.org/packages/87/5e/aeba4a5b39fe6e874e0dd003a82da71c7153e671312671a8dacc5cb7c1af/langgraph_prebuilt-1.0.5-py3-none-any.whl", hash = "sha256:22369563e1848862ace53fbc11b027c28dd04a9ac39314633bb95f2a7e258496", size = 35072 }, ] [[package]] @@ -1861,9 +1853,9 @@ dependencies = [ { name = "httpx" }, { name = "orjson" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/0f/88772be3301cc5ad495e77705538edbcbf7f2ccf38d21555fa26131203aa/langgraph_sdk-0.2.10.tar.gz", hash = "sha256:ab58331504fbea28e6322037aa362929799b4e9106663ac1dbd7c5ac44558933", size = 113432, upload-time = "2025-11-24T21:31:57.268Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/0f/88772be3301cc5ad495e77705538edbcbf7f2ccf38d21555fa26131203aa/langgraph_sdk-0.2.10.tar.gz", hash = "sha256:ab58331504fbea28e6322037aa362929799b4e9106663ac1dbd7c5ac44558933", size = 113432 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/cc/ff4ba17253d31981b047f4be52cc51a19fa28dd2dd16a880c0c595bd66bd/langgraph_sdk-0.2.10-py3-none-any.whl", hash = "sha256:9aef403663726085de6851e4e50459df9562069bd316dd0261eb359f776fd0ef", size = 58430, upload-time = "2025-11-24T21:31:56.052Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/ff4ba17253d31981b047f4be52cc51a19fa28dd2dd16a880c0c595bd66bd/langgraph_sdk-0.2.10-py3-none-any.whl", hash = "sha256:9aef403663726085de6851e4e50459df9562069bd316dd0261eb359f776fd0ef", size = 58430 }, ] [[package]] @@ -1879,18 +1871,18 @@ dependencies = [ { name = "requests-toolbelt" }, { name = "zstandard" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2d/69/85ae805ecbc1300d486136329b3cb1702483c0afdaf81da95947dd83884a/langsmith-0.4.49.tar.gz", hash = "sha256:4a16ef6f3a9b20c5471884991a12ff37d81f2c13a50660cfe27fa79a7ca2c1b0", size = 987017, upload-time = "2025-11-26T21:45:16.338Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/69/85ae805ecbc1300d486136329b3cb1702483c0afdaf81da95947dd83884a/langsmith-0.4.49.tar.gz", hash = "sha256:4a16ef6f3a9b20c5471884991a12ff37d81f2c13a50660cfe27fa79a7ca2c1b0", size = 987017 } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/79/59ecf7dceafd655ed20270a0f595d9e8e13895231cebcfbff9b6eec51fc4/langsmith-0.4.49-py3-none-any.whl", hash = "sha256:95f84edcd8e74ed658e4a3eb7355b530f35cb08a9a8865dbfde6740e4b18323c", size = 410905, upload-time = "2025-11-26T21:45:14.606Z" }, + { url = "https://files.pythonhosted.org/packages/31/79/59ecf7dceafd655ed20270a0f595d9e8e13895231cebcfbff9b6eec51fc4/langsmith-0.4.49-py3-none-any.whl", hash = "sha256:95f84edcd8e74ed658e4a3eb7355b530f35cb08a9a8865dbfde6740e4b18323c", size = 410905 }, ] [[package]] name = "lark" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732 } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, ] [[package]] @@ -1900,94 +1892,94 @@ 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 } 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 }, ] [[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/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, - { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, - { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, - { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, - { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, - { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, - { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, - { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, - { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, - { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, - { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, - { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, - { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, - { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, - { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, - { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, - { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, - { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631 }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057 }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050 }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681 }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705 }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524 }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282 }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745 }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571 }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056 }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932 }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631 }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058 }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287 }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940 }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887 }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692 }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471 }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923 }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572 }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077 }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876 }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615 }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020 }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332 }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947 }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962 }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760 }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529 }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015 }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540 }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105 }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543 }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113 }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612 }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200 }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747 }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341 }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819 }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426 }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146 }, ] [[package]] @@ -1997,9 +1989,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/5e53d26b42ab75491cda89b871dab9e97c840bf12c63ec58a1919710cd06/marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6", size = 221825, upload-time = "2025-02-03T15:32:25.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/5e53d26b42ab75491cda89b871dab9e97c840bf12c63ec58a1919710cd06/marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6", size = 221825 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/75/51952c7b2d3873b44a0028b1bd26a25078c18f92f256608e8d1dc61b39fd/marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c", size = 50878, upload-time = "2025-02-03T15:32:22.295Z" }, + { url = "https://files.pythonhosted.org/packages/34/75/51952c7b2d3873b44a0028b1bd26a25078c18f92f256608e8d1dc61b39fd/marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c", size = 50878 }, ] [[package]] @@ -2009,18 +2001,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516 }, ] [[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 } 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 }, ] [[package]] @@ -2030,9 +2022,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d7/02/a7fb8b21d4d55ac93cdcde9d3638da5dd0ebdd3a4fed76c7725e10b81cbe/mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164", size = 94588, upload-time = "2025-08-29T07:20:43.594Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/02/a7fb8b21d4d55ac93cdcde9d3638da5dd0ebdd3a4fed76c7725e10b81cbe/mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164", size = 94588 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/f0/8282d9641415e9e33df173516226b404d367a0fc55e1a60424a152913abc/mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d", size = 53481, upload-time = "2025-08-29T07:20:42.218Z" }, + { url = "https://files.pythonhosted.org/packages/7a/f0/8282d9641415e9e33df173516226b404d367a0fc55e1a60424a152913abc/mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d", size = 53481 }, ] [[package]] @@ -2043,51 +2035,51 @@ dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453", size = 692314, upload-time = "2025-11-17T22:32:31.031Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/3a/c5b855752a70267ff729c349e650263adb3c206c29d28cc8ea7ace30a1d5/ml_dtypes-0.5.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b95e97e470fe60ed493fd9ae3911d8da4ebac16bd21f87ffa2b7c588bf22ea2c", size = 679735, upload-time = "2025-11-17T22:31:31.367Z" }, - { url = "https://files.pythonhosted.org/packages/41/79/7433f30ee04bd4faa303844048f55e1eb939131c8e5195a00a96a0939b64/ml_dtypes-0.5.4-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4b801ebe0b477be666696bda493a9be8356f1f0057a57f1e35cd26928823e5a", size = 5051883, upload-time = "2025-11-17T22:31:33.658Z" }, - { url = "https://files.pythonhosted.org/packages/10/b1/8938e8830b0ee2e167fc75a094dea766a1152bde46752cd9bfc57ee78a82/ml_dtypes-0.5.4-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:388d399a2152dd79a3f0456a952284a99ee5c93d3e2f8dfe25977511e0515270", size = 5030369, upload-time = "2025-11-17T22:31:35.595Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a3/51886727bd16e2f47587997b802dd56398692ce8c6c03c2e5bb32ecafe26/ml_dtypes-0.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:4ff7f3e7ca2972e7de850e7b8fcbb355304271e2933dd90814c1cb847414d6e2", size = 210738, upload-time = "2025-11-17T22:31:37.43Z" }, - { url = "https://files.pythonhosted.org/packages/c6/5e/712092cfe7e5eb667b8ad9ca7c54442f21ed7ca8979745f1000e24cf8737/ml_dtypes-0.5.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6c7ecb74c4bd71db68a6bea1edf8da8c34f3d9fe218f038814fd1d310ac76c90", size = 679734, upload-time = "2025-11-17T22:31:39.223Z" }, - { url = "https://files.pythonhosted.org/packages/4f/cf/912146dfd4b5c0eea956836c01dcd2fce6c9c844b2691f5152aca196ce4f/ml_dtypes-0.5.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc11d7e8c44a65115d05e2ab9989d1e045125d7be8e05a071a48bc76eb6d6040", size = 5056165, upload-time = "2025-11-17T22:31:41.071Z" }, - { url = "https://files.pythonhosted.org/packages/a9/80/19189ea605017473660e43762dc853d2797984b3c7bf30ce656099add30c/ml_dtypes-0.5.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:19b9a53598f21e453ea2fbda8aa783c20faff8e1eeb0d7ab899309a0053f1483", size = 5034975, upload-time = "2025-11-17T22:31:42.758Z" }, - { url = "https://files.pythonhosted.org/packages/b4/24/70bd59276883fdd91600ca20040b41efd4902a923283c4d6edcb1de128d2/ml_dtypes-0.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:7c23c54a00ae43edf48d44066a7ec31e05fdc2eee0be2b8b50dd1903a1db94bb", size = 210742, upload-time = "2025-11-17T22:31:44.068Z" }, - { url = "https://files.pythonhosted.org/packages/a0/c9/64230ef14e40aa3f1cb254ef623bf812735e6bec7772848d19131111ac0d/ml_dtypes-0.5.4-cp311-cp311-win_arm64.whl", hash = "sha256:557a31a390b7e9439056644cb80ed0735a6e3e3bb09d67fd5687e4b04238d1de", size = 160709, upload-time = "2025-11-17T22:31:46.557Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b8/3c70881695e056f8a32f8b941126cf78775d9a4d7feba8abcb52cb7b04f2/ml_dtypes-0.5.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a174837a64f5b16cab6f368171a1a03a27936b31699d167684073ff1c4237dac", size = 676927, upload-time = "2025-11-17T22:31:48.182Z" }, - { url = "https://files.pythonhosted.org/packages/54/0f/428ef6881782e5ebb7eca459689448c0394fa0a80bea3aa9262cba5445ea/ml_dtypes-0.5.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7f7c643e8b1320fd958bf098aa7ecf70623a42ec5154e3be3be673f4c34d900", size = 5028464, upload-time = "2025-11-17T22:31:50.135Z" }, - { url = "https://files.pythonhosted.org/packages/3a/cb/28ce52eb94390dda42599c98ea0204d74799e4d8047a0eb559b6fd648056/ml_dtypes-0.5.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ad459e99793fa6e13bd5b7e6792c8f9190b4e5a1b45c63aba14a4d0a7f1d5ff", size = 5009002, upload-time = "2025-11-17T22:31:52.001Z" }, - { url = "https://files.pythonhosted.org/packages/f5/f0/0cfadd537c5470378b1b32bd859cf2824972174b51b873c9d95cfd7475a5/ml_dtypes-0.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:c1a953995cccb9e25a4ae19e34316671e4e2edaebe4cf538229b1fc7109087b7", size = 212222, upload-time = "2025-11-17T22:31:53.742Z" }, - { url = "https://files.pythonhosted.org/packages/16/2e/9acc86985bfad8f2c2d30291b27cd2bb4c74cea08695bd540906ed744249/ml_dtypes-0.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:9bad06436568442575beb2d03389aa7456c690a5b05892c471215bfd8cf39460", size = 160793, upload-time = "2025-11-17T22:31:55.358Z" }, - { url = "https://files.pythonhosted.org/packages/d9/a1/4008f14bbc616cfb1ac5b39ea485f9c63031c4634ab3f4cf72e7541f816a/ml_dtypes-0.5.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c760d85a2f82e2bed75867079188c9d18dae2ee77c25a54d60e9cc79be1bc48", size = 676888, upload-time = "2025-11-17T22:31:56.907Z" }, - { url = "https://files.pythonhosted.org/packages/d3/b7/dff378afc2b0d5a7d6cd9d3209b60474d9819d1189d347521e1688a60a53/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce756d3a10d0c4067172804c9cc276ba9cc0ff47af9078ad439b075d1abdc29b", size = 5036993, upload-time = "2025-11-17T22:31:58.497Z" }, - { url = "https://files.pythonhosted.org/packages/eb/33/40cd74219417e78b97c47802037cf2d87b91973e18bb968a7da48a96ea44/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:533ce891ba774eabf607172254f2e7260ba5f57bdd64030c9a4fcfbd99815d0d", size = 5010956, upload-time = "2025-11-17T22:31:59.931Z" }, - { url = "https://files.pythonhosted.org/packages/e1/8b/200088c6859d8221454825959df35b5244fa9bdf263fd0249ac5fb75e281/ml_dtypes-0.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:f21c9219ef48ca5ee78402d5cc831bd58ea27ce89beda894428bc67a52da5328", size = 212224, upload-time = "2025-11-17T22:32:01.349Z" }, - { url = "https://files.pythonhosted.org/packages/8f/75/dfc3775cb36367816e678f69a7843f6f03bd4e2bcd79941e01ea960a068e/ml_dtypes-0.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:35f29491a3e478407f7047b8a4834e4640a77d2737e0b294d049746507af5175", size = 160798, upload-time = "2025-11-17T22:32:02.864Z" }, - { url = "https://files.pythonhosted.org/packages/4f/74/e9ddb35fd1dd43b1106c20ced3f53c2e8e7fc7598c15638e9f80677f81d4/ml_dtypes-0.5.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:304ad47faa395415b9ccbcc06a0350800bc50eda70f0e45326796e27c62f18b6", size = 702083, upload-time = "2025-11-17T22:32:04.08Z" }, - { url = "https://files.pythonhosted.org/packages/74/f5/667060b0aed1aa63166b22897fdf16dca9eb704e6b4bbf86848d5a181aa7/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a0df4223b514d799b8a1629c65ddc351b3efa833ccf7f8ea0cf654a61d1e35d", size = 5354111, upload-time = "2025-11-17T22:32:05.546Z" }, - { url = "https://files.pythonhosted.org/packages/40/49/0f8c498a28c0efa5f5c95a9e374c83ec1385ca41d0e85e7cf40e5d519a21/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531eff30e4d368cb6255bc2328d070e35836aa4f282a0fb5f3a0cd7260257298", size = 5366453, upload-time = "2025-11-17T22:32:07.115Z" }, - { url = "https://files.pythonhosted.org/packages/8c/27/12607423d0a9c6bbbcc780ad19f1f6baa2b68b18ce4bddcdc122c4c68dc9/ml_dtypes-0.5.4-cp313-cp313t-win_amd64.whl", hash = "sha256:cb73dccfc991691c444acc8c0012bee8f2470da826a92e3a20bb333b1a7894e6", size = 225612, upload-time = "2025-11-17T22:32:08.615Z" }, - { url = "https://files.pythonhosted.org/packages/e5/80/5a5929e92c72936d5b19872c5fb8fc09327c1da67b3b68c6a13139e77e20/ml_dtypes-0.5.4-cp313-cp313t-win_arm64.whl", hash = "sha256:3bbbe120b915090d9dd1375e4684dd17a20a2491ef25d640a908281da85e73f1", size = 164145, upload-time = "2025-11-17T22:32:09.782Z" }, - { url = "https://files.pythonhosted.org/packages/72/4e/1339dc6e2557a344f5ba5590872e80346f76f6cb2ac3dd16e4666e88818c/ml_dtypes-0.5.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2b857d3af6ac0d39db1de7c706e69c7f9791627209c3d6dedbfca8c7e5faec22", size = 673781, upload-time = "2025-11-17T22:32:11.364Z" }, - { url = "https://files.pythonhosted.org/packages/04/f9/067b84365c7e83bda15bba2b06c6ca250ce27b20630b1128c435fb7a09aa/ml_dtypes-0.5.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:805cef3a38f4eafae3a5bf9ebdcdb741d0bcfd9e1bd90eb54abd24f928cd2465", size = 5036145, upload-time = "2025-11-17T22:32:12.783Z" }, - { url = "https://files.pythonhosted.org/packages/c6/bb/82c7dcf38070b46172a517e2334e665c5bf374a262f99a283ea454bece7c/ml_dtypes-0.5.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14a4fd3228af936461db66faccef6e4f41c1d82fcc30e9f8d58a08916b1d811f", size = 5010230, upload-time = "2025-11-17T22:32:14.38Z" }, - { url = "https://files.pythonhosted.org/packages/e9/93/2bfed22d2498c468f6bcd0d9f56b033eaa19f33320389314c19ef6766413/ml_dtypes-0.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:8c6a2dcebd6f3903e05d51960a8058d6e131fe69f952a5397e5dbabc841b6d56", size = 221032, upload-time = "2025-11-17T22:32:15.763Z" }, - { url = "https://files.pythonhosted.org/packages/76/a3/9c912fe6ea747bb10fe2f8f54d027eb265db05dfb0c6335e3e063e74e6e8/ml_dtypes-0.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:5a0f68ca8fd8d16583dfa7793973feb86f2fbb56ce3966daf9c9f748f52a2049", size = 163353, upload-time = "2025-11-17T22:32:16.932Z" }, - { url = "https://files.pythonhosted.org/packages/cd/02/48aa7d84cc30ab4ee37624a2fd98c56c02326785750cd212bc0826c2f15b/ml_dtypes-0.5.4-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:bfc534409c5d4b0bf945af29e5d0ab075eae9eecbb549ff8a29280db822f34f9", size = 702085, upload-time = "2025-11-17T22:32:18.175Z" }, - { url = "https://files.pythonhosted.org/packages/5a/e7/85cb99fe80a7a5513253ec7faa88a65306be071163485e9a626fce1b6e84/ml_dtypes-0.5.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2314892cdc3fcf05e373d76d72aaa15fda9fb98625effa73c1d646f331fcecb7", size = 5355358, upload-time = "2025-11-17T22:32:19.7Z" }, - { url = "https://files.pythonhosted.org/packages/79/2b/a826ba18d2179a56e144aef69e57fb2ab7c464ef0b2111940ee8a3a223a2/ml_dtypes-0.5.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d2ffd05a2575b1519dc928c0b93c06339eb67173ff53acb00724502cda231cf", size = 5366332, upload-time = "2025-11-17T22:32:21.193Z" }, - { url = "https://files.pythonhosted.org/packages/84/44/f4d18446eacb20ea11e82f133ea8f86e2bf2891785b67d9da8d0ab0ef525/ml_dtypes-0.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4381fe2f2452a2d7589689693d3162e876b3ddb0a832cde7a414f8e1adf7eab1", size = 236612, upload-time = "2025-11-17T22:32:22.579Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3f/3d42e9a78fe5edf792a83c074b13b9b770092a4fbf3462872f4303135f09/ml_dtypes-0.5.4-cp314-cp314t-win_arm64.whl", hash = "sha256:11942cbf2cf92157db91e5022633c0d9474d4dfd813a909383bd23ce828a4b7d", size = 168825, upload-time = "2025-11-17T22:32:23.766Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453", size = 692314 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/3a/c5b855752a70267ff729c349e650263adb3c206c29d28cc8ea7ace30a1d5/ml_dtypes-0.5.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b95e97e470fe60ed493fd9ae3911d8da4ebac16bd21f87ffa2b7c588bf22ea2c", size = 679735 }, + { url = "https://files.pythonhosted.org/packages/41/79/7433f30ee04bd4faa303844048f55e1eb939131c8e5195a00a96a0939b64/ml_dtypes-0.5.4-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4b801ebe0b477be666696bda493a9be8356f1f0057a57f1e35cd26928823e5a", size = 5051883 }, + { url = "https://files.pythonhosted.org/packages/10/b1/8938e8830b0ee2e167fc75a094dea766a1152bde46752cd9bfc57ee78a82/ml_dtypes-0.5.4-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:388d399a2152dd79a3f0456a952284a99ee5c93d3e2f8dfe25977511e0515270", size = 5030369 }, + { url = "https://files.pythonhosted.org/packages/c7/a3/51886727bd16e2f47587997b802dd56398692ce8c6c03c2e5bb32ecafe26/ml_dtypes-0.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:4ff7f3e7ca2972e7de850e7b8fcbb355304271e2933dd90814c1cb847414d6e2", size = 210738 }, + { url = "https://files.pythonhosted.org/packages/c6/5e/712092cfe7e5eb667b8ad9ca7c54442f21ed7ca8979745f1000e24cf8737/ml_dtypes-0.5.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6c7ecb74c4bd71db68a6bea1edf8da8c34f3d9fe218f038814fd1d310ac76c90", size = 679734 }, + { url = "https://files.pythonhosted.org/packages/4f/cf/912146dfd4b5c0eea956836c01dcd2fce6c9c844b2691f5152aca196ce4f/ml_dtypes-0.5.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc11d7e8c44a65115d05e2ab9989d1e045125d7be8e05a071a48bc76eb6d6040", size = 5056165 }, + { url = "https://files.pythonhosted.org/packages/a9/80/19189ea605017473660e43762dc853d2797984b3c7bf30ce656099add30c/ml_dtypes-0.5.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:19b9a53598f21e453ea2fbda8aa783c20faff8e1eeb0d7ab899309a0053f1483", size = 5034975 }, + { url = "https://files.pythonhosted.org/packages/b4/24/70bd59276883fdd91600ca20040b41efd4902a923283c4d6edcb1de128d2/ml_dtypes-0.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:7c23c54a00ae43edf48d44066a7ec31e05fdc2eee0be2b8b50dd1903a1db94bb", size = 210742 }, + { url = "https://files.pythonhosted.org/packages/a0/c9/64230ef14e40aa3f1cb254ef623bf812735e6bec7772848d19131111ac0d/ml_dtypes-0.5.4-cp311-cp311-win_arm64.whl", hash = "sha256:557a31a390b7e9439056644cb80ed0735a6e3e3bb09d67fd5687e4b04238d1de", size = 160709 }, + { url = "https://files.pythonhosted.org/packages/a8/b8/3c70881695e056f8a32f8b941126cf78775d9a4d7feba8abcb52cb7b04f2/ml_dtypes-0.5.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a174837a64f5b16cab6f368171a1a03a27936b31699d167684073ff1c4237dac", size = 676927 }, + { url = "https://files.pythonhosted.org/packages/54/0f/428ef6881782e5ebb7eca459689448c0394fa0a80bea3aa9262cba5445ea/ml_dtypes-0.5.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7f7c643e8b1320fd958bf098aa7ecf70623a42ec5154e3be3be673f4c34d900", size = 5028464 }, + { url = "https://files.pythonhosted.org/packages/3a/cb/28ce52eb94390dda42599c98ea0204d74799e4d8047a0eb559b6fd648056/ml_dtypes-0.5.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ad459e99793fa6e13bd5b7e6792c8f9190b4e5a1b45c63aba14a4d0a7f1d5ff", size = 5009002 }, + { url = "https://files.pythonhosted.org/packages/f5/f0/0cfadd537c5470378b1b32bd859cf2824972174b51b873c9d95cfd7475a5/ml_dtypes-0.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:c1a953995cccb9e25a4ae19e34316671e4e2edaebe4cf538229b1fc7109087b7", size = 212222 }, + { url = "https://files.pythonhosted.org/packages/16/2e/9acc86985bfad8f2c2d30291b27cd2bb4c74cea08695bd540906ed744249/ml_dtypes-0.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:9bad06436568442575beb2d03389aa7456c690a5b05892c471215bfd8cf39460", size = 160793 }, + { url = "https://files.pythonhosted.org/packages/d9/a1/4008f14bbc616cfb1ac5b39ea485f9c63031c4634ab3f4cf72e7541f816a/ml_dtypes-0.5.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c760d85a2f82e2bed75867079188c9d18dae2ee77c25a54d60e9cc79be1bc48", size = 676888 }, + { url = "https://files.pythonhosted.org/packages/d3/b7/dff378afc2b0d5a7d6cd9d3209b60474d9819d1189d347521e1688a60a53/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce756d3a10d0c4067172804c9cc276ba9cc0ff47af9078ad439b075d1abdc29b", size = 5036993 }, + { url = "https://files.pythonhosted.org/packages/eb/33/40cd74219417e78b97c47802037cf2d87b91973e18bb968a7da48a96ea44/ml_dtypes-0.5.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:533ce891ba774eabf607172254f2e7260ba5f57bdd64030c9a4fcfbd99815d0d", size = 5010956 }, + { url = "https://files.pythonhosted.org/packages/e1/8b/200088c6859d8221454825959df35b5244fa9bdf263fd0249ac5fb75e281/ml_dtypes-0.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:f21c9219ef48ca5ee78402d5cc831bd58ea27ce89beda894428bc67a52da5328", size = 212224 }, + { url = "https://files.pythonhosted.org/packages/8f/75/dfc3775cb36367816e678f69a7843f6f03bd4e2bcd79941e01ea960a068e/ml_dtypes-0.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:35f29491a3e478407f7047b8a4834e4640a77d2737e0b294d049746507af5175", size = 160798 }, + { url = "https://files.pythonhosted.org/packages/4f/74/e9ddb35fd1dd43b1106c20ced3f53c2e8e7fc7598c15638e9f80677f81d4/ml_dtypes-0.5.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:304ad47faa395415b9ccbcc06a0350800bc50eda70f0e45326796e27c62f18b6", size = 702083 }, + { url = "https://files.pythonhosted.org/packages/74/f5/667060b0aed1aa63166b22897fdf16dca9eb704e6b4bbf86848d5a181aa7/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a0df4223b514d799b8a1629c65ddc351b3efa833ccf7f8ea0cf654a61d1e35d", size = 5354111 }, + { url = "https://files.pythonhosted.org/packages/40/49/0f8c498a28c0efa5f5c95a9e374c83ec1385ca41d0e85e7cf40e5d519a21/ml_dtypes-0.5.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531eff30e4d368cb6255bc2328d070e35836aa4f282a0fb5f3a0cd7260257298", size = 5366453 }, + { url = "https://files.pythonhosted.org/packages/8c/27/12607423d0a9c6bbbcc780ad19f1f6baa2b68b18ce4bddcdc122c4c68dc9/ml_dtypes-0.5.4-cp313-cp313t-win_amd64.whl", hash = "sha256:cb73dccfc991691c444acc8c0012bee8f2470da826a92e3a20bb333b1a7894e6", size = 225612 }, + { url = "https://files.pythonhosted.org/packages/e5/80/5a5929e92c72936d5b19872c5fb8fc09327c1da67b3b68c6a13139e77e20/ml_dtypes-0.5.4-cp313-cp313t-win_arm64.whl", hash = "sha256:3bbbe120b915090d9dd1375e4684dd17a20a2491ef25d640a908281da85e73f1", size = 164145 }, + { url = "https://files.pythonhosted.org/packages/72/4e/1339dc6e2557a344f5ba5590872e80346f76f6cb2ac3dd16e4666e88818c/ml_dtypes-0.5.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2b857d3af6ac0d39db1de7c706e69c7f9791627209c3d6dedbfca8c7e5faec22", size = 673781 }, + { url = "https://files.pythonhosted.org/packages/04/f9/067b84365c7e83bda15bba2b06c6ca250ce27b20630b1128c435fb7a09aa/ml_dtypes-0.5.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:805cef3a38f4eafae3a5bf9ebdcdb741d0bcfd9e1bd90eb54abd24f928cd2465", size = 5036145 }, + { url = "https://files.pythonhosted.org/packages/c6/bb/82c7dcf38070b46172a517e2334e665c5bf374a262f99a283ea454bece7c/ml_dtypes-0.5.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14a4fd3228af936461db66faccef6e4f41c1d82fcc30e9f8d58a08916b1d811f", size = 5010230 }, + { url = "https://files.pythonhosted.org/packages/e9/93/2bfed22d2498c468f6bcd0d9f56b033eaa19f33320389314c19ef6766413/ml_dtypes-0.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:8c6a2dcebd6f3903e05d51960a8058d6e131fe69f952a5397e5dbabc841b6d56", size = 221032 }, + { url = "https://files.pythonhosted.org/packages/76/a3/9c912fe6ea747bb10fe2f8f54d027eb265db05dfb0c6335e3e063e74e6e8/ml_dtypes-0.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:5a0f68ca8fd8d16583dfa7793973feb86f2fbb56ce3966daf9c9f748f52a2049", size = 163353 }, + { url = "https://files.pythonhosted.org/packages/cd/02/48aa7d84cc30ab4ee37624a2fd98c56c02326785750cd212bc0826c2f15b/ml_dtypes-0.5.4-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:bfc534409c5d4b0bf945af29e5d0ab075eae9eecbb549ff8a29280db822f34f9", size = 702085 }, + { url = "https://files.pythonhosted.org/packages/5a/e7/85cb99fe80a7a5513253ec7faa88a65306be071163485e9a626fce1b6e84/ml_dtypes-0.5.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2314892cdc3fcf05e373d76d72aaa15fda9fb98625effa73c1d646f331fcecb7", size = 5355358 }, + { url = "https://files.pythonhosted.org/packages/79/2b/a826ba18d2179a56e144aef69e57fb2ab7c464ef0b2111940ee8a3a223a2/ml_dtypes-0.5.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d2ffd05a2575b1519dc928c0b93c06339eb67173ff53acb00724502cda231cf", size = 5366332 }, + { url = "https://files.pythonhosted.org/packages/84/44/f4d18446eacb20ea11e82f133ea8f86e2bf2891785b67d9da8d0ab0ef525/ml_dtypes-0.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4381fe2f2452a2d7589689693d3162e876b3ddb0a832cde7a414f8e1adf7eab1", size = 236612 }, + { url = "https://files.pythonhosted.org/packages/ad/3f/3d42e9a78fe5edf792a83c074b13b9b770092a4fbf3462872f4303135f09/ml_dtypes-0.5.4-cp314-cp314t-win_arm64.whl", hash = "sha256:11942cbf2cf92157db91e5022633c0d9474d4dfd813a909383bd23ce828a4b7d", size = 168825 }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, ] [[package]] @@ -2097,135 +2089,135 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153, upload-time = "2025-10-06T14:48:26.409Z" }, - { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993, upload-time = "2025-10-06T14:48:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607, upload-time = "2025-10-06T14:48:29.581Z" }, - { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847, upload-time = "2025-10-06T14:48:32.107Z" }, - { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616, upload-time = "2025-10-06T14:48:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333, upload-time = "2025-10-06T14:48:35.9Z" }, - { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239, upload-time = "2025-10-06T14:48:37.302Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618, upload-time = "2025-10-06T14:48:38.963Z" }, - { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655, upload-time = "2025-10-06T14:48:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245, upload-time = "2025-10-06T14:48:41.848Z" }, - { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523, upload-time = "2025-10-06T14:48:43.749Z" }, - { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129, upload-time = "2025-10-06T14:48:45.225Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999, upload-time = "2025-10-06T14:48:46.703Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711, upload-time = "2025-10-06T14:48:48.146Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504, upload-time = "2025-10-06T14:48:49.447Z" }, - { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422, upload-time = "2025-10-06T14:48:50.789Z" }, - { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050, upload-time = "2025-10-06T14:48:51.938Z" }, - { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153, upload-time = "2025-10-06T14:48:53.146Z" }, - { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604, upload-time = "2025-10-06T14:48:54.277Z" }, - { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715, upload-time = "2025-10-06T14:48:55.445Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332, upload-time = "2025-10-06T14:48:56.706Z" }, - { url = "https://files.pythonhosted.org/packages/31/61/0c2d50241ada71ff61a79518db85ada85fdabfcf395d5968dae1cbda04e5/multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c", size = 245212, upload-time = "2025-10-06T14:48:58.042Z" }, - { url = "https://files.pythonhosted.org/packages/ac/e0/919666a4e4b57fff1b57f279be1c9316e6cdc5de8a8b525d76f6598fefc7/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7", size = 246671, upload-time = "2025-10-06T14:49:00.004Z" }, - { url = "https://files.pythonhosted.org/packages/a1/cc/d027d9c5a520f3321b65adea289b965e7bcbd2c34402663f482648c716ce/multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7", size = 225491, upload-time = "2025-10-06T14:49:01.393Z" }, - { url = "https://files.pythonhosted.org/packages/75/c4/bbd633980ce6155a28ff04e6a6492dd3335858394d7bb752d8b108708558/multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9", size = 257322, upload-time = "2025-10-06T14:49:02.745Z" }, - { url = "https://files.pythonhosted.org/packages/4c/6d/d622322d344f1f053eae47e033b0b3f965af01212de21b10bcf91be991fb/multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8", size = 254694, upload-time = "2025-10-06T14:49:04.15Z" }, - { url = "https://files.pythonhosted.org/packages/a8/9f/78f8761c2705d4c6d7516faed63c0ebdac569f6db1bef95e0d5218fdc146/multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd", size = 246715, upload-time = "2025-10-06T14:49:05.967Z" }, - { url = "https://files.pythonhosted.org/packages/78/59/950818e04f91b9c2b95aab3d923d9eabd01689d0dcd889563988e9ea0fd8/multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb", size = 243189, upload-time = "2025-10-06T14:49:07.37Z" }, - { url = "https://files.pythonhosted.org/packages/7a/3d/77c79e1934cad2ee74991840f8a0110966d9599b3af95964c0cd79bb905b/multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6", size = 237845, upload-time = "2025-10-06T14:49:08.759Z" }, - { url = "https://files.pythonhosted.org/packages/63/1b/834ce32a0a97a3b70f86437f685f880136677ac00d8bce0027e9fd9c2db7/multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2", size = 246374, upload-time = "2025-10-06T14:49:10.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/ef/43d1c3ba205b5dec93dc97f3fba179dfa47910fc73aaaea4f7ceb41cec2a/multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff", size = 253345, upload-time = "2025-10-06T14:49:12.331Z" }, - { url = "https://files.pythonhosted.org/packages/6b/03/eaf95bcc2d19ead522001f6a650ef32811aa9e3624ff0ad37c445c7a588c/multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b", size = 246940, upload-time = "2025-10-06T14:49:13.821Z" }, - { url = "https://files.pythonhosted.org/packages/e8/df/ec8a5fd66ea6cd6f525b1fcbb23511b033c3e9bc42b81384834ffa484a62/multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34", size = 242229, upload-time = "2025-10-06T14:49:15.603Z" }, - { url = "https://files.pythonhosted.org/packages/8a/a2/59b405d59fd39ec86d1142630e9049243015a5f5291ba49cadf3c090c541/multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff", size = 41308, upload-time = "2025-10-06T14:49:16.871Z" }, - { url = "https://files.pythonhosted.org/packages/32/0f/13228f26f8b882c34da36efa776c3b7348455ec383bab4a66390e42963ae/multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81", size = 46037, upload-time = "2025-10-06T14:49:18.457Z" }, - { url = "https://files.pythonhosted.org/packages/84/1f/68588e31b000535a3207fd3c909ebeec4fb36b52c442107499c18a896a2a/multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912", size = 43023, upload-time = "2025-10-06T14:49:19.648Z" }, - { url = "https://files.pythonhosted.org/packages/c2/9e/9f61ac18d9c8b475889f32ccfa91c9f59363480613fc807b6e3023d6f60b/multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184", size = 76877, upload-time = "2025-10-06T14:49:20.884Z" }, - { url = "https://files.pythonhosted.org/packages/38/6f/614f09a04e6184f8824268fce4bc925e9849edfa654ddd59f0b64508c595/multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45", size = 45467, upload-time = "2025-10-06T14:49:22.054Z" }, - { url = "https://files.pythonhosted.org/packages/b3/93/c4f67a436dd026f2e780c433277fff72be79152894d9fc36f44569cab1a6/multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa", size = 43834, upload-time = "2025-10-06T14:49:23.566Z" }, - { url = "https://files.pythonhosted.org/packages/7f/f5/013798161ca665e4a422afbc5e2d9e4070142a9ff8905e482139cd09e4d0/multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7", size = 250545, upload-time = "2025-10-06T14:49:24.882Z" }, - { url = "https://files.pythonhosted.org/packages/71/2f/91dbac13e0ba94669ea5119ba267c9a832f0cb65419aca75549fcf09a3dc/multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e", size = 258305, upload-time = "2025-10-06T14:49:26.778Z" }, - { url = "https://files.pythonhosted.org/packages/ef/b0/754038b26f6e04488b48ac621f779c341338d78503fb45403755af2df477/multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546", size = 242363, upload-time = "2025-10-06T14:49:28.562Z" }, - { url = "https://files.pythonhosted.org/packages/87/15/9da40b9336a7c9fa606c4cf2ed80a649dffeb42b905d4f63a1d7eb17d746/multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4", size = 268375, upload-time = "2025-10-06T14:49:29.96Z" }, - { url = "https://files.pythonhosted.org/packages/82/72/c53fcade0cc94dfaad583105fd92b3a783af2091eddcb41a6d5a52474000/multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1", size = 269346, upload-time = "2025-10-06T14:49:31.404Z" }, - { url = "https://files.pythonhosted.org/packages/0d/e2/9baffdae21a76f77ef8447f1a05a96ec4bc0a24dae08767abc0a2fe680b8/multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d", size = 256107, upload-time = "2025-10-06T14:49:32.974Z" }, - { url = "https://files.pythonhosted.org/packages/3c/06/3f06f611087dc60d65ef775f1fb5aca7c6d61c6db4990e7cda0cef9b1651/multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304", size = 253592, upload-time = "2025-10-06T14:49:34.52Z" }, - { url = "https://files.pythonhosted.org/packages/20/24/54e804ec7945b6023b340c412ce9c3f81e91b3bf5fa5ce65558740141bee/multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12", size = 251024, upload-time = "2025-10-06T14:49:35.956Z" }, - { url = "https://files.pythonhosted.org/packages/14/48/011cba467ea0b17ceb938315d219391d3e421dfd35928e5dbdc3f4ae76ef/multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62", size = 251484, upload-time = "2025-10-06T14:49:37.631Z" }, - { url = "https://files.pythonhosted.org/packages/0d/2f/919258b43bb35b99fa127435cfb2d91798eb3a943396631ef43e3720dcf4/multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0", size = 263579, upload-time = "2025-10-06T14:49:39.502Z" }, - { url = "https://files.pythonhosted.org/packages/31/22/a0e884d86b5242b5a74cf08e876bdf299e413016b66e55511f7a804a366e/multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a", size = 259654, upload-time = "2025-10-06T14:49:41.32Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e5/17e10e1b5c5f5a40f2fcbb45953c9b215f8a4098003915e46a93f5fcaa8f/multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8", size = 251511, upload-time = "2025-10-06T14:49:46.021Z" }, - { url = "https://files.pythonhosted.org/packages/e3/9a/201bb1e17e7af53139597069c375e7b0dcbd47594604f65c2d5359508566/multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4", size = 41895, upload-time = "2025-10-06T14:49:48.718Z" }, - { url = "https://files.pythonhosted.org/packages/46/e2/348cd32faad84eaf1d20cce80e2bb0ef8d312c55bca1f7fa9865e7770aaf/multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b", size = 46073, upload-time = "2025-10-06T14:49:50.28Z" }, - { url = "https://files.pythonhosted.org/packages/25/ec/aad2613c1910dce907480e0c3aa306905830f25df2e54ccc9dea450cb5aa/multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec", size = 43226, upload-time = "2025-10-06T14:49:52.304Z" }, - { url = "https://files.pythonhosted.org/packages/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135, upload-time = "2025-10-06T14:49:54.26Z" }, - { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117, upload-time = "2025-10-06T14:49:55.82Z" }, - { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472, upload-time = "2025-10-06T14:49:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342, upload-time = "2025-10-06T14:49:58.368Z" }, - { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082, upload-time = "2025-10-06T14:49:59.89Z" }, - { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704, upload-time = "2025-10-06T14:50:01.485Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355, upload-time = "2025-10-06T14:50:02.955Z" }, - { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259, upload-time = "2025-10-06T14:50:04.446Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903, upload-time = "2025-10-06T14:50:05.98Z" }, - { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365, upload-time = "2025-10-06T14:50:07.511Z" }, - { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062, upload-time = "2025-10-06T14:50:09.074Z" }, - { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683, upload-time = "2025-10-06T14:50:10.714Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254, upload-time = "2025-10-06T14:50:12.28Z" }, - { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967, upload-time = "2025-10-06T14:50:14.16Z" }, - { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085, upload-time = "2025-10-06T14:50:15.639Z" }, - { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713, upload-time = "2025-10-06T14:50:17.066Z" }, - { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915, upload-time = "2025-10-06T14:50:18.264Z" }, - { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077, upload-time = "2025-10-06T14:50:19.853Z" }, - { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114, upload-time = "2025-10-06T14:50:21.223Z" }, - { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442, upload-time = "2025-10-06T14:50:22.871Z" }, - { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885, upload-time = "2025-10-06T14:50:24.258Z" }, - { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588, upload-time = "2025-10-06T14:50:25.716Z" }, - { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966, upload-time = "2025-10-06T14:50:28.192Z" }, - { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618, upload-time = "2025-10-06T14:50:29.82Z" }, - { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539, upload-time = "2025-10-06T14:50:31.731Z" }, - { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345, upload-time = "2025-10-06T14:50:33.26Z" }, - { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934, upload-time = "2025-10-06T14:50:34.808Z" }, - { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243, upload-time = "2025-10-06T14:50:36.436Z" }, - { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878, upload-time = "2025-10-06T14:50:37.953Z" }, - { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452, upload-time = "2025-10-06T14:50:39.574Z" }, - { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312, upload-time = "2025-10-06T14:50:41.612Z" }, - { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935, upload-time = "2025-10-06T14:50:43.972Z" }, - { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385, upload-time = "2025-10-06T14:50:45.648Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, - { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, - { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, - { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, - { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, - { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, - { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, - { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, - { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, - { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, - { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, - { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, - { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, - { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, - { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, - { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, - { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, - { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, - { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, - { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, - { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, - { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, - { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, - { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, - { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, - { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, - { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, - { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, - { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, - { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, - { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, - { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153 }, + { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993 }, + { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607 }, + { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847 }, + { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616 }, + { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333 }, + { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239 }, + { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618 }, + { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655 }, + { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245 }, + { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523 }, + { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129 }, + { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999 }, + { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711 }, + { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504 }, + { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422 }, + { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050 }, + { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153 }, + { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604 }, + { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715 }, + { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332 }, + { url = "https://files.pythonhosted.org/packages/31/61/0c2d50241ada71ff61a79518db85ada85fdabfcf395d5968dae1cbda04e5/multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c", size = 245212 }, + { url = "https://files.pythonhosted.org/packages/ac/e0/919666a4e4b57fff1b57f279be1c9316e6cdc5de8a8b525d76f6598fefc7/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7", size = 246671 }, + { url = "https://files.pythonhosted.org/packages/a1/cc/d027d9c5a520f3321b65adea289b965e7bcbd2c34402663f482648c716ce/multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7", size = 225491 }, + { url = "https://files.pythonhosted.org/packages/75/c4/bbd633980ce6155a28ff04e6a6492dd3335858394d7bb752d8b108708558/multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9", size = 257322 }, + { url = "https://files.pythonhosted.org/packages/4c/6d/d622322d344f1f053eae47e033b0b3f965af01212de21b10bcf91be991fb/multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8", size = 254694 }, + { url = "https://files.pythonhosted.org/packages/a8/9f/78f8761c2705d4c6d7516faed63c0ebdac569f6db1bef95e0d5218fdc146/multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd", size = 246715 }, + { url = "https://files.pythonhosted.org/packages/78/59/950818e04f91b9c2b95aab3d923d9eabd01689d0dcd889563988e9ea0fd8/multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb", size = 243189 }, + { url = "https://files.pythonhosted.org/packages/7a/3d/77c79e1934cad2ee74991840f8a0110966d9599b3af95964c0cd79bb905b/multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6", size = 237845 }, + { url = "https://files.pythonhosted.org/packages/63/1b/834ce32a0a97a3b70f86437f685f880136677ac00d8bce0027e9fd9c2db7/multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2", size = 246374 }, + { url = "https://files.pythonhosted.org/packages/23/ef/43d1c3ba205b5dec93dc97f3fba179dfa47910fc73aaaea4f7ceb41cec2a/multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff", size = 253345 }, + { url = "https://files.pythonhosted.org/packages/6b/03/eaf95bcc2d19ead522001f6a650ef32811aa9e3624ff0ad37c445c7a588c/multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b", size = 246940 }, + { url = "https://files.pythonhosted.org/packages/e8/df/ec8a5fd66ea6cd6f525b1fcbb23511b033c3e9bc42b81384834ffa484a62/multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34", size = 242229 }, + { url = "https://files.pythonhosted.org/packages/8a/a2/59b405d59fd39ec86d1142630e9049243015a5f5291ba49cadf3c090c541/multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff", size = 41308 }, + { url = "https://files.pythonhosted.org/packages/32/0f/13228f26f8b882c34da36efa776c3b7348455ec383bab4a66390e42963ae/multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81", size = 46037 }, + { url = "https://files.pythonhosted.org/packages/84/1f/68588e31b000535a3207fd3c909ebeec4fb36b52c442107499c18a896a2a/multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912", size = 43023 }, + { url = "https://files.pythonhosted.org/packages/c2/9e/9f61ac18d9c8b475889f32ccfa91c9f59363480613fc807b6e3023d6f60b/multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184", size = 76877 }, + { url = "https://files.pythonhosted.org/packages/38/6f/614f09a04e6184f8824268fce4bc925e9849edfa654ddd59f0b64508c595/multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45", size = 45467 }, + { url = "https://files.pythonhosted.org/packages/b3/93/c4f67a436dd026f2e780c433277fff72be79152894d9fc36f44569cab1a6/multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa", size = 43834 }, + { url = "https://files.pythonhosted.org/packages/7f/f5/013798161ca665e4a422afbc5e2d9e4070142a9ff8905e482139cd09e4d0/multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7", size = 250545 }, + { url = "https://files.pythonhosted.org/packages/71/2f/91dbac13e0ba94669ea5119ba267c9a832f0cb65419aca75549fcf09a3dc/multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e", size = 258305 }, + { url = "https://files.pythonhosted.org/packages/ef/b0/754038b26f6e04488b48ac621f779c341338d78503fb45403755af2df477/multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546", size = 242363 }, + { url = "https://files.pythonhosted.org/packages/87/15/9da40b9336a7c9fa606c4cf2ed80a649dffeb42b905d4f63a1d7eb17d746/multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4", size = 268375 }, + { url = "https://files.pythonhosted.org/packages/82/72/c53fcade0cc94dfaad583105fd92b3a783af2091eddcb41a6d5a52474000/multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1", size = 269346 }, + { url = "https://files.pythonhosted.org/packages/0d/e2/9baffdae21a76f77ef8447f1a05a96ec4bc0a24dae08767abc0a2fe680b8/multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d", size = 256107 }, + { url = "https://files.pythonhosted.org/packages/3c/06/3f06f611087dc60d65ef775f1fb5aca7c6d61c6db4990e7cda0cef9b1651/multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304", size = 253592 }, + { url = "https://files.pythonhosted.org/packages/20/24/54e804ec7945b6023b340c412ce9c3f81e91b3bf5fa5ce65558740141bee/multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12", size = 251024 }, + { url = "https://files.pythonhosted.org/packages/14/48/011cba467ea0b17ceb938315d219391d3e421dfd35928e5dbdc3f4ae76ef/multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62", size = 251484 }, + { url = "https://files.pythonhosted.org/packages/0d/2f/919258b43bb35b99fa127435cfb2d91798eb3a943396631ef43e3720dcf4/multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0", size = 263579 }, + { url = "https://files.pythonhosted.org/packages/31/22/a0e884d86b5242b5a74cf08e876bdf299e413016b66e55511f7a804a366e/multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a", size = 259654 }, + { url = "https://files.pythonhosted.org/packages/b2/e5/17e10e1b5c5f5a40f2fcbb45953c9b215f8a4098003915e46a93f5fcaa8f/multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8", size = 251511 }, + { url = "https://files.pythonhosted.org/packages/e3/9a/201bb1e17e7af53139597069c375e7b0dcbd47594604f65c2d5359508566/multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4", size = 41895 }, + { url = "https://files.pythonhosted.org/packages/46/e2/348cd32faad84eaf1d20cce80e2bb0ef8d312c55bca1f7fa9865e7770aaf/multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b", size = 46073 }, + { url = "https://files.pythonhosted.org/packages/25/ec/aad2613c1910dce907480e0c3aa306905830f25df2e54ccc9dea450cb5aa/multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec", size = 43226 }, + { url = "https://files.pythonhosted.org/packages/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135 }, + { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117 }, + { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472 }, + { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342 }, + { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082 }, + { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704 }, + { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355 }, + { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259 }, + { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903 }, + { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365 }, + { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062 }, + { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683 }, + { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254 }, + { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967 }, + { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085 }, + { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713 }, + { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915 }, + { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077 }, + { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114 }, + { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442 }, + { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885 }, + { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588 }, + { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966 }, + { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618 }, + { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539 }, + { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345 }, + { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934 }, + { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243 }, + { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878 }, + { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452 }, + { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312 }, + { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935 }, + { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385 }, + { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777 }, + { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104 }, + { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503 }, + { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128 }, + { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410 }, + { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205 }, + { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084 }, + { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667 }, + { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590 }, + { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112 }, + { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194 }, + { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510 }, + { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395 }, + { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520 }, + { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479 }, + { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903 }, + { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333 }, + { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411 }, + { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940 }, + { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087 }, + { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368 }, + { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326 }, + { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065 }, + { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475 }, + { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324 }, + { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877 }, + { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824 }, + { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558 }, + { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339 }, + { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895 }, + { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862 }, + { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376 }, + { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272 }, + { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774 }, + { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731 }, + { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193 }, + { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023 }, + { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507 }, + { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804 }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317 }, ] [[package]] @@ -2238,48 +2230,48 @@ dependencies = [ { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/77/8f0d0001ffad290cef2f7f216f96c814866248a0b92a722365ed54648e7e/mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b", size = 3448846, upload-time = "2025-09-19T00:11:10.519Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/6f/657961a0743cff32e6c0611b63ff1c1970a0b482ace35b069203bf705187/mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c", size = 12807973, upload-time = "2025-09-19T00:10:35.282Z" }, - { url = "https://files.pythonhosted.org/packages/10/e9/420822d4f661f13ca8900f5fa239b40ee3be8b62b32f3357df9a3045a08b/mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e", size = 11896527, upload-time = "2025-09-19T00:10:55.791Z" }, - { url = "https://files.pythonhosted.org/packages/aa/73/a05b2bbaa7005f4642fcfe40fb73f2b4fb6bb44229bd585b5878e9a87ef8/mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b", size = 12507004, upload-time = "2025-09-19T00:11:05.411Z" }, - { url = "https://files.pythonhosted.org/packages/4f/01/f6e4b9f0d031c11ccbd6f17da26564f3a0f3c4155af344006434b0a05a9d/mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66", size = 13245947, upload-time = "2025-09-19T00:10:46.923Z" }, - { url = "https://files.pythonhosted.org/packages/d7/97/19727e7499bfa1ae0773d06afd30ac66a58ed7437d940c70548634b24185/mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428", size = 13499217, upload-time = "2025-09-19T00:09:39.472Z" }, - { url = "https://files.pythonhosted.org/packages/9f/4f/90dc8c15c1441bf31cf0f9918bb077e452618708199e530f4cbd5cede6ff/mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed", size = 9766753, upload-time = "2025-09-19T00:10:49.161Z" }, - { url = "https://files.pythonhosted.org/packages/88/87/cafd3ae563f88f94eec33f35ff722d043e09832ea8530ef149ec1efbaf08/mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f", size = 12731198, upload-time = "2025-09-19T00:09:44.857Z" }, - { url = "https://files.pythonhosted.org/packages/0f/e0/1e96c3d4266a06d4b0197ace5356d67d937d8358e2ee3ffac71faa843724/mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341", size = 11817879, upload-time = "2025-09-19T00:09:47.131Z" }, - { url = "https://files.pythonhosted.org/packages/72/ef/0c9ba89eb03453e76bdac5a78b08260a848c7bfc5d6603634774d9cd9525/mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d", size = 12427292, upload-time = "2025-09-19T00:10:22.472Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/ec4a061dd599eb8179d5411d99775bec2a20542505988f40fc2fee781068/mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86", size = 13163750, upload-time = "2025-09-19T00:09:51.472Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5f/2cf2ceb3b36372d51568f2208c021870fe7834cf3186b653ac6446511839/mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37", size = 13351827, upload-time = "2025-09-19T00:09:58.311Z" }, - { url = "https://files.pythonhosted.org/packages/c8/7d/2697b930179e7277529eaaec1513f8de622818696857f689e4a5432e5e27/mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8", size = 9757983, upload-time = "2025-09-19T00:10:09.071Z" }, - { url = "https://files.pythonhosted.org/packages/07/06/dfdd2bc60c66611dd8335f463818514733bc763e4760dee289dcc33df709/mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34", size = 12908273, upload-time = "2025-09-19T00:10:58.321Z" }, - { url = "https://files.pythonhosted.org/packages/81/14/6a9de6d13a122d5608e1a04130724caf9170333ac5a924e10f670687d3eb/mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764", size = 11920910, upload-time = "2025-09-19T00:10:20.043Z" }, - { url = "https://files.pythonhosted.org/packages/5f/a9/b29de53e42f18e8cc547e38daa9dfa132ffdc64f7250e353f5c8cdd44bee/mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893", size = 12465585, upload-time = "2025-09-19T00:10:33.005Z" }, - { url = "https://files.pythonhosted.org/packages/77/ae/6c3d2c7c61ff21f2bee938c917616c92ebf852f015fb55917fd6e2811db2/mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914", size = 13348562, upload-time = "2025-09-19T00:10:11.51Z" }, - { url = "https://files.pythonhosted.org/packages/4d/31/aec68ab3b4aebdf8f36d191b0685d99faa899ab990753ca0fee60fb99511/mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8", size = 13533296, upload-time = "2025-09-19T00:10:06.568Z" }, - { url = "https://files.pythonhosted.org/packages/9f/83/abcb3ad9478fca3ebeb6a5358bb0b22c95ea42b43b7789c7fb1297ca44f4/mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074", size = 9828828, upload-time = "2025-09-19T00:10:28.203Z" }, - { url = "https://files.pythonhosted.org/packages/5f/04/7f462e6fbba87a72bc8097b93f6842499c428a6ff0c81dd46948d175afe8/mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc", size = 12898728, upload-time = "2025-09-19T00:10:01.33Z" }, - { url = "https://files.pythonhosted.org/packages/99/5b/61ed4efb64f1871b41fd0b82d29a64640f3516078f6c7905b68ab1ad8b13/mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e", size = 11910758, upload-time = "2025-09-19T00:10:42.607Z" }, - { url = "https://files.pythonhosted.org/packages/3c/46/d297d4b683cc89a6e4108c4250a6a6b717f5fa96e1a30a7944a6da44da35/mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986", size = 12475342, upload-time = "2025-09-19T00:11:00.371Z" }, - { url = "https://files.pythonhosted.org/packages/83/45/4798f4d00df13eae3bfdf726c9244bcb495ab5bd588c0eed93a2f2dd67f3/mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d", size = 13338709, upload-time = "2025-09-19T00:11:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/d7/09/479f7358d9625172521a87a9271ddd2441e1dab16a09708f056e97007207/mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba", size = 13529806, upload-time = "2025-09-19T00:10:26.073Z" }, - { url = "https://files.pythonhosted.org/packages/71/cf/ac0f2c7e9d0ea3c75cd99dff7aec1c9df4a1376537cb90e4c882267ee7e9/mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544", size = 9833262, upload-time = "2025-09-19T00:10:40.035Z" }, - { url = "https://files.pythonhosted.org/packages/5a/0c/7d5300883da16f0063ae53996358758b2a2df2a09c72a5061fa79a1f5006/mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce", size = 12893775, upload-time = "2025-09-19T00:10:03.814Z" }, - { url = "https://files.pythonhosted.org/packages/50/df/2cffbf25737bdb236f60c973edf62e3e7b4ee1c25b6878629e88e2cde967/mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d", size = 11936852, upload-time = "2025-09-19T00:10:51.631Z" }, - { url = "https://files.pythonhosted.org/packages/be/50/34059de13dd269227fb4a03be1faee6e2a4b04a2051c82ac0a0b5a773c9a/mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c", size = 12480242, upload-time = "2025-09-19T00:11:07.955Z" }, - { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, - { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, - { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/c0/77/8f0d0001ffad290cef2f7f216f96c814866248a0b92a722365ed54648e7e/mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b", size = 3448846 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/6f/657961a0743cff32e6c0611b63ff1c1970a0b482ace35b069203bf705187/mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c", size = 12807973 }, + { url = "https://files.pythonhosted.org/packages/10/e9/420822d4f661f13ca8900f5fa239b40ee3be8b62b32f3357df9a3045a08b/mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e", size = 11896527 }, + { url = "https://files.pythonhosted.org/packages/aa/73/a05b2bbaa7005f4642fcfe40fb73f2b4fb6bb44229bd585b5878e9a87ef8/mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b", size = 12507004 }, + { url = "https://files.pythonhosted.org/packages/4f/01/f6e4b9f0d031c11ccbd6f17da26564f3a0f3c4155af344006434b0a05a9d/mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66", size = 13245947 }, + { url = "https://files.pythonhosted.org/packages/d7/97/19727e7499bfa1ae0773d06afd30ac66a58ed7437d940c70548634b24185/mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428", size = 13499217 }, + { url = "https://files.pythonhosted.org/packages/9f/4f/90dc8c15c1441bf31cf0f9918bb077e452618708199e530f4cbd5cede6ff/mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed", size = 9766753 }, + { url = "https://files.pythonhosted.org/packages/88/87/cafd3ae563f88f94eec33f35ff722d043e09832ea8530ef149ec1efbaf08/mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f", size = 12731198 }, + { url = "https://files.pythonhosted.org/packages/0f/e0/1e96c3d4266a06d4b0197ace5356d67d937d8358e2ee3ffac71faa843724/mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341", size = 11817879 }, + { url = "https://files.pythonhosted.org/packages/72/ef/0c9ba89eb03453e76bdac5a78b08260a848c7bfc5d6603634774d9cd9525/mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d", size = 12427292 }, + { url = "https://files.pythonhosted.org/packages/1a/52/ec4a061dd599eb8179d5411d99775bec2a20542505988f40fc2fee781068/mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86", size = 13163750 }, + { url = "https://files.pythonhosted.org/packages/c4/5f/2cf2ceb3b36372d51568f2208c021870fe7834cf3186b653ac6446511839/mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37", size = 13351827 }, + { url = "https://files.pythonhosted.org/packages/c8/7d/2697b930179e7277529eaaec1513f8de622818696857f689e4a5432e5e27/mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8", size = 9757983 }, + { url = "https://files.pythonhosted.org/packages/07/06/dfdd2bc60c66611dd8335f463818514733bc763e4760dee289dcc33df709/mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34", size = 12908273 }, + { url = "https://files.pythonhosted.org/packages/81/14/6a9de6d13a122d5608e1a04130724caf9170333ac5a924e10f670687d3eb/mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764", size = 11920910 }, + { url = "https://files.pythonhosted.org/packages/5f/a9/b29de53e42f18e8cc547e38daa9dfa132ffdc64f7250e353f5c8cdd44bee/mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893", size = 12465585 }, + { url = "https://files.pythonhosted.org/packages/77/ae/6c3d2c7c61ff21f2bee938c917616c92ebf852f015fb55917fd6e2811db2/mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914", size = 13348562 }, + { url = "https://files.pythonhosted.org/packages/4d/31/aec68ab3b4aebdf8f36d191b0685d99faa899ab990753ca0fee60fb99511/mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8", size = 13533296 }, + { url = "https://files.pythonhosted.org/packages/9f/83/abcb3ad9478fca3ebeb6a5358bb0b22c95ea42b43b7789c7fb1297ca44f4/mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074", size = 9828828 }, + { url = "https://files.pythonhosted.org/packages/5f/04/7f462e6fbba87a72bc8097b93f6842499c428a6ff0c81dd46948d175afe8/mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc", size = 12898728 }, + { url = "https://files.pythonhosted.org/packages/99/5b/61ed4efb64f1871b41fd0b82d29a64640f3516078f6c7905b68ab1ad8b13/mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e", size = 11910758 }, + { url = "https://files.pythonhosted.org/packages/3c/46/d297d4b683cc89a6e4108c4250a6a6b717f5fa96e1a30a7944a6da44da35/mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986", size = 12475342 }, + { url = "https://files.pythonhosted.org/packages/83/45/4798f4d00df13eae3bfdf726c9244bcb495ab5bd588c0eed93a2f2dd67f3/mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d", size = 13338709 }, + { url = "https://files.pythonhosted.org/packages/d7/09/479f7358d9625172521a87a9271ddd2441e1dab16a09708f056e97007207/mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba", size = 13529806 }, + { url = "https://files.pythonhosted.org/packages/71/cf/ac0f2c7e9d0ea3c75cd99dff7aec1c9df4a1376537cb90e4c882267ee7e9/mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544", size = 9833262 }, + { url = "https://files.pythonhosted.org/packages/5a/0c/7d5300883da16f0063ae53996358758b2a2df2a09c72a5061fa79a1f5006/mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce", size = 12893775 }, + { url = "https://files.pythonhosted.org/packages/50/df/2cffbf25737bdb236f60c973edf62e3e7b4ee1c25b6878629e88e2cde967/mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d", size = 11936852 }, + { url = "https://files.pythonhosted.org/packages/be/50/34059de13dd269227fb4a03be1faee6e2a4b04a2051c82ac0a0b5a773c9a/mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c", size = 12480242 }, + { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683 }, + { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749 }, + { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959 }, + { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367 }, ] [[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 } 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 }, ] [[package]] @@ -2292,9 +2284,9 @@ dependencies = [ { name = "nbformat" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424, upload-time = "2024-12-19T10:32:27.164Z" } +sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434, upload-time = "2024-12-19T10:32:24.139Z" }, + { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434 }, ] [[package]] @@ -2317,9 +2309,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525 }, ] [[package]] @@ -2332,18 +2324,18 @@ dependencies = [ { name = "jupyter-core" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, ] [[package]] name = "nest-asyncio" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, ] [[package]] @@ -2353,9 +2345,9 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, ] [[package]] @@ -2368,9 +2360,9 @@ resolution-markers = [ "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] -sdist = { url = "https://files.pythonhosted.org/packages/e8/fc/7b6fd4d22c8c4dc5704430140d8b3f520531d4fe7328b8f8d03f5a7950e8/networkx-3.6.tar.gz", hash = "sha256:285276002ad1f7f7da0f7b42f004bcba70d381e936559166363707fdad3d72ad", size = 2511464, upload-time = "2025-11-24T03:03:47.158Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/fc/7b6fd4d22c8c4dc5704430140d8b3f520531d4fe7328b8f8d03f5a7950e8/networkx-3.6.tar.gz", hash = "sha256:285276002ad1f7f7da0f7b42f004bcba70d381e936559166363707fdad3d72ad", size = 2511464 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/c7/d64168da60332c17d24c0d2f08bdf3987e8d1ae9d84b5bbd0eec2eb26a55/networkx-3.6-py3-none-any.whl", hash = "sha256:cdb395b105806062473d3be36458d8f1459a4e4b98e236a66c3a48996e07684f", size = 2063713, upload-time = "2025-11-24T03:03:45.21Z" }, + { url = "https://files.pythonhosted.org/packages/07/c7/d64168da60332c17d24c0d2f08bdf3987e8d1ae9d84b5bbd0eec2eb26a55/networkx-3.6-py3-none-any.whl", hash = "sha256:cdb395b105806062473d3be36458d8f1459a4e4b98e236a66c3a48996e07684f", size = 2063713 }, ] [[package]] @@ -2384,9 +2376,9 @@ dependencies = [ { name = "notebook-shim" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/89/ac/a97041621250a4fc5af379fb377942841eea2ca146aab166b8fcdfba96c2/notebook-7.5.0.tar.gz", hash = "sha256:3b27eaf9913033c28dde92d02139414c608992e1df4b969c843219acf2ff95e4", size = 14052074, upload-time = "2025-11-19T08:36:20.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/89/ac/a97041621250a4fc5af379fb377942841eea2ca146aab166b8fcdfba96c2/notebook-7.5.0.tar.gz", hash = "sha256:3b27eaf9913033c28dde92d02139414c608992e1df4b969c843219acf2ff95e4", size = 14052074 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/96/00df2a4760f10f5af0f45c4955573cae6189931f9a30265a35865f8c1031/notebook-7.5.0-py3-none-any.whl", hash = "sha256:3300262d52905ca271bd50b22617681d95f08a8360d099e097726e6d2efb5811", size = 14460968, upload-time = "2025-11-19T08:36:15.869Z" }, + { url = "https://files.pythonhosted.org/packages/73/96/00df2a4760f10f5af0f45c4955573cae6189931f9a30265a35865f8c1031/notebook-7.5.0-py3-none-any.whl", hash = "sha256:3300262d52905ca271bd50b22617681d95f08a8360d099e097726e6d2efb5811", size = 14460968 }, ] [[package]] @@ -2396,9 +2388,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 }, ] [[package]] @@ -2408,62 +2400,62 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.11'", ] -sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, - { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, - { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, - { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, - { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, - { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, - { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, - { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, - { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, - { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, - { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, - { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, - { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, - { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, - { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, - { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, - { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, - { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, - { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, - { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, - { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, - { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245 }, + { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048 }, + { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542 }, + { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301 }, + { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320 }, + { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050 }, + { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034 }, + { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185 }, + { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149 }, + { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620 }, + { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963 }, + { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743 }, + { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616 }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579 }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005 }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570 }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548 }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521 }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866 }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455 }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348 }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362 }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103 }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382 }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462 }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618 }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511 }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783 }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506 }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190 }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828 }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006 }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765 }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736 }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719 }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072 }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213 }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632 }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532 }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885 }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467 }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144 }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217 }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014 }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935 }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122 }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143 }, + { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260 }, + { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225 }, + { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374 }, + { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391 }, + { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754 }, + { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476 }, + { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666 }, ] [[package]] @@ -2476,81 +2468,81 @@ resolution-markers = [ "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", ] -sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641, upload-time = "2025-11-16T22:49:19.336Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324, upload-time = "2025-11-16T22:49:22.582Z" }, - { url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872, upload-time = "2025-11-16T22:49:25.408Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148, upload-time = "2025-11-16T22:49:27.549Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282, upload-time = "2025-11-16T22:49:30.964Z" }, - { url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903, upload-time = "2025-11-16T22:49:34.191Z" }, - { url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672, upload-time = "2025-11-16T22:49:37.2Z" }, - { url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896, upload-time = "2025-11-16T22:49:39.727Z" }, - { url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608, upload-time = "2025-11-16T22:49:42.079Z" }, - { url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442, upload-time = "2025-11-16T22:49:43.99Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555, upload-time = "2025-11-16T22:49:47.092Z" }, - { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" }, - { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" }, - { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" }, - { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" }, - { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" }, - { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" }, - { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" }, - { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" }, - { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" }, - { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" }, - { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" }, - { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" }, - { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" }, - { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" }, - { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" }, - { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" }, - { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" }, - { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" }, - { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" }, - { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" }, - { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" }, - { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" }, - { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" }, - { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" }, - { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" }, - { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" }, - { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" }, - { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" }, - { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" }, - { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" }, - { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" }, - { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" }, - { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" }, - { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" }, - { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" }, - { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" }, - { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" }, - { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" }, - { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" }, - { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" }, - { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" }, - { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" }, - { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" }, - { url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689, upload-time = "2025-11-16T22:52:23.247Z" }, - { url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053, upload-time = "2025-11-16T22:52:26.367Z" }, - { url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635, upload-time = "2025-11-16T22:52:29.266Z" }, - { url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770, upload-time = "2025-11-16T22:52:31.421Z" }, - { url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768, upload-time = "2025-11-16T22:52:33.593Z" }, - { url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263, upload-time = "2025-11-16T22:52:36.369Z" }, - { url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213, upload-time = "2025-11-16T22:52:39.38Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641 }, + { url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324 }, + { url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872 }, + { url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148 }, + { url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282 }, + { url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903 }, + { url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672 }, + { url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896 }, + { url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608 }, + { url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442 }, + { url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555 }, + { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873 }, + { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838 }, + { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378 }, + { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559 }, + { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702 }, + { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086 }, + { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985 }, + { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976 }, + { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274 }, + { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922 }, + { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667 }, + { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251 }, + { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652 }, + { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172 }, + { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990 }, + { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902 }, + { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430 }, + { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551 }, + { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275 }, + { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637 }, + { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090 }, + { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710 }, + { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292 }, + { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897 }, + { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391 }, + { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275 }, + { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855 }, + { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359 }, + { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374 }, + { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587 }, + { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940 }, + { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341 }, + { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507 }, + { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706 }, + { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507 }, + { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049 }, + { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603 }, + { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696 }, + { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350 }, + { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190 }, + { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749 }, + { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432 }, + { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388 }, + { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651 }, + { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503 }, + { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612 }, + { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042 }, + { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502 }, + { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962 }, + { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054 }, + { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613 }, + { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147 }, + { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806 }, + { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760 }, + { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459 }, + { url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689 }, + { url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053 }, + { url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635 }, + { url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770 }, + { url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768 }, + { url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263 }, + { url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213 }, ] [[package]] @@ -2558,7 +2550,7 @@ name = "nvidia-cublas-cu12" version = "12.8.4.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, ] [[package]] @@ -2566,7 +2558,7 @@ name = "nvidia-cuda-cupti-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, ] [[package]] @@ -2574,7 +2566,7 @@ name = "nvidia-cuda-nvrtc-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, ] [[package]] @@ -2582,7 +2574,7 @@ name = "nvidia-cuda-runtime-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, ] [[package]] @@ -2593,7 +2585,7 @@ dependencies = [ { name = "nvidia-cublas-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, ] [[package]] @@ -2604,7 +2596,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, ] [[package]] @@ -2612,7 +2604,7 @@ name = "nvidia-cufile-cu12" version = "1.13.1.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, ] [[package]] @@ -2620,7 +2612,7 @@ name = "nvidia-curand-cu12" version = "10.3.9.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, ] [[package]] @@ -2633,7 +2625,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, ] [[package]] @@ -2644,7 +2636,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, ] [[package]] @@ -2652,7 +2644,7 @@ name = "nvidia-cusparselt-cu12" version = "0.7.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, ] [[package]] @@ -2660,7 +2652,7 @@ name = "nvidia-nccl-cu12" version = "2.27.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, ] [[package]] @@ -2668,7 +2660,7 @@ name = "nvidia-nvjitlink-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, ] [[package]] @@ -2676,7 +2668,7 @@ name = "nvidia-nvshmem-cu12" version = "3.3.20" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" }, + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145 }, ] [[package]] @@ -2684,7 +2676,7 @@ name = "nvidia-nvtx-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, ] [[package]] @@ -2701,163 +2693,163 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d5/e4/42591e356f1d53c568418dc7e30dcda7be31dd5a4d570bca22acb0525862/openai-2.8.1.tar.gz", hash = "sha256:cb1b79eef6e809f6da326a7ef6038719e35aa944c42d081807bfa1be8060f15f", size = 602490, upload-time = "2025-11-17T22:39:59.549Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/e4/42591e356f1d53c568418dc7e30dcda7be31dd5a4d570bca22acb0525862/openai-2.8.1.tar.gz", hash = "sha256:cb1b79eef6e809f6da326a7ef6038719e35aa944c42d081807bfa1be8060f15f", size = 602490 } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/4f/dbc0c124c40cb390508a82770fb9f6e3ed162560181a85089191a851c59a/openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463", size = 1022688, upload-time = "2025-11-17T22:39:57.675Z" }, + { url = "https://files.pythonhosted.org/packages/55/4f/dbc0c124c40cb390508a82770fb9f6e3ed162560181a85089191a851c59a/openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463", size = 1022688 }, ] [[package]] name = "orjson" version = "3.11.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870, upload-time = "2025-10-24T15:48:28.908Z" }, - { url = "https://files.pythonhosted.org/packages/44/1f/da46563c08bef33c41fd63c660abcd2184b4d2b950c8686317d03b9f5f0c/orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44", size = 130622, upload-time = "2025-10-24T15:48:31.361Z" }, - { url = "https://files.pythonhosted.org/packages/02/bd/b551a05d0090eab0bf8008a13a14edc0f3c3e0236aa6f5b697760dd2817b/orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c", size = 129344, upload-time = "2025-10-24T15:48:32.71Z" }, - { url = "https://files.pythonhosted.org/packages/87/6c/9ddd5e609f443b2548c5e7df3c44d0e86df2c68587a0e20c50018cdec535/orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23", size = 136633, upload-time = "2025-10-24T15:48:34.128Z" }, - { url = "https://files.pythonhosted.org/packages/95/f2/9f04f2874c625a9fb60f6918c33542320661255323c272e66f7dcce14df2/orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea", size = 137695, upload-time = "2025-10-24T15:48:35.654Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c2/c7302afcbdfe8a891baae0e2cee091583a30e6fa613e8bdf33b0e9c8a8c7/orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba", size = 136879, upload-time = "2025-10-24T15:48:37.483Z" }, - { url = "https://files.pythonhosted.org/packages/c6/3a/b31c8f0182a3e27f48e703f46e61bb769666cd0dac4700a73912d07a1417/orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff", size = 136374, upload-time = "2025-10-24T15:48:38.624Z" }, - { url = "https://files.pythonhosted.org/packages/29/d0/fd9ab96841b090d281c46df566b7f97bc6c8cd9aff3f3ebe99755895c406/orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac", size = 140519, upload-time = "2025-10-24T15:48:39.756Z" }, - { url = "https://files.pythonhosted.org/packages/d6/ce/36eb0f15978bb88e33a3480e1a3fb891caa0f189ba61ce7713e0ccdadabf/orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79", size = 406522, upload-time = "2025-10-24T15:48:41.198Z" }, - { url = "https://files.pythonhosted.org/packages/85/11/e8af3161a288f5c6a00c188fc729c7ba193b0cbc07309a1a29c004347c30/orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827", size = 149790, upload-time = "2025-10-24T15:48:42.664Z" }, - { url = "https://files.pythonhosted.org/packages/ea/96/209d52db0cf1e10ed48d8c194841e383e23c2ced5a2ee766649fe0e32d02/orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b", size = 140040, upload-time = "2025-10-24T15:48:44.042Z" }, - { url = "https://files.pythonhosted.org/packages/ef/0e/526db1395ccb74c3d59ac1660b9a325017096dc5643086b38f27662b4add/orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3", size = 135955, upload-time = "2025-10-24T15:48:45.495Z" }, - { url = "https://files.pythonhosted.org/packages/e6/69/18a778c9de3702b19880e73c9866b91cc85f904b885d816ba1ab318b223c/orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc", size = 131577, upload-time = "2025-10-24T15:48:46.609Z" }, - { url = "https://files.pythonhosted.org/packages/63/1d/1ea6005fffb56715fd48f632611e163d1604e8316a5bad2288bee9a1c9eb/orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39", size = 243498, upload-time = "2025-10-24T15:48:48.101Z" }, - { url = "https://files.pythonhosted.org/packages/37/d7/ffed10c7da677f2a9da307d491b9eb1d0125b0307019c4ad3d665fd31f4f/orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d", size = 128961, upload-time = "2025-10-24T15:48:49.571Z" }, - { url = "https://files.pythonhosted.org/packages/a2/96/3e4d10a18866d1368f73c8c44b7fe37cc8a15c32f2a7620be3877d4c55a3/orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175", size = 130321, upload-time = "2025-10-24T15:48:50.713Z" }, - { url = "https://files.pythonhosted.org/packages/eb/1f/465f66e93f434f968dd74d5b623eb62c657bdba2332f5a8be9f118bb74c7/orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040", size = 129207, upload-time = "2025-10-24T15:48:52.193Z" }, - { url = "https://files.pythonhosted.org/packages/28/43/d1e94837543321c119dff277ae8e348562fe8c0fafbb648ef7cb0c67e521/orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63", size = 136323, upload-time = "2025-10-24T15:48:54.806Z" }, - { url = "https://files.pythonhosted.org/packages/bf/04/93303776c8890e422a5847dd012b4853cdd88206b8bbd3edc292c90102d1/orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9", size = 137440, upload-time = "2025-10-24T15:48:56.326Z" }, - { url = "https://files.pythonhosted.org/packages/1e/ef/75519d039e5ae6b0f34d0336854d55544ba903e21bf56c83adc51cd8bf82/orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a", size = 136680, upload-time = "2025-10-24T15:48:57.476Z" }, - { url = "https://files.pythonhosted.org/packages/b5/18/bf8581eaae0b941b44efe14fee7b7862c3382fbc9a0842132cfc7cf5ecf4/orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be", size = 136160, upload-time = "2025-10-24T15:48:59.631Z" }, - { url = "https://files.pythonhosted.org/packages/c4/35/a6d582766d351f87fc0a22ad740a641b0a8e6fc47515e8614d2e4790ae10/orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7", size = 140318, upload-time = "2025-10-24T15:49:00.834Z" }, - { url = "https://files.pythonhosted.org/packages/76/b3/5a4801803ab2e2e2d703bce1a56540d9f99a9143fbec7bf63d225044fef8/orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549", size = 406330, upload-time = "2025-10-24T15:49:02.327Z" }, - { url = "https://files.pythonhosted.org/packages/80/55/a8f682f64833e3a649f620eafefee175cbfeb9854fc5b710b90c3bca45df/orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905", size = 149580, upload-time = "2025-10-24T15:49:03.517Z" }, - { url = "https://files.pythonhosted.org/packages/ad/e4/c132fa0c67afbb3eb88274fa98df9ac1f631a675e7877037c611805a4413/orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907", size = 139846, upload-time = "2025-10-24T15:49:04.761Z" }, - { url = "https://files.pythonhosted.org/packages/54/06/dc3491489efd651fef99c5908e13951abd1aead1257c67f16135f95ce209/orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c", size = 135781, upload-time = "2025-10-24T15:49:05.969Z" }, - { url = "https://files.pythonhosted.org/packages/79/b7/5e5e8d77bd4ea02a6ac54c42c818afb01dd31961be8a574eb79f1d2cfb1e/orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a", size = 131391, upload-time = "2025-10-24T15:49:07.355Z" }, - { url = "https://files.pythonhosted.org/packages/0f/dc/9484127cc1aa213be398ed735f5f270eedcb0c0977303a6f6ddc46b60204/orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045", size = 126252, upload-time = "2025-10-24T15:49:08.869Z" }, - { url = "https://files.pythonhosted.org/packages/63/51/6b556192a04595b93e277a9ff71cd0cc06c21a7df98bcce5963fa0f5e36f/orjson-3.11.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4371de39319d05d3f482f372720b841c841b52f5385bd99c61ed69d55d9ab50", size = 243571, upload-time = "2025-10-24T15:49:10.008Z" }, - { url = "https://files.pythonhosted.org/packages/1c/2c/2602392ddf2601d538ff11848b98621cd465d1a1ceb9db9e8043181f2f7b/orjson-3.11.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e41fd3b3cac850eaae78232f37325ed7d7436e11c471246b87b2cd294ec94853", size = 128891, upload-time = "2025-10-24T15:49:11.297Z" }, - { url = "https://files.pythonhosted.org/packages/4e/47/bf85dcf95f7a3a12bf223394a4f849430acd82633848d52def09fa3f46ad/orjson-3.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600e0e9ca042878c7fdf189cf1b028fe2c1418cc9195f6cb9824eb6ed99cb938", size = 130137, upload-time = "2025-10-24T15:49:12.544Z" }, - { url = "https://files.pythonhosted.org/packages/b4/4d/a0cb31007f3ab6f1fd2a1b17057c7c349bc2baf8921a85c0180cc7be8011/orjson-3.11.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bbf9b333f1568ef5da42bc96e18bf30fd7f8d54e9ae066d711056add508e415", size = 129152, upload-time = "2025-10-24T15:49:13.754Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ef/2811def7ce3d8576b19e3929fff8f8f0d44bc5eb2e0fdecb2e6e6cc6c720/orjson-3.11.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806363144bb6e7297b8e95870e78d30a649fdc4e23fc84daa80c8ebd366ce44", size = 136834, upload-time = "2025-10-24T15:49:15.307Z" }, - { url = "https://files.pythonhosted.org/packages/00/d4/9aee9e54f1809cec8ed5abd9bc31e8a9631d19460e3b8470145d25140106/orjson-3.11.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad355e8308493f527d41154e9053b86a5be892b3b359a5c6d5d95cda23601cb2", size = 137519, upload-time = "2025-10-24T15:49:16.557Z" }, - { url = "https://files.pythonhosted.org/packages/db/ea/67bfdb5465d5679e8ae8d68c11753aaf4f47e3e7264bad66dc2f2249e643/orjson-3.11.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a7517482667fb9f0ff1b2f16fe5829296ed7a655d04d68cd9711a4d8a4e708", size = 136749, upload-time = "2025-10-24T15:49:17.796Z" }, - { url = "https://files.pythonhosted.org/packages/01/7e/62517dddcfce6d53a39543cd74d0dccfcbdf53967017c58af68822100272/orjson-3.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97eb5942c7395a171cbfecc4ef6701fc3c403e762194683772df4c54cfbb2210", size = 136325, upload-time = "2025-10-24T15:49:19.347Z" }, - { url = "https://files.pythonhosted.org/packages/18/ae/40516739f99ab4c7ec3aaa5cc242d341fcb03a45d89edeeaabc5f69cb2cf/orjson-3.11.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:149d95d5e018bdd822e3f38c103b1a7c91f88d38a88aada5c4e9b3a73a244241", size = 140204, upload-time = "2025-10-24T15:49:20.545Z" }, - { url = "https://files.pythonhosted.org/packages/82/18/ff5734365623a8916e3a4037fcef1cd1782bfc14cf0992afe7940c5320bf/orjson-3.11.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:624f3951181eb46fc47dea3d221554e98784c823e7069edb5dbd0dc826ac909b", size = 406242, upload-time = "2025-10-24T15:49:21.884Z" }, - { url = "https://files.pythonhosted.org/packages/e1/43/96436041f0a0c8c8deca6a05ebeaf529bf1de04839f93ac5e7c479807aec/orjson-3.11.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03bfa548cf35e3f8b3a96c4e8e41f753c686ff3d8e182ce275b1751deddab58c", size = 150013, upload-time = "2025-10-24T15:49:23.185Z" }, - { url = "https://files.pythonhosted.org/packages/1b/48/78302d98423ed8780479a1e682b9aecb869e8404545d999d34fa486e573e/orjson-3.11.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:525021896afef44a68148f6ed8a8bf8375553d6066c7f48537657f64823565b9", size = 139951, upload-time = "2025-10-24T15:49:24.428Z" }, - { url = "https://files.pythonhosted.org/packages/4a/7b/ad613fdcdaa812f075ec0875143c3d37f8654457d2af17703905425981bf/orjson-3.11.4-cp312-cp312-win32.whl", hash = "sha256:b58430396687ce0f7d9eeb3dd47761ca7d8fda8e9eb92b3077a7a353a75efefa", size = 136049, upload-time = "2025-10-24T15:49:25.973Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3c/9cf47c3ff5f39b8350fb21ba65d789b6a1129d4cbb3033ba36c8a9023520/orjson-3.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:c6dbf422894e1e3c80a177133c0dda260f81428f9de16d61041949f6a2e5c140", size = 131461, upload-time = "2025-10-24T15:49:27.259Z" }, - { url = "https://files.pythonhosted.org/packages/c6/3b/e2425f61e5825dc5b08c2a5a2b3af387eaaca22a12b9c8c01504f8614c36/orjson-3.11.4-cp312-cp312-win_arm64.whl", hash = "sha256:d38d2bc06d6415852224fcc9c0bfa834c25431e466dc319f0edd56cca81aa96e", size = 126167, upload-time = "2025-10-24T15:49:28.511Z" }, - { url = "https://files.pythonhosted.org/packages/23/15/c52aa7112006b0f3d6180386c3a46ae057f932ab3425bc6f6ac50431cca1/orjson-3.11.4-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2d6737d0e616a6e053c8b4acc9eccea6b6cce078533666f32d140e4f85002534", size = 243525, upload-time = "2025-10-24T15:49:29.737Z" }, - { url = "https://files.pythonhosted.org/packages/ec/38/05340734c33b933fd114f161f25a04e651b0c7c33ab95e9416ade5cb44b8/orjson-3.11.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:afb14052690aa328cc118a8e09f07c651d301a72e44920b887c519b313d892ff", size = 128871, upload-time = "2025-10-24T15:49:31.109Z" }, - { url = "https://files.pythonhosted.org/packages/55/b9/ae8d34899ff0c012039b5a7cb96a389b2476e917733294e498586b45472d/orjson-3.11.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38aa9e65c591febb1b0aed8da4d469eba239d434c218562df179885c94e1a3ad", size = 130055, upload-time = "2025-10-24T15:49:33.382Z" }, - { url = "https://files.pythonhosted.org/packages/33/aa/6346dd5073730451bee3681d901e3c337e7ec17342fb79659ec9794fc023/orjson-3.11.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2cf4dfaf9163b0728d061bebc1e08631875c51cd30bf47cb9e3293bfbd7dcd5", size = 129061, upload-time = "2025-10-24T15:49:34.935Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8eea51598f66a6c853c380979912d17ec510e8e66b280d968602e680b942/orjson-3.11.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89216ff3dfdde0e4070932e126320a1752c9d9a758d6a32ec54b3b9334991a6a", size = 136541, upload-time = "2025-10-24T15:49:36.923Z" }, - { url = "https://files.pythonhosted.org/packages/9a/47/cb8c654fa9adcc60e99580e17c32b9e633290e6239a99efa6b885aba9dbc/orjson-3.11.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9daa26ca8e97fae0ce8aa5d80606ef8f7914e9b129b6b5df9104266f764ce436", size = 137535, upload-time = "2025-10-24T15:49:38.307Z" }, - { url = "https://files.pythonhosted.org/packages/43/92/04b8cc5c2b729f3437ee013ce14a60ab3d3001465d95c184758f19362f23/orjson-3.11.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c8b2769dc31883c44a9cd126560327767f848eb95f99c36c9932f51090bfce9", size = 136703, upload-time = "2025-10-24T15:49:40.795Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fd/d0733fcb9086b8be4ebcfcda2d0312865d17d0d9884378b7cffb29d0763f/orjson-3.11.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1469d254b9884f984026bd9b0fa5bbab477a4bfe558bba6848086f6d43eb5e73", size = 136293, upload-time = "2025-10-24T15:49:42.347Z" }, - { url = "https://files.pythonhosted.org/packages/c2/d7/3c5514e806837c210492d72ae30ccf050ce3f940f45bf085bab272699ef4/orjson-3.11.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68e44722541983614e37117209a194e8c3ad07838ccb3127d96863c95ec7f1e0", size = 140131, upload-time = "2025-10-24T15:49:43.638Z" }, - { url = "https://files.pythonhosted.org/packages/9c/dd/ba9d32a53207babf65bd510ac4d0faaa818bd0df9a9c6f472fe7c254f2e3/orjson-3.11.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e7805fda9672c12be2f22ae124dcd7b03928d6c197544fe12174b86553f3196", size = 406164, upload-time = "2025-10-24T15:49:45.498Z" }, - { url = "https://files.pythonhosted.org/packages/8e/f9/f68ad68f4af7c7bde57cd514eaa2c785e500477a8bc8f834838eb696a685/orjson-3.11.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04b69c14615fb4434ab867bf6f38b2d649f6f300af30a6705397e895f7aec67a", size = 149859, upload-time = "2025-10-24T15:49:46.981Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d2/7f847761d0c26818395b3d6b21fb6bc2305d94612a35b0a30eae65a22728/orjson-3.11.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:639c3735b8ae7f970066930e58cf0ed39a852d417c24acd4a25fc0b3da3c39a6", size = 139926, upload-time = "2025-10-24T15:49:48.321Z" }, - { url = "https://files.pythonhosted.org/packages/9f/37/acd14b12dc62db9a0e1d12386271b8661faae270b22492580d5258808975/orjson-3.11.4-cp313-cp313-win32.whl", hash = "sha256:6c13879c0d2964335491463302a6ca5ad98105fc5db3565499dcb80b1b4bd839", size = 136007, upload-time = "2025-10-24T15:49:49.938Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a9/967be009ddf0a1fffd7a67de9c36656b28c763659ef91352acc02cbe364c/orjson-3.11.4-cp313-cp313-win_amd64.whl", hash = "sha256:09bf242a4af98732db9f9a1ec57ca2604848e16f132e3f72edfd3c5c96de009a", size = 131314, upload-time = "2025-10-24T15:49:51.248Z" }, - { url = "https://files.pythonhosted.org/packages/cb/db/399abd6950fbd94ce125cb8cd1a968def95174792e127b0642781e040ed4/orjson-3.11.4-cp313-cp313-win_arm64.whl", hash = "sha256:a85f0adf63319d6c1ba06fb0dbf997fced64a01179cf17939a6caca662bf92de", size = 126152, upload-time = "2025-10-24T15:49:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/25/e3/54ff63c093cc1697e758e4fceb53164dd2661a7d1bcd522260ba09f54533/orjson-3.11.4-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:42d43a1f552be1a112af0b21c10a5f553983c2a0938d2bbb8ecd8bc9fb572803", size = 243501, upload-time = "2025-10-24T15:49:54.288Z" }, - { url = "https://files.pythonhosted.org/packages/ac/7d/e2d1076ed2e8e0ae9badca65bf7ef22710f93887b29eaa37f09850604e09/orjson-3.11.4-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:26a20f3fbc6c7ff2cb8e89c4c5897762c9d88cf37330c6a117312365d6781d54", size = 128862, upload-time = "2025-10-24T15:49:55.961Z" }, - { url = "https://files.pythonhosted.org/packages/9f/37/ca2eb40b90621faddfa9517dfe96e25f5ae4d8057a7c0cdd613c17e07b2c/orjson-3.11.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3f20be9048941c7ffa8fc523ccbd17f82e24df1549d1d1fe9317712d19938e", size = 130047, upload-time = "2025-10-24T15:49:57.406Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/1021ed35a1f2bad9040f05fa4cc4f9893410df0ba3eaa323ccf899b1c90a/orjson-3.11.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aac364c758dc87a52e68e349924d7e4ded348dedff553889e4d9f22f74785316", size = 129073, upload-time = "2025-10-24T15:49:58.782Z" }, - { url = "https://files.pythonhosted.org/packages/e8/3f/f84d966ec2a6fd5f73b1a707e7cd876813422ae4bf9f0145c55c9c6a0f57/orjson-3.11.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5c54a6d76e3d741dcc3f2707f8eeb9ba2a791d3adbf18f900219b62942803b1", size = 136597, upload-time = "2025-10-24T15:50:00.12Z" }, - { url = "https://files.pythonhosted.org/packages/32/78/4fa0aeca65ee82bbabb49e055bd03fa4edea33f7c080c5c7b9601661ef72/orjson-3.11.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f28485bdca8617b79d44627f5fb04336897041dfd9fa66d383a49d09d86798bc", size = 137515, upload-time = "2025-10-24T15:50:01.57Z" }, - { url = "https://files.pythonhosted.org/packages/c1/9d/0c102e26e7fde40c4c98470796d050a2ec1953897e2c8ab0cb95b0759fa2/orjson-3.11.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2a484cad3585e4ba61985a6062a4c2ed5c7925db6d39f1fa267c9d166487f", size = 136703, upload-time = "2025-10-24T15:50:02.944Z" }, - { url = "https://files.pythonhosted.org/packages/df/ac/2de7188705b4cdfaf0b6c97d2f7849c17d2003232f6e70df98602173f788/orjson-3.11.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e34dbd508cb91c54f9c9788923daca129fe5b55c5b4eebe713bf5ed3791280cf", size = 136311, upload-time = "2025-10-24T15:50:04.441Z" }, - { url = "https://files.pythonhosted.org/packages/e0/52/847fcd1a98407154e944feeb12e3b4d487a0e264c40191fb44d1269cbaa1/orjson-3.11.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b13c478fa413d4b4ee606ec8e11c3b2e52683a640b006bb586b3041c2ca5f606", size = 140127, upload-time = "2025-10-24T15:50:07.398Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ae/21d208f58bdb847dd4d0d9407e2929862561841baa22bdab7aea10ca088e/orjson-3.11.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:724ca721ecc8a831b319dcd72cfa370cc380db0bf94537f08f7edd0a7d4e1780", size = 406201, upload-time = "2025-10-24T15:50:08.796Z" }, - { url = "https://files.pythonhosted.org/packages/8d/55/0789d6de386c8366059db098a628e2ad8798069e94409b0d8935934cbcb9/orjson-3.11.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:977c393f2e44845ce1b540e19a786e9643221b3323dae190668a98672d43fb23", size = 149872, upload-time = "2025-10-24T15:50:10.234Z" }, - { url = "https://files.pythonhosted.org/packages/cc/1d/7ff81ea23310e086c17b41d78a72270d9de04481e6113dbe2ac19118f7fb/orjson-3.11.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e539e382cf46edec157ad66b0b0872a90d829a6b71f17cb633d6c160a223155", size = 139931, upload-time = "2025-10-24T15:50:11.623Z" }, - { url = "https://files.pythonhosted.org/packages/77/92/25b886252c50ed64be68c937b562b2f2333b45afe72d53d719e46a565a50/orjson-3.11.4-cp314-cp314-win32.whl", hash = "sha256:d63076d625babab9db5e7836118bdfa086e60f37d8a174194ae720161eb12394", size = 136065, upload-time = "2025-10-24T15:50:13.025Z" }, - { url = "https://files.pythonhosted.org/packages/63/b8/718eecf0bb7e9d64e4956afaafd23db9f04c776d445f59fe94f54bdae8f0/orjson-3.11.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a54d6635fa3aaa438ae32e8570b9f0de36f3f6562c308d2a2a452e8b0592db1", size = 131310, upload-time = "2025-10-24T15:50:14.46Z" }, - { url = "https://files.pythonhosted.org/packages/1a/bf/def5e25d4d8bfce296a9a7c8248109bf58622c21618b590678f945a2c59c/orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d", size = 126151, upload-time = "2025-10-24T15:50:15.878Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870 }, + { url = "https://files.pythonhosted.org/packages/44/1f/da46563c08bef33c41fd63c660abcd2184b4d2b950c8686317d03b9f5f0c/orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44", size = 130622 }, + { url = "https://files.pythonhosted.org/packages/02/bd/b551a05d0090eab0bf8008a13a14edc0f3c3e0236aa6f5b697760dd2817b/orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c", size = 129344 }, + { url = "https://files.pythonhosted.org/packages/87/6c/9ddd5e609f443b2548c5e7df3c44d0e86df2c68587a0e20c50018cdec535/orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23", size = 136633 }, + { url = "https://files.pythonhosted.org/packages/95/f2/9f04f2874c625a9fb60f6918c33542320661255323c272e66f7dcce14df2/orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea", size = 137695 }, + { url = "https://files.pythonhosted.org/packages/d2/c2/c7302afcbdfe8a891baae0e2cee091583a30e6fa613e8bdf33b0e9c8a8c7/orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba", size = 136879 }, + { url = "https://files.pythonhosted.org/packages/c6/3a/b31c8f0182a3e27f48e703f46e61bb769666cd0dac4700a73912d07a1417/orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff", size = 136374 }, + { url = "https://files.pythonhosted.org/packages/29/d0/fd9ab96841b090d281c46df566b7f97bc6c8cd9aff3f3ebe99755895c406/orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac", size = 140519 }, + { url = "https://files.pythonhosted.org/packages/d6/ce/36eb0f15978bb88e33a3480e1a3fb891caa0f189ba61ce7713e0ccdadabf/orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79", size = 406522 }, + { url = "https://files.pythonhosted.org/packages/85/11/e8af3161a288f5c6a00c188fc729c7ba193b0cbc07309a1a29c004347c30/orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827", size = 149790 }, + { url = "https://files.pythonhosted.org/packages/ea/96/209d52db0cf1e10ed48d8c194841e383e23c2ced5a2ee766649fe0e32d02/orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b", size = 140040 }, + { url = "https://files.pythonhosted.org/packages/ef/0e/526db1395ccb74c3d59ac1660b9a325017096dc5643086b38f27662b4add/orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3", size = 135955 }, + { url = "https://files.pythonhosted.org/packages/e6/69/18a778c9de3702b19880e73c9866b91cc85f904b885d816ba1ab318b223c/orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc", size = 131577 }, + { url = "https://files.pythonhosted.org/packages/63/1d/1ea6005fffb56715fd48f632611e163d1604e8316a5bad2288bee9a1c9eb/orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39", size = 243498 }, + { url = "https://files.pythonhosted.org/packages/37/d7/ffed10c7da677f2a9da307d491b9eb1d0125b0307019c4ad3d665fd31f4f/orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d", size = 128961 }, + { url = "https://files.pythonhosted.org/packages/a2/96/3e4d10a18866d1368f73c8c44b7fe37cc8a15c32f2a7620be3877d4c55a3/orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175", size = 130321 }, + { url = "https://files.pythonhosted.org/packages/eb/1f/465f66e93f434f968dd74d5b623eb62c657bdba2332f5a8be9f118bb74c7/orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040", size = 129207 }, + { url = "https://files.pythonhosted.org/packages/28/43/d1e94837543321c119dff277ae8e348562fe8c0fafbb648ef7cb0c67e521/orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63", size = 136323 }, + { url = "https://files.pythonhosted.org/packages/bf/04/93303776c8890e422a5847dd012b4853cdd88206b8bbd3edc292c90102d1/orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9", size = 137440 }, + { url = "https://files.pythonhosted.org/packages/1e/ef/75519d039e5ae6b0f34d0336854d55544ba903e21bf56c83adc51cd8bf82/orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a", size = 136680 }, + { url = "https://files.pythonhosted.org/packages/b5/18/bf8581eaae0b941b44efe14fee7b7862c3382fbc9a0842132cfc7cf5ecf4/orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be", size = 136160 }, + { url = "https://files.pythonhosted.org/packages/c4/35/a6d582766d351f87fc0a22ad740a641b0a8e6fc47515e8614d2e4790ae10/orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7", size = 140318 }, + { url = "https://files.pythonhosted.org/packages/76/b3/5a4801803ab2e2e2d703bce1a56540d9f99a9143fbec7bf63d225044fef8/orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549", size = 406330 }, + { url = "https://files.pythonhosted.org/packages/80/55/a8f682f64833e3a649f620eafefee175cbfeb9854fc5b710b90c3bca45df/orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905", size = 149580 }, + { url = "https://files.pythonhosted.org/packages/ad/e4/c132fa0c67afbb3eb88274fa98df9ac1f631a675e7877037c611805a4413/orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907", size = 139846 }, + { url = "https://files.pythonhosted.org/packages/54/06/dc3491489efd651fef99c5908e13951abd1aead1257c67f16135f95ce209/orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c", size = 135781 }, + { url = "https://files.pythonhosted.org/packages/79/b7/5e5e8d77bd4ea02a6ac54c42c818afb01dd31961be8a574eb79f1d2cfb1e/orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a", size = 131391 }, + { url = "https://files.pythonhosted.org/packages/0f/dc/9484127cc1aa213be398ed735f5f270eedcb0c0977303a6f6ddc46b60204/orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045", size = 126252 }, + { url = "https://files.pythonhosted.org/packages/63/51/6b556192a04595b93e277a9ff71cd0cc06c21a7df98bcce5963fa0f5e36f/orjson-3.11.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4371de39319d05d3f482f372720b841c841b52f5385bd99c61ed69d55d9ab50", size = 243571 }, + { url = "https://files.pythonhosted.org/packages/1c/2c/2602392ddf2601d538ff11848b98621cd465d1a1ceb9db9e8043181f2f7b/orjson-3.11.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e41fd3b3cac850eaae78232f37325ed7d7436e11c471246b87b2cd294ec94853", size = 128891 }, + { url = "https://files.pythonhosted.org/packages/4e/47/bf85dcf95f7a3a12bf223394a4f849430acd82633848d52def09fa3f46ad/orjson-3.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600e0e9ca042878c7fdf189cf1b028fe2c1418cc9195f6cb9824eb6ed99cb938", size = 130137 }, + { url = "https://files.pythonhosted.org/packages/b4/4d/a0cb31007f3ab6f1fd2a1b17057c7c349bc2baf8921a85c0180cc7be8011/orjson-3.11.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bbf9b333f1568ef5da42bc96e18bf30fd7f8d54e9ae066d711056add508e415", size = 129152 }, + { url = "https://files.pythonhosted.org/packages/f7/ef/2811def7ce3d8576b19e3929fff8f8f0d44bc5eb2e0fdecb2e6e6cc6c720/orjson-3.11.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806363144bb6e7297b8e95870e78d30a649fdc4e23fc84daa80c8ebd366ce44", size = 136834 }, + { url = "https://files.pythonhosted.org/packages/00/d4/9aee9e54f1809cec8ed5abd9bc31e8a9631d19460e3b8470145d25140106/orjson-3.11.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad355e8308493f527d41154e9053b86a5be892b3b359a5c6d5d95cda23601cb2", size = 137519 }, + { url = "https://files.pythonhosted.org/packages/db/ea/67bfdb5465d5679e8ae8d68c11753aaf4f47e3e7264bad66dc2f2249e643/orjson-3.11.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a7517482667fb9f0ff1b2f16fe5829296ed7a655d04d68cd9711a4d8a4e708", size = 136749 }, + { url = "https://files.pythonhosted.org/packages/01/7e/62517dddcfce6d53a39543cd74d0dccfcbdf53967017c58af68822100272/orjson-3.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97eb5942c7395a171cbfecc4ef6701fc3c403e762194683772df4c54cfbb2210", size = 136325 }, + { url = "https://files.pythonhosted.org/packages/18/ae/40516739f99ab4c7ec3aaa5cc242d341fcb03a45d89edeeaabc5f69cb2cf/orjson-3.11.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:149d95d5e018bdd822e3f38c103b1a7c91f88d38a88aada5c4e9b3a73a244241", size = 140204 }, + { url = "https://files.pythonhosted.org/packages/82/18/ff5734365623a8916e3a4037fcef1cd1782bfc14cf0992afe7940c5320bf/orjson-3.11.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:624f3951181eb46fc47dea3d221554e98784c823e7069edb5dbd0dc826ac909b", size = 406242 }, + { url = "https://files.pythonhosted.org/packages/e1/43/96436041f0a0c8c8deca6a05ebeaf529bf1de04839f93ac5e7c479807aec/orjson-3.11.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03bfa548cf35e3f8b3a96c4e8e41f753c686ff3d8e182ce275b1751deddab58c", size = 150013 }, + { url = "https://files.pythonhosted.org/packages/1b/48/78302d98423ed8780479a1e682b9aecb869e8404545d999d34fa486e573e/orjson-3.11.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:525021896afef44a68148f6ed8a8bf8375553d6066c7f48537657f64823565b9", size = 139951 }, + { url = "https://files.pythonhosted.org/packages/4a/7b/ad613fdcdaa812f075ec0875143c3d37f8654457d2af17703905425981bf/orjson-3.11.4-cp312-cp312-win32.whl", hash = "sha256:b58430396687ce0f7d9eeb3dd47761ca7d8fda8e9eb92b3077a7a353a75efefa", size = 136049 }, + { url = "https://files.pythonhosted.org/packages/b9/3c/9cf47c3ff5f39b8350fb21ba65d789b6a1129d4cbb3033ba36c8a9023520/orjson-3.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:c6dbf422894e1e3c80a177133c0dda260f81428f9de16d61041949f6a2e5c140", size = 131461 }, + { url = "https://files.pythonhosted.org/packages/c6/3b/e2425f61e5825dc5b08c2a5a2b3af387eaaca22a12b9c8c01504f8614c36/orjson-3.11.4-cp312-cp312-win_arm64.whl", hash = "sha256:d38d2bc06d6415852224fcc9c0bfa834c25431e466dc319f0edd56cca81aa96e", size = 126167 }, + { url = "https://files.pythonhosted.org/packages/23/15/c52aa7112006b0f3d6180386c3a46ae057f932ab3425bc6f6ac50431cca1/orjson-3.11.4-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2d6737d0e616a6e053c8b4acc9eccea6b6cce078533666f32d140e4f85002534", size = 243525 }, + { url = "https://files.pythonhosted.org/packages/ec/38/05340734c33b933fd114f161f25a04e651b0c7c33ab95e9416ade5cb44b8/orjson-3.11.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:afb14052690aa328cc118a8e09f07c651d301a72e44920b887c519b313d892ff", size = 128871 }, + { url = "https://files.pythonhosted.org/packages/55/b9/ae8d34899ff0c012039b5a7cb96a389b2476e917733294e498586b45472d/orjson-3.11.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38aa9e65c591febb1b0aed8da4d469eba239d434c218562df179885c94e1a3ad", size = 130055 }, + { url = "https://files.pythonhosted.org/packages/33/aa/6346dd5073730451bee3681d901e3c337e7ec17342fb79659ec9794fc023/orjson-3.11.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2cf4dfaf9163b0728d061bebc1e08631875c51cd30bf47cb9e3293bfbd7dcd5", size = 129061 }, + { url = "https://files.pythonhosted.org/packages/39/e4/8eea51598f66a6c853c380979912d17ec510e8e66b280d968602e680b942/orjson-3.11.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89216ff3dfdde0e4070932e126320a1752c9d9a758d6a32ec54b3b9334991a6a", size = 136541 }, + { url = "https://files.pythonhosted.org/packages/9a/47/cb8c654fa9adcc60e99580e17c32b9e633290e6239a99efa6b885aba9dbc/orjson-3.11.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9daa26ca8e97fae0ce8aa5d80606ef8f7914e9b129b6b5df9104266f764ce436", size = 137535 }, + { url = "https://files.pythonhosted.org/packages/43/92/04b8cc5c2b729f3437ee013ce14a60ab3d3001465d95c184758f19362f23/orjson-3.11.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c8b2769dc31883c44a9cd126560327767f848eb95f99c36c9932f51090bfce9", size = 136703 }, + { url = "https://files.pythonhosted.org/packages/aa/fd/d0733fcb9086b8be4ebcfcda2d0312865d17d0d9884378b7cffb29d0763f/orjson-3.11.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1469d254b9884f984026bd9b0fa5bbab477a4bfe558bba6848086f6d43eb5e73", size = 136293 }, + { url = "https://files.pythonhosted.org/packages/c2/d7/3c5514e806837c210492d72ae30ccf050ce3f940f45bf085bab272699ef4/orjson-3.11.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68e44722541983614e37117209a194e8c3ad07838ccb3127d96863c95ec7f1e0", size = 140131 }, + { url = "https://files.pythonhosted.org/packages/9c/dd/ba9d32a53207babf65bd510ac4d0faaa818bd0df9a9c6f472fe7c254f2e3/orjson-3.11.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e7805fda9672c12be2f22ae124dcd7b03928d6c197544fe12174b86553f3196", size = 406164 }, + { url = "https://files.pythonhosted.org/packages/8e/f9/f68ad68f4af7c7bde57cd514eaa2c785e500477a8bc8f834838eb696a685/orjson-3.11.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04b69c14615fb4434ab867bf6f38b2d649f6f300af30a6705397e895f7aec67a", size = 149859 }, + { url = "https://files.pythonhosted.org/packages/b6/d2/7f847761d0c26818395b3d6b21fb6bc2305d94612a35b0a30eae65a22728/orjson-3.11.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:639c3735b8ae7f970066930e58cf0ed39a852d417c24acd4a25fc0b3da3c39a6", size = 139926 }, + { url = "https://files.pythonhosted.org/packages/9f/37/acd14b12dc62db9a0e1d12386271b8661faae270b22492580d5258808975/orjson-3.11.4-cp313-cp313-win32.whl", hash = "sha256:6c13879c0d2964335491463302a6ca5ad98105fc5db3565499dcb80b1b4bd839", size = 136007 }, + { url = "https://files.pythonhosted.org/packages/c0/a9/967be009ddf0a1fffd7a67de9c36656b28c763659ef91352acc02cbe364c/orjson-3.11.4-cp313-cp313-win_amd64.whl", hash = "sha256:09bf242a4af98732db9f9a1ec57ca2604848e16f132e3f72edfd3c5c96de009a", size = 131314 }, + { url = "https://files.pythonhosted.org/packages/cb/db/399abd6950fbd94ce125cb8cd1a968def95174792e127b0642781e040ed4/orjson-3.11.4-cp313-cp313-win_arm64.whl", hash = "sha256:a85f0adf63319d6c1ba06fb0dbf997fced64a01179cf17939a6caca662bf92de", size = 126152 }, + { url = "https://files.pythonhosted.org/packages/25/e3/54ff63c093cc1697e758e4fceb53164dd2661a7d1bcd522260ba09f54533/orjson-3.11.4-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:42d43a1f552be1a112af0b21c10a5f553983c2a0938d2bbb8ecd8bc9fb572803", size = 243501 }, + { url = "https://files.pythonhosted.org/packages/ac/7d/e2d1076ed2e8e0ae9badca65bf7ef22710f93887b29eaa37f09850604e09/orjson-3.11.4-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:26a20f3fbc6c7ff2cb8e89c4c5897762c9d88cf37330c6a117312365d6781d54", size = 128862 }, + { url = "https://files.pythonhosted.org/packages/9f/37/ca2eb40b90621faddfa9517dfe96e25f5ae4d8057a7c0cdd613c17e07b2c/orjson-3.11.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3f20be9048941c7ffa8fc523ccbd17f82e24df1549d1d1fe9317712d19938e", size = 130047 }, + { url = "https://files.pythonhosted.org/packages/c7/62/1021ed35a1f2bad9040f05fa4cc4f9893410df0ba3eaa323ccf899b1c90a/orjson-3.11.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aac364c758dc87a52e68e349924d7e4ded348dedff553889e4d9f22f74785316", size = 129073 }, + { url = "https://files.pythonhosted.org/packages/e8/3f/f84d966ec2a6fd5f73b1a707e7cd876813422ae4bf9f0145c55c9c6a0f57/orjson-3.11.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5c54a6d76e3d741dcc3f2707f8eeb9ba2a791d3adbf18f900219b62942803b1", size = 136597 }, + { url = "https://files.pythonhosted.org/packages/32/78/4fa0aeca65ee82bbabb49e055bd03fa4edea33f7c080c5c7b9601661ef72/orjson-3.11.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f28485bdca8617b79d44627f5fb04336897041dfd9fa66d383a49d09d86798bc", size = 137515 }, + { url = "https://files.pythonhosted.org/packages/c1/9d/0c102e26e7fde40c4c98470796d050a2ec1953897e2c8ab0cb95b0759fa2/orjson-3.11.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2a484cad3585e4ba61985a6062a4c2ed5c7925db6d39f1fa267c9d166487f", size = 136703 }, + { url = "https://files.pythonhosted.org/packages/df/ac/2de7188705b4cdfaf0b6c97d2f7849c17d2003232f6e70df98602173f788/orjson-3.11.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e34dbd508cb91c54f9c9788923daca129fe5b55c5b4eebe713bf5ed3791280cf", size = 136311 }, + { url = "https://files.pythonhosted.org/packages/e0/52/847fcd1a98407154e944feeb12e3b4d487a0e264c40191fb44d1269cbaa1/orjson-3.11.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b13c478fa413d4b4ee606ec8e11c3b2e52683a640b006bb586b3041c2ca5f606", size = 140127 }, + { url = "https://files.pythonhosted.org/packages/c1/ae/21d208f58bdb847dd4d0d9407e2929862561841baa22bdab7aea10ca088e/orjson-3.11.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:724ca721ecc8a831b319dcd72cfa370cc380db0bf94537f08f7edd0a7d4e1780", size = 406201 }, + { url = "https://files.pythonhosted.org/packages/8d/55/0789d6de386c8366059db098a628e2ad8798069e94409b0d8935934cbcb9/orjson-3.11.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:977c393f2e44845ce1b540e19a786e9643221b3323dae190668a98672d43fb23", size = 149872 }, + { url = "https://files.pythonhosted.org/packages/cc/1d/7ff81ea23310e086c17b41d78a72270d9de04481e6113dbe2ac19118f7fb/orjson-3.11.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e539e382cf46edec157ad66b0b0872a90d829a6b71f17cb633d6c160a223155", size = 139931 }, + { url = "https://files.pythonhosted.org/packages/77/92/25b886252c50ed64be68c937b562b2f2333b45afe72d53d719e46a565a50/orjson-3.11.4-cp314-cp314-win32.whl", hash = "sha256:d63076d625babab9db5e7836118bdfa086e60f37d8a174194ae720161eb12394", size = 136065 }, + { url = "https://files.pythonhosted.org/packages/63/b8/718eecf0bb7e9d64e4956afaafd23db9f04c776d445f59fe94f54bdae8f0/orjson-3.11.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a54d6635fa3aaa438ae32e8570b9f0de36f3f6562c308d2a2a452e8b0592db1", size = 131310 }, + { url = "https://files.pythonhosted.org/packages/1a/bf/def5e25d4d8bfce296a9a7c8248109bf58622c21618b590678f945a2c59c/orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d", size = 126151 }, ] [[package]] name = "ormsgpack" version = "1.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/67/d5ef41c3b4a94400be801984ef7c7fc9623e1a82b643e74eeec367e7462b/ormsgpack-1.12.0.tar.gz", hash = "sha256:94be818fdbb0285945839b88763b269987787cb2f7ef280cad5d6ec815b7e608", size = 49959, upload-time = "2025-11-04T18:30:10.083Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/0c/8f45fcd22c95190b05d4fba71375d8f783a9e3b0b6aaf476812b693e3868/ormsgpack-1.12.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e08904c232358b94a682ccfbb680bc47d3fd5c424bb7dccb65974dd20c95e8e1", size = 369156, upload-time = "2025-11-04T18:29:17.629Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f8/c7adc093d4ceb05e38786906815f868210f808326c27f8124b4d9466a26b/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9ed7a4b0037d69c8ba7e670e03ee65ae8d5c5114a409e73c5770d7fb5e4b895", size = 195743, upload-time = "2025-11-04T18:29:18.964Z" }, - { url = "https://files.pythonhosted.org/packages/fe/b8/bf002648fa6c150ed6157837b00303edafb35f65c352429463f83214de18/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db2928525b684f3f2af0367aef7ae8d20cde37fc5349c700017129d493a755aa", size = 206472, upload-time = "2025-11-04T18:29:19.951Z" }, - { url = "https://files.pythonhosted.org/packages/23/d6/1f445947c95a931bb189b7864a3f9dcbeebe7dcbc1b3c7387427b3779228/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45f911d9c5b23d11e49ff03fc8f9566745a2b1a7d9033733a1c0a2fa9301cd60", size = 207959, upload-time = "2025-11-04T18:29:21.282Z" }, - { url = "https://files.pythonhosted.org/packages/5c/9c/dd8ccd7553a5c1d0b4b69a0541611983a2f9bc2e8c5708a4bfffc0100468/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:98c54ae6fd682b2aceb264505af9b2255f3df9d84e6e4369bc44d2110f1f311d", size = 377659, upload-time = "2025-11-04T18:29:22.561Z" }, - { url = "https://files.pythonhosted.org/packages/3d/08/3282d8f6330e742d4cdbcfbe2c100b403ae5526ae82a1c1b6a11b7967e37/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:857ab987c3502de08258cc4baf0e87267cb2c80931601084e13df3c355b1ab9d", size = 471391, upload-time = "2025-11-04T18:29:23.663Z" }, - { url = "https://files.pythonhosted.org/packages/18/d4/94a2fbfd4837754bda7a099b6a23b9d40aba9e76e1af8b8fb8133612eb54/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27579d45dc502ee736238e1024559cb0a01aa72a3b68827448b8edf6a2dcdc9c", size = 381501, upload-time = "2025-11-04T18:29:24.771Z" }, - { url = "https://files.pythonhosted.org/packages/d8/c6/1a9fa122cb5deb10b067bbaa43165b12291a914cc0ce364988ff17bbf405/ormsgpack-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c78379d054760875540cf2e81f28da1bb78d09fda3eabdbeb6c53b3e297158cb", size = 112715, upload-time = "2025-11-04T18:29:26.016Z" }, - { url = "https://files.pythonhosted.org/packages/1a/ba/3cae83cf36420c1c8dd294f16c852c03313aafe2439a165c4c6ac611b1d0/ormsgpack-1.12.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c40d86d77391b18dd34de5295e3de2b8ad818bcab9c9def4121c8ec5c9714ae4", size = 369159, upload-time = "2025-11-04T18:29:27.057Z" }, - { url = "https://files.pythonhosted.org/packages/97/d4/5e176309e01a8b9098d80201aac1eb7db9336c3b5b4fa6254a2bbb0d0fa0/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:777b7fab364dc0f200bb382a98a385c8222ffa6a2333d627d763797326202c86", size = 195744, upload-time = "2025-11-04T18:29:28.069Z" }, - { url = "https://files.pythonhosted.org/packages/4f/83/6d80c8c5571639c000a39f38f77752dfaf9d9e552d775331e8d280f66a4e/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b5089ad9dd5b3d3013b245a55e4abaea2f8ad70f4a78e1b002127b02340004", size = 206474, upload-time = "2025-11-04T18:29:29.034Z" }, - { url = "https://files.pythonhosted.org/packages/5e/e6/940311e48dc0cfc3e212bd7007a21ed0825158638057687d804f2c5c2cca/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaf0c87cace7bc08fbf68c5cc66605b593df6427e9f4de235b2da358787e008", size = 207959, upload-time = "2025-11-04T18:29:30.315Z" }, - { url = "https://files.pythonhosted.org/packages/1a/e3/fbe94b0a311815343b86a95a0627e4901b11ff6fd522679ca29a2a88c99b/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f62d476fe28bc5675d9aff30341bfa9f41d7de332c5b63fbbe9aaf6bb7ec74d4", size = 377666, upload-time = "2025-11-04T18:29:31.38Z" }, - { url = "https://files.pythonhosted.org/packages/a3/3b/229cfa28076798ffb619aaa854b842de3f2ed5ea4e6509bf34d14c038c4d/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ded7810095b887e28434f32f5a345d354e88cf851bab3c5435aeb86a718618d2", size = 471394, upload-time = "2025-11-04T18:29:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/6b/bd/4eae4ab35586e4175c07acb5f98aec83aa9d8987f71ea0443aa900191bdf/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f72a1dea0c4ae7c4101dcfbe8133f274a9d769d0b87fe5188db4fab07ffabaee", size = 381506, upload-time = "2025-11-04T18:29:33.533Z" }, - { url = "https://files.pythonhosted.org/packages/dd/51/f9d56d6d015cbfa1ce9a4358ca30a41744644f0cf606e060d7203efe5af8/ormsgpack-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f479bfef847255d7d0b12c7a198f6a21490155da2da3062e082ba370893d4a1", size = 112707, upload-time = "2025-11-04T18:29:34.898Z" }, - { url = "https://files.pythonhosted.org/packages/f4/07/bb189ef7072979f2f96e8716e952172efdce9c54930aa0814bec73aee19b/ormsgpack-1.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:3583ca410e4502144b2594170542e4bbef7b15643fd1208703ae820f11029036", size = 106533, upload-time = "2025-11-04T18:29:36.112Z" }, - { url = "https://files.pythonhosted.org/packages/a2/f2/c1036b2775fcc0cfa5fd618c53bcd3b862ee07298fb627f03af4c7982f84/ormsgpack-1.12.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e0c1e08b64d99076fee155276097489b82cc56e8d5951c03c721a65a32f44494", size = 369538, upload-time = "2025-11-04T18:29:37.125Z" }, - { url = "https://files.pythonhosted.org/packages/d9/ca/526c4ae02f3cb34621af91bf8282a10d666757c2e0c6ff391ff5d403d607/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd43bcb299131690b8e0677af172020b2ada8e625169034b42ac0c13adf84aa", size = 195872, upload-time = "2025-11-04T18:29:38.34Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/83bb7968e9715f6a85be53d041b1e6324a05428f56b8b980dac866886871/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0149d595341e22ead340bf281b2995c4cc7dc8d522a6b5f575fe17aa407604", size = 206469, upload-time = "2025-11-04T18:29:39.749Z" }, - { url = "https://files.pythonhosted.org/packages/02/e3/9e93ca1065f2d4af035804a842b1ff3025bab580c7918239bb225cd1fee2/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f19a1b27d169deb553c80fd10b589fc2be1fc14cee779fae79fcaf40db04de2b", size = 208273, upload-time = "2025-11-04T18:29:40.769Z" }, - { url = "https://files.pythonhosted.org/packages/b3/d8/6d6ef901b3a8b8f3ab8836b135a56eb7f66c559003e251d9530bedb12627/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f28896942d655064940dfe06118b7ce1e3468d051483148bf02c99ec157483a", size = 377839, upload-time = "2025-11-04T18:29:42.092Z" }, - { url = "https://files.pythonhosted.org/packages/4c/72/fcb704bfa4c2c3a37b647d597cc45a13cffc9d50baac635a9ad620731d29/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9396efcfa48b4abbc06e44c5dbc3c4574a8381a80cb4cd01eea15d28b38c554e", size = 471446, upload-time = "2025-11-04T18:29:43.133Z" }, - { url = "https://files.pythonhosted.org/packages/84/f8/402e4e3eb997c2ee534c99bec4b5bb359c2a1f9edadf043e254a71e11378/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:96586ed537a5fb386a162c4f9f7d8e6f76e07b38a990d50c73f11131e00ff040", size = 381783, upload-time = "2025-11-04T18:29:44.466Z" }, - { url = "https://files.pythonhosted.org/packages/f0/8d/5897b700360bc00911b70ae5ef1134ee7abf5baa81a92a4be005917d3dfd/ormsgpack-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e70387112fb3870e4844de090014212cdcf1342f5022047aecca01ec7de05d7a", size = 112943, upload-time = "2025-11-04T18:29:45.468Z" }, - { url = "https://files.pythonhosted.org/packages/5b/44/1e73649f79bb96d6cf9e5bcbac68b6216d238bba80af351c4c0cbcf7ee15/ormsgpack-1.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:d71290a23de5d4829610c42665d816c661ecad8979883f3f06b2e3ab9639962e", size = 106688, upload-time = "2025-11-04T18:29:46.411Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e8/35f11ce9313111488b26b3035e4cbe55caa27909c0b6c8b5b5cd59f9661e/ormsgpack-1.12.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:766f2f3b512d85cd375b26a8b1329b99843560b50b93d3880718e634ad4a5de5", size = 369574, upload-time = "2025-11-04T18:29:47.431Z" }, - { url = "https://files.pythonhosted.org/packages/61/b0/77461587f412d4e598d3687bafe23455ed0f26269f44be20252eddaa624e/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84b285b1f3f185aad7da45641b873b30acfd13084cf829cf668c4c6480a81583", size = 195893, upload-time = "2025-11-04T18:29:48.735Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/e197ceb04c3b550589e5407fc9fdae10f4e2e2eba5fdac921a269e02e974/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e23604fc79fe110292cb365f4c8232e64e63a34f470538be320feae3921f271b", size = 206503, upload-time = "2025-11-04T18:29:49.99Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b1/7fa8ba82a25cef678983c7976f85edeef5014f5c26495f338258e6a3cf1c/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc32b156c113a0fae2975051417d8d9a7a5247c34b2d7239410c46b75ce9348a", size = 208257, upload-time = "2025-11-04T18:29:51.007Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b1/759e999390000d2589e6d0797f7265e6ec28378547075d28d3736248ab63/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:94ac500dd10c20fa8b8a23bc55606250bfe711bf9716828d9f3d44dfd1f25668", size = 377852, upload-time = "2025-11-04T18:29:52.103Z" }, - { url = "https://files.pythonhosted.org/packages/51/e7/0af737c94272494d9d84a3c29cc42c973ef7fd2342917020906596db863c/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c5201ff7ec24f721f813a182885a17064cffdbe46b2412685a52e6374a872c8f", size = 471456, upload-time = "2025-11-04T18:29:53.336Z" }, - { url = "https://files.pythonhosted.org/packages/f4/ba/c81f0aa4f19fbf457213395945b672e6fde3ce777e3587456e7f0fca2147/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a9740bb3839c9368aacae1cbcfc474ee6976458f41cc135372b7255d5206c953", size = 381813, upload-time = "2025-11-04T18:29:54.394Z" }, - { url = "https://files.pythonhosted.org/packages/ce/15/429c72d64323503fd42cc4ca8398930ded8aa8b3470df8a86b3bbae7a35c/ormsgpack-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ed37f29772432048b58174e920a1d4c4cde0404a5d448d3d8bbcc95d86a6918", size = 112949, upload-time = "2025-11-04T18:29:55.371Z" }, - { url = "https://files.pythonhosted.org/packages/55/b9/e72c451a40f8c57bfc229e0b8e536ecea7203c8f0a839676df2ffb605c62/ormsgpack-1.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:b03994bbec5d6d42e03d6604e327863f885bde67aa61e06107ce1fa5bdd3e71d", size = 106689, upload-time = "2025-11-04T18:29:56.262Z" }, - { url = "https://files.pythonhosted.org/packages/13/16/13eab1a75da531b359105fdee90dda0b6bd1ca0a09880250cf91d8bdfdea/ormsgpack-1.12.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0f3981ba3cba80656012090337e548e597799e14b41e3d0b595ab5ab05a23d7f", size = 369620, upload-time = "2025-11-04T18:29:57.255Z" }, - { url = "https://files.pythonhosted.org/packages/a0/c1/cbcc38b7af4ce58d8893e56d3595c0c8dcd117093bf048f889cf351bdba0/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:901f6f55184d6776dbd5183cbce14caf05bf7f467eef52faf9b094686980bf71", size = 195925, upload-time = "2025-11-04T18:29:58.34Z" }, - { url = "https://files.pythonhosted.org/packages/5c/59/4fa4dc0681490e12b75333440a1c0fd9741b0ebff272b1db4a29d35c2021/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e13b15412571422b711b40f45e3fe6d993ea3314b5e97d1a853fe99226c5effc", size = 206594, upload-time = "2025-11-04T18:29:59.329Z" }, - { url = "https://files.pythonhosted.org/packages/39/67/249770896bc32bb91b22c30256961f935d0915cbcf6e289a7fc961d9b14c/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91fa8a452553a62e5fb3fbab471e7faf7b3bec3c87a2f355ebf3d7aab290fe4f", size = 208307, upload-time = "2025-11-04T18:30:00.377Z" }, - { url = "https://files.pythonhosted.org/packages/07/0a/e041a248cd72f2f4c07e155913e0a3ede4c86cf21a40ae6cd79f135f2847/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74ec101f69624695eec4ce7c953192d97748254abe78fb01b591f06d529e1952", size = 377844, upload-time = "2025-11-04T18:30:01.389Z" }, - { url = "https://files.pythonhosted.org/packages/d8/71/6f7773e4ffda73a358ce4bba69b3e8bee9d40a7a06315e4c1cd7a3ea9d02/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9bbf7896580848326c1f9bd7531f264e561f98db7e08e15aa75963d83832c717", size = 471572, upload-time = "2025-11-04T18:30:02.486Z" }, - { url = "https://files.pythonhosted.org/packages/65/29/af6769a4289c07acc71e7bda1d64fb31800563147d73142686e185e82348/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7567917da613b8f8d591c1674e411fd3404bea41ef2b9a0e0a1e049c0f9406d7", size = 381842, upload-time = "2025-11-04T18:30:03.799Z" }, - { url = "https://files.pythonhosted.org/packages/0b/dd/0a86195ee7a1a96c088aefc8504385e881cf56f4563ed81bafe21cbf1fb0/ormsgpack-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e418256c5d8622b8bc92861936f7c6a0131355e7bcad88a42102ae8227f8a1c", size = 113008, upload-time = "2025-11-04T18:30:04.777Z" }, - { url = "https://files.pythonhosted.org/packages/4c/57/fafc79e32f3087f6f26f509d80b8167516326bfea38d30502627c01617e0/ormsgpack-1.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:433ace29aa02713554f714c62a4e4dcad0c9e32674ba4f66742c91a4c3b1b969", size = 106648, upload-time = "2025-11-04T18:30:05.708Z" }, - { url = "https://files.pythonhosted.org/packages/b3/cf/5d58d9b132128d2fe5d586355dde76af386554abef00d608f66b913bff1f/ormsgpack-1.12.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e57164be4ca34b64e210ec515059193280ac84df4d6f31a6fcbfb2fc8436de55", size = 369803, upload-time = "2025-11-04T18:30:06.728Z" }, - { url = "https://files.pythonhosted.org/packages/67/42/968a2da361eaff2e4cbb17c82c7599787babf16684110ad70409646cc1e4/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:904f96289deaa92fc6440b122edc27c5bdc28234edd63717f6d853d88c823a83", size = 195991, upload-time = "2025-11-04T18:30:07.713Z" }, - { url = "https://files.pythonhosted.org/packages/03/f0/9696c6c6cf8ad35170f0be8d0ef3523cc258083535f6c8071cb8235ebb8b/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b291d086e524a1062d57d1b7b5a8bcaaf29caebf0212fec12fd86240bd33633", size = 208316, upload-time = "2025-11-04T18:30:08.663Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/6c/67/d5ef41c3b4a94400be801984ef7c7fc9623e1a82b643e74eeec367e7462b/ormsgpack-1.12.0.tar.gz", hash = "sha256:94be818fdbb0285945839b88763b269987787cb2f7ef280cad5d6ec815b7e608", size = 49959 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/0c/8f45fcd22c95190b05d4fba71375d8f783a9e3b0b6aaf476812b693e3868/ormsgpack-1.12.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e08904c232358b94a682ccfbb680bc47d3fd5c424bb7dccb65974dd20c95e8e1", size = 369156 }, + { url = "https://files.pythonhosted.org/packages/d2/f8/c7adc093d4ceb05e38786906815f868210f808326c27f8124b4d9466a26b/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9ed7a4b0037d69c8ba7e670e03ee65ae8d5c5114a409e73c5770d7fb5e4b895", size = 195743 }, + { url = "https://files.pythonhosted.org/packages/fe/b8/bf002648fa6c150ed6157837b00303edafb35f65c352429463f83214de18/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db2928525b684f3f2af0367aef7ae8d20cde37fc5349c700017129d493a755aa", size = 206472 }, + { url = "https://files.pythonhosted.org/packages/23/d6/1f445947c95a931bb189b7864a3f9dcbeebe7dcbc1b3c7387427b3779228/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45f911d9c5b23d11e49ff03fc8f9566745a2b1a7d9033733a1c0a2fa9301cd60", size = 207959 }, + { url = "https://files.pythonhosted.org/packages/5c/9c/dd8ccd7553a5c1d0b4b69a0541611983a2f9bc2e8c5708a4bfffc0100468/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:98c54ae6fd682b2aceb264505af9b2255f3df9d84e6e4369bc44d2110f1f311d", size = 377659 }, + { url = "https://files.pythonhosted.org/packages/3d/08/3282d8f6330e742d4cdbcfbe2c100b403ae5526ae82a1c1b6a11b7967e37/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:857ab987c3502de08258cc4baf0e87267cb2c80931601084e13df3c355b1ab9d", size = 471391 }, + { url = "https://files.pythonhosted.org/packages/18/d4/94a2fbfd4837754bda7a099b6a23b9d40aba9e76e1af8b8fb8133612eb54/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27579d45dc502ee736238e1024559cb0a01aa72a3b68827448b8edf6a2dcdc9c", size = 381501 }, + { url = "https://files.pythonhosted.org/packages/d8/c6/1a9fa122cb5deb10b067bbaa43165b12291a914cc0ce364988ff17bbf405/ormsgpack-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c78379d054760875540cf2e81f28da1bb78d09fda3eabdbeb6c53b3e297158cb", size = 112715 }, + { url = "https://files.pythonhosted.org/packages/1a/ba/3cae83cf36420c1c8dd294f16c852c03313aafe2439a165c4c6ac611b1d0/ormsgpack-1.12.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c40d86d77391b18dd34de5295e3de2b8ad818bcab9c9def4121c8ec5c9714ae4", size = 369159 }, + { url = "https://files.pythonhosted.org/packages/97/d4/5e176309e01a8b9098d80201aac1eb7db9336c3b5b4fa6254a2bbb0d0fa0/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:777b7fab364dc0f200bb382a98a385c8222ffa6a2333d627d763797326202c86", size = 195744 }, + { url = "https://files.pythonhosted.org/packages/4f/83/6d80c8c5571639c000a39f38f77752dfaf9d9e552d775331e8d280f66a4e/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b5089ad9dd5b3d3013b245a55e4abaea2f8ad70f4a78e1b002127b02340004", size = 206474 }, + { url = "https://files.pythonhosted.org/packages/5e/e6/940311e48dc0cfc3e212bd7007a21ed0825158638057687d804f2c5c2cca/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaf0c87cace7bc08fbf68c5cc66605b593df6427e9f4de235b2da358787e008", size = 207959 }, + { url = "https://files.pythonhosted.org/packages/1a/e3/fbe94b0a311815343b86a95a0627e4901b11ff6fd522679ca29a2a88c99b/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f62d476fe28bc5675d9aff30341bfa9f41d7de332c5b63fbbe9aaf6bb7ec74d4", size = 377666 }, + { url = "https://files.pythonhosted.org/packages/a3/3b/229cfa28076798ffb619aaa854b842de3f2ed5ea4e6509bf34d14c038c4d/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ded7810095b887e28434f32f5a345d354e88cf851bab3c5435aeb86a718618d2", size = 471394 }, + { url = "https://files.pythonhosted.org/packages/6b/bd/4eae4ab35586e4175c07acb5f98aec83aa9d8987f71ea0443aa900191bdf/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f72a1dea0c4ae7c4101dcfbe8133f274a9d769d0b87fe5188db4fab07ffabaee", size = 381506 }, + { url = "https://files.pythonhosted.org/packages/dd/51/f9d56d6d015cbfa1ce9a4358ca30a41744644f0cf606e060d7203efe5af8/ormsgpack-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f479bfef847255d7d0b12c7a198f6a21490155da2da3062e082ba370893d4a1", size = 112707 }, + { url = "https://files.pythonhosted.org/packages/f4/07/bb189ef7072979f2f96e8716e952172efdce9c54930aa0814bec73aee19b/ormsgpack-1.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:3583ca410e4502144b2594170542e4bbef7b15643fd1208703ae820f11029036", size = 106533 }, + { url = "https://files.pythonhosted.org/packages/a2/f2/c1036b2775fcc0cfa5fd618c53bcd3b862ee07298fb627f03af4c7982f84/ormsgpack-1.12.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e0c1e08b64d99076fee155276097489b82cc56e8d5951c03c721a65a32f44494", size = 369538 }, + { url = "https://files.pythonhosted.org/packages/d9/ca/526c4ae02f3cb34621af91bf8282a10d666757c2e0c6ff391ff5d403d607/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd43bcb299131690b8e0677af172020b2ada8e625169034b42ac0c13adf84aa", size = 195872 }, + { url = "https://files.pythonhosted.org/packages/7f/0f/83bb7968e9715f6a85be53d041b1e6324a05428f56b8b980dac866886871/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0149d595341e22ead340bf281b2995c4cc7dc8d522a6b5f575fe17aa407604", size = 206469 }, + { url = "https://files.pythonhosted.org/packages/02/e3/9e93ca1065f2d4af035804a842b1ff3025bab580c7918239bb225cd1fee2/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f19a1b27d169deb553c80fd10b589fc2be1fc14cee779fae79fcaf40db04de2b", size = 208273 }, + { url = "https://files.pythonhosted.org/packages/b3/d8/6d6ef901b3a8b8f3ab8836b135a56eb7f66c559003e251d9530bedb12627/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f28896942d655064940dfe06118b7ce1e3468d051483148bf02c99ec157483a", size = 377839 }, + { url = "https://files.pythonhosted.org/packages/4c/72/fcb704bfa4c2c3a37b647d597cc45a13cffc9d50baac635a9ad620731d29/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9396efcfa48b4abbc06e44c5dbc3c4574a8381a80cb4cd01eea15d28b38c554e", size = 471446 }, + { url = "https://files.pythonhosted.org/packages/84/f8/402e4e3eb997c2ee534c99bec4b5bb359c2a1f9edadf043e254a71e11378/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:96586ed537a5fb386a162c4f9f7d8e6f76e07b38a990d50c73f11131e00ff040", size = 381783 }, + { url = "https://files.pythonhosted.org/packages/f0/8d/5897b700360bc00911b70ae5ef1134ee7abf5baa81a92a4be005917d3dfd/ormsgpack-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e70387112fb3870e4844de090014212cdcf1342f5022047aecca01ec7de05d7a", size = 112943 }, + { url = "https://files.pythonhosted.org/packages/5b/44/1e73649f79bb96d6cf9e5bcbac68b6216d238bba80af351c4c0cbcf7ee15/ormsgpack-1.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:d71290a23de5d4829610c42665d816c661ecad8979883f3f06b2e3ab9639962e", size = 106688 }, + { url = "https://files.pythonhosted.org/packages/2e/e8/35f11ce9313111488b26b3035e4cbe55caa27909c0b6c8b5b5cd59f9661e/ormsgpack-1.12.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:766f2f3b512d85cd375b26a8b1329b99843560b50b93d3880718e634ad4a5de5", size = 369574 }, + { url = "https://files.pythonhosted.org/packages/61/b0/77461587f412d4e598d3687bafe23455ed0f26269f44be20252eddaa624e/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84b285b1f3f185aad7da45641b873b30acfd13084cf829cf668c4c6480a81583", size = 195893 }, + { url = "https://files.pythonhosted.org/packages/c6/67/e197ceb04c3b550589e5407fc9fdae10f4e2e2eba5fdac921a269e02e974/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e23604fc79fe110292cb365f4c8232e64e63a34f470538be320feae3921f271b", size = 206503 }, + { url = "https://files.pythonhosted.org/packages/0b/b1/7fa8ba82a25cef678983c7976f85edeef5014f5c26495f338258e6a3cf1c/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc32b156c113a0fae2975051417d8d9a7a5247c34b2d7239410c46b75ce9348a", size = 208257 }, + { url = "https://files.pythonhosted.org/packages/ce/b1/759e999390000d2589e6d0797f7265e6ec28378547075d28d3736248ab63/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:94ac500dd10c20fa8b8a23bc55606250bfe711bf9716828d9f3d44dfd1f25668", size = 377852 }, + { url = "https://files.pythonhosted.org/packages/51/e7/0af737c94272494d9d84a3c29cc42c973ef7fd2342917020906596db863c/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c5201ff7ec24f721f813a182885a17064cffdbe46b2412685a52e6374a872c8f", size = 471456 }, + { url = "https://files.pythonhosted.org/packages/f4/ba/c81f0aa4f19fbf457213395945b672e6fde3ce777e3587456e7f0fca2147/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a9740bb3839c9368aacae1cbcfc474ee6976458f41cc135372b7255d5206c953", size = 381813 }, + { url = "https://files.pythonhosted.org/packages/ce/15/429c72d64323503fd42cc4ca8398930ded8aa8b3470df8a86b3bbae7a35c/ormsgpack-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ed37f29772432048b58174e920a1d4c4cde0404a5d448d3d8bbcc95d86a6918", size = 112949 }, + { url = "https://files.pythonhosted.org/packages/55/b9/e72c451a40f8c57bfc229e0b8e536ecea7203c8f0a839676df2ffb605c62/ormsgpack-1.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:b03994bbec5d6d42e03d6604e327863f885bde67aa61e06107ce1fa5bdd3e71d", size = 106689 }, + { url = "https://files.pythonhosted.org/packages/13/16/13eab1a75da531b359105fdee90dda0b6bd1ca0a09880250cf91d8bdfdea/ormsgpack-1.12.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0f3981ba3cba80656012090337e548e597799e14b41e3d0b595ab5ab05a23d7f", size = 369620 }, + { url = "https://files.pythonhosted.org/packages/a0/c1/cbcc38b7af4ce58d8893e56d3595c0c8dcd117093bf048f889cf351bdba0/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:901f6f55184d6776dbd5183cbce14caf05bf7f467eef52faf9b094686980bf71", size = 195925 }, + { url = "https://files.pythonhosted.org/packages/5c/59/4fa4dc0681490e12b75333440a1c0fd9741b0ebff272b1db4a29d35c2021/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e13b15412571422b711b40f45e3fe6d993ea3314b5e97d1a853fe99226c5effc", size = 206594 }, + { url = "https://files.pythonhosted.org/packages/39/67/249770896bc32bb91b22c30256961f935d0915cbcf6e289a7fc961d9b14c/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91fa8a452553a62e5fb3fbab471e7faf7b3bec3c87a2f355ebf3d7aab290fe4f", size = 208307 }, + { url = "https://files.pythonhosted.org/packages/07/0a/e041a248cd72f2f4c07e155913e0a3ede4c86cf21a40ae6cd79f135f2847/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74ec101f69624695eec4ce7c953192d97748254abe78fb01b591f06d529e1952", size = 377844 }, + { url = "https://files.pythonhosted.org/packages/d8/71/6f7773e4ffda73a358ce4bba69b3e8bee9d40a7a06315e4c1cd7a3ea9d02/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9bbf7896580848326c1f9bd7531f264e561f98db7e08e15aa75963d83832c717", size = 471572 }, + { url = "https://files.pythonhosted.org/packages/65/29/af6769a4289c07acc71e7bda1d64fb31800563147d73142686e185e82348/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7567917da613b8f8d591c1674e411fd3404bea41ef2b9a0e0a1e049c0f9406d7", size = 381842 }, + { url = "https://files.pythonhosted.org/packages/0b/dd/0a86195ee7a1a96c088aefc8504385e881cf56f4563ed81bafe21cbf1fb0/ormsgpack-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e418256c5d8622b8bc92861936f7c6a0131355e7bcad88a42102ae8227f8a1c", size = 113008 }, + { url = "https://files.pythonhosted.org/packages/4c/57/fafc79e32f3087f6f26f509d80b8167516326bfea38d30502627c01617e0/ormsgpack-1.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:433ace29aa02713554f714c62a4e4dcad0c9e32674ba4f66742c91a4c3b1b969", size = 106648 }, + { url = "https://files.pythonhosted.org/packages/b3/cf/5d58d9b132128d2fe5d586355dde76af386554abef00d608f66b913bff1f/ormsgpack-1.12.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e57164be4ca34b64e210ec515059193280ac84df4d6f31a6fcbfb2fc8436de55", size = 369803 }, + { url = "https://files.pythonhosted.org/packages/67/42/968a2da361eaff2e4cbb17c82c7599787babf16684110ad70409646cc1e4/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:904f96289deaa92fc6440b122edc27c5bdc28234edd63717f6d853d88c823a83", size = 195991 }, + { url = "https://files.pythonhosted.org/packages/03/f0/9696c6c6cf8ad35170f0be8d0ef3523cc258083535f6c8071cb8235ebb8b/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b291d086e524a1062d57d1b7b5a8bcaaf29caebf0212fec12fd86240bd33633", size = 208316 }, ] [[package]] name = "overrides" version = "7.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832 }, ] [[package]] name = "packaging" version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, ] [[package]] @@ -2871,82 +2863,82 @@ dependencies = [ { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, - { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, - { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, - { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, - { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, - { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, - { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790, upload-time = "2025-09-29T23:18:30.065Z" }, - { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831, upload-time = "2025-09-29T23:38:56.071Z" }, - { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267, upload-time = "2025-09-29T23:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/bf/c9/63f8d545568d9ab91476b1818b4741f521646cbdd151c6efebf40d6de6f7/pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", size = 12789281, upload-time = "2025-09-29T23:18:56.834Z" }, - { url = "https://files.pythonhosted.org/packages/f2/00/a5ac8c7a0e67fd1a6059e40aa08fa1c52cc00709077d2300e210c3ce0322/pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", size = 13240453, upload-time = "2025-09-29T23:19:09.247Z" }, - { url = "https://files.pythonhosted.org/packages/27/4d/5c23a5bc7bd209231618dd9e606ce076272c9bc4f12023a70e03a86b4067/pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", size = 13890361, upload-time = "2025-09-29T23:19:25.342Z" }, - { url = "https://files.pythonhosted.org/packages/8e/59/712db1d7040520de7a4965df15b774348980e6df45c129b8c64d0dbe74ef/pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", size = 11348702, upload-time = "2025-09-29T23:19:38.296Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, - { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, - { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, - { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, - { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, - { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, - { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, - { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, - { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, - { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, - { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, - { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, - { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, - { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, - { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, - { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, - { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, - { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, - { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, - { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, - { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, - { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, - { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, - { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, - { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, - { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, - { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, - { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, - { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763 }, + { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217 }, + { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791 }, + { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373 }, + { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444 }, + { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459 }, + { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086 }, + { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790 }, + { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831 }, + { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267 }, + { url = "https://files.pythonhosted.org/packages/bf/c9/63f8d545568d9ab91476b1818b4741f521646cbdd151c6efebf40d6de6f7/pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", size = 12789281 }, + { url = "https://files.pythonhosted.org/packages/f2/00/a5ac8c7a0e67fd1a6059e40aa08fa1c52cc00709077d2300e210c3ce0322/pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", size = 13240453 }, + { url = "https://files.pythonhosted.org/packages/27/4d/5c23a5bc7bd209231618dd9e606ce076272c9bc4f12023a70e03a86b4067/pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", size = 13890361 }, + { url = "https://files.pythonhosted.org/packages/8e/59/712db1d7040520de7a4965df15b774348980e6df45c129b8c64d0dbe74ef/pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", size = 11348702 }, + { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846 }, + { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618 }, + { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212 }, + { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693 }, + { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002 }, + { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971 }, + { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722 }, + { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671 }, + { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807 }, + { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872 }, + { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371 }, + { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333 }, + { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120 }, + { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991 }, + { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227 }, + { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056 }, + { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189 }, + { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912 }, + { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160 }, + { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233 }, + { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635 }, + { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079 }, + { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049 }, + { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638 }, + { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834 }, + { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925 }, + { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071 }, + { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504 }, + { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702 }, + { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535 }, + { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582 }, + { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963 }, + { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175 }, ] [[package]] name = "pandocfilters" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, ] [[package]] name = "parso" version = "0.8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205 } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668 }, ] [[package]] name = "pathspec" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, ] [[package]] @@ -2956,143 +2948,143 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, ] [[package]] name = "pillow" version = "12.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/08/26e68b6b5da219c2a2cb7b563af008b53bb8e6b6fcb3fa40715fcdb2523a/pillow-12.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b", size = 5289809, upload-time = "2025-10-15T18:21:27.791Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e9/4e58fb097fb74c7b4758a680aacd558810a417d1edaa7000142976ef9d2f/pillow-12.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1", size = 4650606, upload-time = "2025-10-15T18:21:29.823Z" }, - { url = "https://files.pythonhosted.org/packages/4b/e0/1fa492aa9f77b3bc6d471c468e62bfea1823056bf7e5e4f1914d7ab2565e/pillow-12.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363", size = 6221023, upload-time = "2025-10-15T18:21:31.415Z" }, - { url = "https://files.pythonhosted.org/packages/c1/09/4de7cd03e33734ccd0c876f0251401f1314e819cbfd89a0fcb6e77927cc6/pillow-12.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca", size = 8024937, upload-time = "2025-10-15T18:21:33.453Z" }, - { url = "https://files.pythonhosted.org/packages/2e/69/0688e7c1390666592876d9d474f5e135abb4acb39dcb583c4dc5490f1aff/pillow-12.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e", size = 6334139, upload-time = "2025-10-15T18:21:35.395Z" }, - { url = "https://files.pythonhosted.org/packages/ed/1c/880921e98f525b9b44ce747ad1ea8f73fd7e992bafe3ca5e5644bf433dea/pillow-12.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782", size = 7026074, upload-time = "2025-10-15T18:21:37.219Z" }, - { url = "https://files.pythonhosted.org/packages/28/03/96f718331b19b355610ef4ebdbbde3557c726513030665071fd025745671/pillow-12.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10", size = 6448852, upload-time = "2025-10-15T18:21:39.168Z" }, - { url = "https://files.pythonhosted.org/packages/3a/a0/6a193b3f0cc9437b122978d2c5cbce59510ccf9a5b48825096ed7472da2f/pillow-12.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa", size = 7117058, upload-time = "2025-10-15T18:21:40.997Z" }, - { url = "https://files.pythonhosted.org/packages/a7/c4/043192375eaa4463254e8e61f0e2ec9a846b983929a8d0a7122e0a6d6fff/pillow-12.0.0-cp310-cp310-win32.whl", hash = "sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275", size = 6295431, upload-time = "2025-10-15T18:21:42.518Z" }, - { url = "https://files.pythonhosted.org/packages/92/c6/c2f2fc7e56301c21827e689bb8b0b465f1b52878b57471a070678c0c33cd/pillow-12.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d", size = 7000412, upload-time = "2025-10-15T18:21:44.404Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d2/5f675067ba82da7a1c238a73b32e3fd78d67f9d9f80fbadd33a40b9c0481/pillow-12.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7", size = 2435903, upload-time = "2025-10-15T18:21:46.29Z" }, - { url = "https://files.pythonhosted.org/packages/0e/5a/a2f6773b64edb921a756eb0729068acad9fc5208a53f4a349396e9436721/pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc", size = 5289798, upload-time = "2025-10-15T18:21:47.763Z" }, - { url = "https://files.pythonhosted.org/packages/2e/05/069b1f8a2e4b5a37493da6c5868531c3f77b85e716ad7a590ef87d58730d/pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257", size = 4650589, upload-time = "2025-10-15T18:21:49.515Z" }, - { url = "https://files.pythonhosted.org/packages/61/e3/2c820d6e9a36432503ead175ae294f96861b07600a7156154a086ba7111a/pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642", size = 6230472, upload-time = "2025-10-15T18:21:51.052Z" }, - { url = "https://files.pythonhosted.org/packages/4f/89/63427f51c64209c5e23d4d52071c8d0f21024d3a8a487737caaf614a5795/pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3", size = 8033887, upload-time = "2025-10-15T18:21:52.604Z" }, - { url = "https://files.pythonhosted.org/packages/f6/1b/c9711318d4901093c15840f268ad649459cd81984c9ec9887756cca049a5/pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c", size = 6343964, upload-time = "2025-10-15T18:21:54.619Z" }, - { url = "https://files.pythonhosted.org/packages/41/1e/db9470f2d030b4995083044cd8738cdd1bf773106819f6d8ba12597d5352/pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227", size = 7034756, upload-time = "2025-10-15T18:21:56.151Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b0/6177a8bdd5ee4ed87cba2de5a3cc1db55ffbbec6176784ce5bb75aa96798/pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b", size = 6458075, upload-time = "2025-10-15T18:21:57.759Z" }, - { url = "https://files.pythonhosted.org/packages/bc/5e/61537aa6fa977922c6a03253a0e727e6e4a72381a80d63ad8eec350684f2/pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e", size = 7125955, upload-time = "2025-10-15T18:21:59.372Z" }, - { url = "https://files.pythonhosted.org/packages/1f/3d/d5033539344ee3cbd9a4d69e12e63ca3a44a739eb2d4c8da350a3d38edd7/pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739", size = 6298440, upload-time = "2025-10-15T18:22:00.982Z" }, - { url = "https://files.pythonhosted.org/packages/4d/42/aaca386de5cc8bd8a0254516957c1f265e3521c91515b16e286c662854c4/pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e", size = 6999256, upload-time = "2025-10-15T18:22:02.617Z" }, - { url = "https://files.pythonhosted.org/packages/ba/f1/9197c9c2d5708b785f631a6dfbfa8eb3fb9672837cb92ae9af812c13b4ed/pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d", size = 2436025, upload-time = "2025-10-15T18:22:04.598Z" }, - { url = "https://files.pythonhosted.org/packages/2c/90/4fcce2c22caf044e660a198d740e7fbc14395619e3cb1abad12192c0826c/pillow-12.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371", size = 5249377, upload-time = "2025-10-15T18:22:05.993Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e0/ed960067543d080691d47d6938ebccbf3976a931c9567ab2fbfab983a5dd/pillow-12.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082", size = 4650343, upload-time = "2025-10-15T18:22:07.718Z" }, - { url = "https://files.pythonhosted.org/packages/e7/a1/f81fdeddcb99c044bf7d6faa47e12850f13cee0849537a7d27eeab5534d4/pillow-12.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f", size = 6232981, upload-time = "2025-10-15T18:22:09.287Z" }, - { url = "https://files.pythonhosted.org/packages/88/e1/9098d3ce341a8750b55b0e00c03f1630d6178f38ac191c81c97a3b047b44/pillow-12.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d", size = 8041399, upload-time = "2025-10-15T18:22:10.872Z" }, - { url = "https://files.pythonhosted.org/packages/a7/62/a22e8d3b602ae8cc01446d0c57a54e982737f44b6f2e1e019a925143771d/pillow-12.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953", size = 6347740, upload-time = "2025-10-15T18:22:12.769Z" }, - { url = "https://files.pythonhosted.org/packages/4f/87/424511bdcd02c8d7acf9f65caa09f291a519b16bd83c3fb3374b3d4ae951/pillow-12.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8", size = 7040201, upload-time = "2025-10-15T18:22:14.813Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4d/435c8ac688c54d11755aedfdd9f29c9eeddf68d150fe42d1d3dbd2365149/pillow-12.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79", size = 6462334, upload-time = "2025-10-15T18:22:16.375Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f2/ad34167a8059a59b8ad10bc5c72d4d9b35acc6b7c0877af8ac885b5f2044/pillow-12.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba", size = 7134162, upload-time = "2025-10-15T18:22:17.996Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b1/a7391df6adacf0a5c2cf6ac1cf1fcc1369e7d439d28f637a847f8803beb3/pillow-12.0.0-cp312-cp312-win32.whl", hash = "sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0", size = 6298769, upload-time = "2025-10-15T18:22:19.923Z" }, - { url = "https://files.pythonhosted.org/packages/a2/0b/d87733741526541c909bbf159e338dcace4f982daac6e5a8d6be225ca32d/pillow-12.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a", size = 7001107, upload-time = "2025-10-15T18:22:21.644Z" }, - { url = "https://files.pythonhosted.org/packages/bc/96/aaa61ce33cc98421fb6088af2a03be4157b1e7e0e87087c888e2370a7f45/pillow-12.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad", size = 2436012, upload-time = "2025-10-15T18:22:23.621Z" }, - { url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493, upload-time = "2025-10-15T18:22:25.758Z" }, - { url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461, upload-time = "2025-10-15T18:22:27.286Z" }, - { url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912, upload-time = "2025-10-15T18:22:28.751Z" }, - { url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132, upload-time = "2025-10-15T18:22:30.641Z" }, - { url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099, upload-time = "2025-10-15T18:22:32.73Z" }, - { url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808, upload-time = "2025-10-15T18:22:34.337Z" }, - { url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804, upload-time = "2025-10-15T18:22:36.402Z" }, - { url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553, upload-time = "2025-10-15T18:22:38.066Z" }, - { url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729, upload-time = "2025-10-15T18:22:39.769Z" }, - { url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789, upload-time = "2025-10-15T18:22:41.437Z" }, - { url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917, upload-time = "2025-10-15T18:22:43.152Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391, upload-time = "2025-10-15T18:22:44.753Z" }, - { url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477, upload-time = "2025-10-15T18:22:46.838Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918, upload-time = "2025-10-15T18:22:48.399Z" }, - { url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406, upload-time = "2025-10-15T18:22:49.905Z" }, - { url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218, upload-time = "2025-10-15T18:22:51.587Z" }, - { url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564, upload-time = "2025-10-15T18:22:53.215Z" }, - { url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260, upload-time = "2025-10-15T18:22:54.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248, upload-time = "2025-10-15T18:22:56.605Z" }, - { url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043, upload-time = "2025-10-15T18:22:58.53Z" }, - { url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915, upload-time = "2025-10-15T18:23:00.582Z" }, - { url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998, upload-time = "2025-10-15T18:23:02.627Z" }, - { url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201, upload-time = "2025-10-15T18:23:04.709Z" }, - { url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165, upload-time = "2025-10-15T18:23:06.46Z" }, - { url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834, upload-time = "2025-10-15T18:23:08.194Z" }, - { url = "https://files.pythonhosted.org/packages/54/2a/9a8c6ba2c2c07b71bec92cf63e03370ca5e5f5c5b119b742bcc0cde3f9c5/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9", size = 4045531, upload-time = "2025-10-15T18:23:10.121Z" }, - { url = "https://files.pythonhosted.org/packages/84/54/836fdbf1bfb3d66a59f0189ff0b9f5f666cee09c6188309300df04ad71fa/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2", size = 4120554, upload-time = "2025-10-15T18:23:12.14Z" }, - { url = "https://files.pythonhosted.org/packages/0d/cd/16aec9f0da4793e98e6b54778a5fbce4f375c6646fe662e80600b8797379/pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a", size = 3576812, upload-time = "2025-10-15T18:23:13.962Z" }, - { url = "https://files.pythonhosted.org/packages/f6/b7/13957fda356dc46339298b351cae0d327704986337c3c69bb54628c88155/pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b", size = 5252689, upload-time = "2025-10-15T18:23:15.562Z" }, - { url = "https://files.pythonhosted.org/packages/fc/f5/eae31a306341d8f331f43edb2e9122c7661b975433de5e447939ae61c5da/pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad", size = 4650186, upload-time = "2025-10-15T18:23:17.379Z" }, - { url = "https://files.pythonhosted.org/packages/86/62/2a88339aa40c4c77e79108facbd307d6091e2c0eb5b8d3cf4977cfca2fe6/pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01", size = 6230308, upload-time = "2025-10-15T18:23:18.971Z" }, - { url = "https://files.pythonhosted.org/packages/c7/33/5425a8992bcb32d1cb9fa3dd39a89e613d09a22f2c8083b7bf43c455f760/pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c", size = 8039222, upload-time = "2025-10-15T18:23:20.909Z" }, - { url = "https://files.pythonhosted.org/packages/d8/61/3f5d3b35c5728f37953d3eec5b5f3e77111949523bd2dd7f31a851e50690/pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e", size = 6346657, upload-time = "2025-10-15T18:23:23.077Z" }, - { url = "https://files.pythonhosted.org/packages/3a/be/ee90a3d79271227e0f0a33c453531efd6ed14b2e708596ba5dd9be948da3/pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e", size = 7038482, upload-time = "2025-10-15T18:23:25.005Z" }, - { url = "https://files.pythonhosted.org/packages/44/34/a16b6a4d1ad727de390e9bd9f19f5f669e079e5826ec0f329010ddea492f/pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9", size = 6461416, upload-time = "2025-10-15T18:23:27.009Z" }, - { url = "https://files.pythonhosted.org/packages/b6/39/1aa5850d2ade7d7ba9f54e4e4c17077244ff7a2d9e25998c38a29749eb3f/pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab", size = 7131584, upload-time = "2025-10-15T18:23:29.752Z" }, - { url = "https://files.pythonhosted.org/packages/bf/db/4fae862f8fad0167073a7733973bfa955f47e2cac3dc3e3e6257d10fab4a/pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b", size = 6400621, upload-time = "2025-10-15T18:23:32.06Z" }, - { url = "https://files.pythonhosted.org/packages/2b/24/b350c31543fb0107ab2599464d7e28e6f856027aadda995022e695313d94/pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b", size = 7142916, upload-time = "2025-10-15T18:23:34.71Z" }, - { url = "https://files.pythonhosted.org/packages/0f/9b/0ba5a6fd9351793996ef7487c4fdbde8d3f5f75dbedc093bb598648fddf0/pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0", size = 2523836, upload-time = "2025-10-15T18:23:36.967Z" }, - { url = "https://files.pythonhosted.org/packages/f5/7a/ceee0840aebc579af529b523d530840338ecf63992395842e54edc805987/pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6", size = 5255092, upload-time = "2025-10-15T18:23:38.573Z" }, - { url = "https://files.pythonhosted.org/packages/44/76/20776057b4bfd1aef4eeca992ebde0f53a4dce874f3ae693d0ec90a4f79b/pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6", size = 4653158, upload-time = "2025-10-15T18:23:40.238Z" }, - { url = "https://files.pythonhosted.org/packages/82/3f/d9ff92ace07be8836b4e7e87e6a4c7a8318d47c2f1463ffcf121fc57d9cb/pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1", size = 6267882, upload-time = "2025-10-15T18:23:42.434Z" }, - { url = "https://files.pythonhosted.org/packages/9f/7a/4f7ff87f00d3ad33ba21af78bfcd2f032107710baf8280e3722ceec28cda/pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e", size = 8071001, upload-time = "2025-10-15T18:23:44.29Z" }, - { url = "https://files.pythonhosted.org/packages/75/87/fcea108944a52dad8cca0715ae6247e271eb80459364a98518f1e4f480c1/pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca", size = 6380146, upload-time = "2025-10-15T18:23:46.065Z" }, - { url = "https://files.pythonhosted.org/packages/91/52/0d31b5e571ef5fd111d2978b84603fce26aba1b6092f28e941cb46570745/pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925", size = 7067344, upload-time = "2025-10-15T18:23:47.898Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f4/2dd3d721f875f928d48e83bb30a434dee75a2531bca839bb996bb0aa5a91/pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8", size = 6491864, upload-time = "2025-10-15T18:23:49.607Z" }, - { url = "https://files.pythonhosted.org/packages/30/4b/667dfcf3d61fc309ba5a15b141845cece5915e39b99c1ceab0f34bf1d124/pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4", size = 7158911, upload-time = "2025-10-15T18:23:51.351Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045, upload-time = "2025-10-15T18:23:53.177Z" }, - { url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282, upload-time = "2025-10-15T18:23:55.316Z" }, - { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" }, - { url = "https://files.pythonhosted.org/packages/1d/b3/582327e6c9f86d037b63beebe981425d6811104cb443e8193824ef1a2f27/pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8", size = 5215068, upload-time = "2025-10-15T18:23:59.594Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d6/67748211d119f3b6540baf90f92fae73ae51d5217b171b0e8b5f7e5d558f/pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a", size = 4614994, upload-time = "2025-10-15T18:24:01.669Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e1/f8281e5d844c41872b273b9f2c34a4bf64ca08905668c8ae730eedc7c9fa/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197", size = 5246639, upload-time = "2025-10-15T18:24:03.403Z" }, - { url = "https://files.pythonhosted.org/packages/94/5a/0d8ab8ffe8a102ff5df60d0de5af309015163bf710c7bb3e8311dd3b3ad0/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c", size = 6986839, upload-time = "2025-10-15T18:24:05.344Z" }, - { url = "https://files.pythonhosted.org/packages/20/2e/3434380e8110b76cd9eb00a363c484b050f949b4bbe84ba770bb8508a02c/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e", size = 5313505, upload-time = "2025-10-15T18:24:07.137Z" }, - { url = "https://files.pythonhosted.org/packages/57/ca/5a9d38900d9d74785141d6580950fe705de68af735ff6e727cb911b64740/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76", size = 5963654, upload-time = "2025-10-15T18:24:09.579Z" }, - { url = "https://files.pythonhosted.org/packages/95/7e/f896623c3c635a90537ac093c6a618ebe1a90d87206e42309cb5d98a1b9e/pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5", size = 6997850, upload-time = "2025-10-15T18:24:11.495Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/08/26e68b6b5da219c2a2cb7b563af008b53bb8e6b6fcb3fa40715fcdb2523a/pillow-12.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b", size = 5289809 }, + { url = "https://files.pythonhosted.org/packages/cb/e9/4e58fb097fb74c7b4758a680aacd558810a417d1edaa7000142976ef9d2f/pillow-12.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1", size = 4650606 }, + { url = "https://files.pythonhosted.org/packages/4b/e0/1fa492aa9f77b3bc6d471c468e62bfea1823056bf7e5e4f1914d7ab2565e/pillow-12.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363", size = 6221023 }, + { url = "https://files.pythonhosted.org/packages/c1/09/4de7cd03e33734ccd0c876f0251401f1314e819cbfd89a0fcb6e77927cc6/pillow-12.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca", size = 8024937 }, + { url = "https://files.pythonhosted.org/packages/2e/69/0688e7c1390666592876d9d474f5e135abb4acb39dcb583c4dc5490f1aff/pillow-12.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e", size = 6334139 }, + { url = "https://files.pythonhosted.org/packages/ed/1c/880921e98f525b9b44ce747ad1ea8f73fd7e992bafe3ca5e5644bf433dea/pillow-12.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782", size = 7026074 }, + { url = "https://files.pythonhosted.org/packages/28/03/96f718331b19b355610ef4ebdbbde3557c726513030665071fd025745671/pillow-12.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10", size = 6448852 }, + { url = "https://files.pythonhosted.org/packages/3a/a0/6a193b3f0cc9437b122978d2c5cbce59510ccf9a5b48825096ed7472da2f/pillow-12.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa", size = 7117058 }, + { url = "https://files.pythonhosted.org/packages/a7/c4/043192375eaa4463254e8e61f0e2ec9a846b983929a8d0a7122e0a6d6fff/pillow-12.0.0-cp310-cp310-win32.whl", hash = "sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275", size = 6295431 }, + { url = "https://files.pythonhosted.org/packages/92/c6/c2f2fc7e56301c21827e689bb8b0b465f1b52878b57471a070678c0c33cd/pillow-12.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d", size = 7000412 }, + { url = "https://files.pythonhosted.org/packages/b2/d2/5f675067ba82da7a1c238a73b32e3fd78d67f9d9f80fbadd33a40b9c0481/pillow-12.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7", size = 2435903 }, + { url = "https://files.pythonhosted.org/packages/0e/5a/a2f6773b64edb921a756eb0729068acad9fc5208a53f4a349396e9436721/pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc", size = 5289798 }, + { url = "https://files.pythonhosted.org/packages/2e/05/069b1f8a2e4b5a37493da6c5868531c3f77b85e716ad7a590ef87d58730d/pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257", size = 4650589 }, + { url = "https://files.pythonhosted.org/packages/61/e3/2c820d6e9a36432503ead175ae294f96861b07600a7156154a086ba7111a/pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642", size = 6230472 }, + { url = "https://files.pythonhosted.org/packages/4f/89/63427f51c64209c5e23d4d52071c8d0f21024d3a8a487737caaf614a5795/pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3", size = 8033887 }, + { url = "https://files.pythonhosted.org/packages/f6/1b/c9711318d4901093c15840f268ad649459cd81984c9ec9887756cca049a5/pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c", size = 6343964 }, + { url = "https://files.pythonhosted.org/packages/41/1e/db9470f2d030b4995083044cd8738cdd1bf773106819f6d8ba12597d5352/pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227", size = 7034756 }, + { url = "https://files.pythonhosted.org/packages/cc/b0/6177a8bdd5ee4ed87cba2de5a3cc1db55ffbbec6176784ce5bb75aa96798/pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b", size = 6458075 }, + { url = "https://files.pythonhosted.org/packages/bc/5e/61537aa6fa977922c6a03253a0e727e6e4a72381a80d63ad8eec350684f2/pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e", size = 7125955 }, + { url = "https://files.pythonhosted.org/packages/1f/3d/d5033539344ee3cbd9a4d69e12e63ca3a44a739eb2d4c8da350a3d38edd7/pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739", size = 6298440 }, + { url = "https://files.pythonhosted.org/packages/4d/42/aaca386de5cc8bd8a0254516957c1f265e3521c91515b16e286c662854c4/pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e", size = 6999256 }, + { url = "https://files.pythonhosted.org/packages/ba/f1/9197c9c2d5708b785f631a6dfbfa8eb3fb9672837cb92ae9af812c13b4ed/pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d", size = 2436025 }, + { url = "https://files.pythonhosted.org/packages/2c/90/4fcce2c22caf044e660a198d740e7fbc14395619e3cb1abad12192c0826c/pillow-12.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371", size = 5249377 }, + { url = "https://files.pythonhosted.org/packages/fd/e0/ed960067543d080691d47d6938ebccbf3976a931c9567ab2fbfab983a5dd/pillow-12.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082", size = 4650343 }, + { url = "https://files.pythonhosted.org/packages/e7/a1/f81fdeddcb99c044bf7d6faa47e12850f13cee0849537a7d27eeab5534d4/pillow-12.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f", size = 6232981 }, + { url = "https://files.pythonhosted.org/packages/88/e1/9098d3ce341a8750b55b0e00c03f1630d6178f38ac191c81c97a3b047b44/pillow-12.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d", size = 8041399 }, + { url = "https://files.pythonhosted.org/packages/a7/62/a22e8d3b602ae8cc01446d0c57a54e982737f44b6f2e1e019a925143771d/pillow-12.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953", size = 6347740 }, + { url = "https://files.pythonhosted.org/packages/4f/87/424511bdcd02c8d7acf9f65caa09f291a519b16bd83c3fb3374b3d4ae951/pillow-12.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8", size = 7040201 }, + { url = "https://files.pythonhosted.org/packages/dc/4d/435c8ac688c54d11755aedfdd9f29c9eeddf68d150fe42d1d3dbd2365149/pillow-12.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79", size = 6462334 }, + { url = "https://files.pythonhosted.org/packages/2b/f2/ad34167a8059a59b8ad10bc5c72d4d9b35acc6b7c0877af8ac885b5f2044/pillow-12.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba", size = 7134162 }, + { url = "https://files.pythonhosted.org/packages/0c/b1/a7391df6adacf0a5c2cf6ac1cf1fcc1369e7d439d28f637a847f8803beb3/pillow-12.0.0-cp312-cp312-win32.whl", hash = "sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0", size = 6298769 }, + { url = "https://files.pythonhosted.org/packages/a2/0b/d87733741526541c909bbf159e338dcace4f982daac6e5a8d6be225ca32d/pillow-12.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a", size = 7001107 }, + { url = "https://files.pythonhosted.org/packages/bc/96/aaa61ce33cc98421fb6088af2a03be4157b1e7e0e87087c888e2370a7f45/pillow-12.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad", size = 2436012 }, + { url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493 }, + { url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461 }, + { url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912 }, + { url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132 }, + { url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099 }, + { url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808 }, + { url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804 }, + { url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553 }, + { url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729 }, + { url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789 }, + { url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917 }, + { url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391 }, + { url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477 }, + { url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918 }, + { url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406 }, + { url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218 }, + { url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564 }, + { url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260 }, + { url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248 }, + { url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043 }, + { url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915 }, + { url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998 }, + { url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201 }, + { url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165 }, + { url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834 }, + { url = "https://files.pythonhosted.org/packages/54/2a/9a8c6ba2c2c07b71bec92cf63e03370ca5e5f5c5b119b742bcc0cde3f9c5/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9", size = 4045531 }, + { url = "https://files.pythonhosted.org/packages/84/54/836fdbf1bfb3d66a59f0189ff0b9f5f666cee09c6188309300df04ad71fa/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2", size = 4120554 }, + { url = "https://files.pythonhosted.org/packages/0d/cd/16aec9f0da4793e98e6b54778a5fbce4f375c6646fe662e80600b8797379/pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a", size = 3576812 }, + { url = "https://files.pythonhosted.org/packages/f6/b7/13957fda356dc46339298b351cae0d327704986337c3c69bb54628c88155/pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b", size = 5252689 }, + { url = "https://files.pythonhosted.org/packages/fc/f5/eae31a306341d8f331f43edb2e9122c7661b975433de5e447939ae61c5da/pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad", size = 4650186 }, + { url = "https://files.pythonhosted.org/packages/86/62/2a88339aa40c4c77e79108facbd307d6091e2c0eb5b8d3cf4977cfca2fe6/pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01", size = 6230308 }, + { url = "https://files.pythonhosted.org/packages/c7/33/5425a8992bcb32d1cb9fa3dd39a89e613d09a22f2c8083b7bf43c455f760/pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c", size = 8039222 }, + { url = "https://files.pythonhosted.org/packages/d8/61/3f5d3b35c5728f37953d3eec5b5f3e77111949523bd2dd7f31a851e50690/pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e", size = 6346657 }, + { url = "https://files.pythonhosted.org/packages/3a/be/ee90a3d79271227e0f0a33c453531efd6ed14b2e708596ba5dd9be948da3/pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e", size = 7038482 }, + { url = "https://files.pythonhosted.org/packages/44/34/a16b6a4d1ad727de390e9bd9f19f5f669e079e5826ec0f329010ddea492f/pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9", size = 6461416 }, + { url = "https://files.pythonhosted.org/packages/b6/39/1aa5850d2ade7d7ba9f54e4e4c17077244ff7a2d9e25998c38a29749eb3f/pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab", size = 7131584 }, + { url = "https://files.pythonhosted.org/packages/bf/db/4fae862f8fad0167073a7733973bfa955f47e2cac3dc3e3e6257d10fab4a/pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b", size = 6400621 }, + { url = "https://files.pythonhosted.org/packages/2b/24/b350c31543fb0107ab2599464d7e28e6f856027aadda995022e695313d94/pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b", size = 7142916 }, + { url = "https://files.pythonhosted.org/packages/0f/9b/0ba5a6fd9351793996ef7487c4fdbde8d3f5f75dbedc093bb598648fddf0/pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0", size = 2523836 }, + { url = "https://files.pythonhosted.org/packages/f5/7a/ceee0840aebc579af529b523d530840338ecf63992395842e54edc805987/pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6", size = 5255092 }, + { url = "https://files.pythonhosted.org/packages/44/76/20776057b4bfd1aef4eeca992ebde0f53a4dce874f3ae693d0ec90a4f79b/pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6", size = 4653158 }, + { url = "https://files.pythonhosted.org/packages/82/3f/d9ff92ace07be8836b4e7e87e6a4c7a8318d47c2f1463ffcf121fc57d9cb/pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1", size = 6267882 }, + { url = "https://files.pythonhosted.org/packages/9f/7a/4f7ff87f00d3ad33ba21af78bfcd2f032107710baf8280e3722ceec28cda/pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e", size = 8071001 }, + { url = "https://files.pythonhosted.org/packages/75/87/fcea108944a52dad8cca0715ae6247e271eb80459364a98518f1e4f480c1/pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca", size = 6380146 }, + { url = "https://files.pythonhosted.org/packages/91/52/0d31b5e571ef5fd111d2978b84603fce26aba1b6092f28e941cb46570745/pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925", size = 7067344 }, + { url = "https://files.pythonhosted.org/packages/7b/f4/2dd3d721f875f928d48e83bb30a434dee75a2531bca839bb996bb0aa5a91/pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8", size = 6491864 }, + { url = "https://files.pythonhosted.org/packages/30/4b/667dfcf3d61fc309ba5a15b141845cece5915e39b99c1ceab0f34bf1d124/pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4", size = 7158911 }, + { url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045 }, + { url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282 }, + { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630 }, + { url = "https://files.pythonhosted.org/packages/1d/b3/582327e6c9f86d037b63beebe981425d6811104cb443e8193824ef1a2f27/pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8", size = 5215068 }, + { url = "https://files.pythonhosted.org/packages/fd/d6/67748211d119f3b6540baf90f92fae73ae51d5217b171b0e8b5f7e5d558f/pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a", size = 4614994 }, + { url = "https://files.pythonhosted.org/packages/2d/e1/f8281e5d844c41872b273b9f2c34a4bf64ca08905668c8ae730eedc7c9fa/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197", size = 5246639 }, + { url = "https://files.pythonhosted.org/packages/94/5a/0d8ab8ffe8a102ff5df60d0de5af309015163bf710c7bb3e8311dd3b3ad0/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c", size = 6986839 }, + { url = "https://files.pythonhosted.org/packages/20/2e/3434380e8110b76cd9eb00a363c484b050f949b4bbe84ba770bb8508a02c/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e", size = 5313505 }, + { url = "https://files.pythonhosted.org/packages/57/ca/5a9d38900d9d74785141d6580950fe705de68af735ff6e727cb911b64740/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76", size = 5963654 }, + { url = "https://files.pythonhosted.org/packages/95/7e/f896623c3c635a90537ac093c6a618ebe1a90d87206e42309cb5d98a1b9e/pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5", size = 6997850 }, ] [[package]] name = "platformdirs" version = "4.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651 }, ] [[package]] name = "pluggy" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, ] [[package]] name = "ply" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130, upload-time = "2018-02-15T19:01:31.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567, upload-time = "2018-02-15T19:01:27.172Z" }, + { url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567 }, ] [[package]] name = "prometheus-client" version = "0.23.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481, upload-time = "2025-09-18T20:47:25.043Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145, upload-time = "2025-09-18T20:47:23.875Z" }, + { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145 }, ] [[package]] @@ -3102,176 +3094,176 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, ] [[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/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, - { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, - { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, - { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, - { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, - { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, - { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, - { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, - { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, - { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, - { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, - { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, - { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, - { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, - { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, - { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, - { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, - { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, - { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, - { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, - { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, - { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, - { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, - { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534 }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526 }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263 }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012 }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491 }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319 }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856 }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241 }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552 }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113 }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778 }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047 }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093 }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638 }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229 }, + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208 }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777 }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647 }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929 }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778 }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144 }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030 }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252 }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064 }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429 }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727 }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097 }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084 }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637 }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064 }, + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061 }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037 }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324 }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505 }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242 }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474 }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575 }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736 }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019 }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376 }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988 }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615 }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066 }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655 }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586 }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790 }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396 }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897 }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140 }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257 }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546 }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259 }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428 }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, ] [[package]] name = "psutil" version = "7.1.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/88/bdd0a41e5857d5d703287598cbf08dad90aed56774ea52ae071bae9071b6/psutil-7.1.3.tar.gz", hash = "sha256:6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74", size = 489059, upload-time = "2025-11-02T12:25:54.619Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/93/0c49e776b8734fef56ec9c5c57f923922f2cf0497d62e0f419465f28f3d0/psutil-7.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0005da714eee687b4b8decd3d6cc7c6db36215c9e74e5ad2264b90c3df7d92dc", size = 239751, upload-time = "2025-11-02T12:25:58.161Z" }, - { url = "https://files.pythonhosted.org/packages/6f/8d/b31e39c769e70780f007969815195a55c81a63efebdd4dbe9e7a113adb2f/psutil-7.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19644c85dcb987e35eeeaefdc3915d059dac7bd1167cdcdbf27e0ce2df0c08c0", size = 240368, upload-time = "2025-11-02T12:26:00.491Z" }, - { url = "https://files.pythonhosted.org/packages/62/61/23fd4acc3c9eebbf6b6c78bcd89e5d020cfde4acf0a9233e9d4e3fa698b4/psutil-7.1.3-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95ef04cf2e5ba0ab9eaafc4a11eaae91b44f4ef5541acd2ee91d9108d00d59a7", size = 287134, upload-time = "2025-11-02T12:26:02.613Z" }, - { url = "https://files.pythonhosted.org/packages/30/1c/f921a009ea9ceb51aa355cb0cc118f68d354db36eae18174bab63affb3e6/psutil-7.1.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1068c303be3a72f8e18e412c5b2a8f6d31750fb152f9cb106b54090296c9d251", size = 289904, upload-time = "2025-11-02T12:26:05.207Z" }, - { url = "https://files.pythonhosted.org/packages/a6/82/62d68066e13e46a5116df187d319d1724b3f437ddd0f958756fc052677f4/psutil-7.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:18349c5c24b06ac5612c0428ec2a0331c26443d259e2a0144a9b24b4395b58fa", size = 249642, upload-time = "2025-11-02T12:26:07.447Z" }, - { url = "https://files.pythonhosted.org/packages/df/ad/c1cd5fe965c14a0392112f68362cfceb5230819dbb5b1888950d18a11d9f/psutil-7.1.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c525ffa774fe4496282fb0b1187725793de3e7c6b29e41562733cae9ada151ee", size = 245518, upload-time = "2025-11-02T12:26:09.719Z" }, - { url = "https://files.pythonhosted.org/packages/2e/bb/6670bded3e3236eb4287c7bcdc167e9fae6e1e9286e437f7111caed2f909/psutil-7.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b403da1df4d6d43973dc004d19cee3b848e998ae3154cc8097d139b77156c353", size = 239843, upload-time = "2025-11-02T12:26:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/b8/66/853d50e75a38c9a7370ddbeefabdd3d3116b9c31ef94dc92c6729bc36bec/psutil-7.1.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad81425efc5e75da3f39b3e636293360ad8d0b49bed7df824c79764fb4ba9b8b", size = 240369, upload-time = "2025-11-02T12:26:14.358Z" }, - { url = "https://files.pythonhosted.org/packages/41/bd/313aba97cb5bfb26916dc29cf0646cbe4dd6a89ca69e8c6edce654876d39/psutil-7.1.3-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f33a3702e167783a9213db10ad29650ebf383946e91bc77f28a5eb083496bc9", size = 288210, upload-time = "2025-11-02T12:26:16.699Z" }, - { url = "https://files.pythonhosted.org/packages/c2/fa/76e3c06e760927a0cfb5705eb38164254de34e9bd86db656d4dbaa228b04/psutil-7.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fac9cd332c67f4422504297889da5ab7e05fd11e3c4392140f7370f4208ded1f", size = 291182, upload-time = "2025-11-02T12:26:18.848Z" }, - { url = "https://files.pythonhosted.org/packages/0f/1d/5774a91607035ee5078b8fd747686ebec28a962f178712de100d00b78a32/psutil-7.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:3792983e23b69843aea49c8f5b8f115572c5ab64c153bada5270086a2123c7e7", size = 250466, upload-time = "2025-11-02T12:26:21.183Z" }, - { url = "https://files.pythonhosted.org/packages/00/ca/e426584bacb43a5cb1ac91fae1937f478cd8fbe5e4ff96574e698a2c77cd/psutil-7.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:31d77fcedb7529f27bb3a0472bea9334349f9a04160e8e6e5020f22c59893264", size = 245756, upload-time = "2025-11-02T12:26:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/ef/94/46b9154a800253e7ecff5aaacdf8ebf43db99de4a2dfa18575b02548654e/psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab", size = 238359, upload-time = "2025-11-02T12:26:25.284Z" }, - { url = "https://files.pythonhosted.org/packages/68/3a/9f93cff5c025029a36d9a92fef47220ab4692ee7f2be0fba9f92813d0cb8/psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880", size = 239171, upload-time = "2025-11-02T12:26:27.23Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b1/5f49af514f76431ba4eea935b8ad3725cdeb397e9245ab919dbc1d1dc20f/psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3", size = 263261, upload-time = "2025-11-02T12:26:29.48Z" }, - { url = "https://files.pythonhosted.org/packages/e0/95/992c8816a74016eb095e73585d747e0a8ea21a061ed3689474fabb29a395/psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b", size = 264635, upload-time = "2025-11-02T12:26:31.74Z" }, - { url = "https://files.pythonhosted.org/packages/55/4c/c3ed1a622b6ae2fd3c945a366e64eb35247a31e4db16cf5095e269e8eb3c/psutil-7.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:f39c2c19fe824b47484b96f9692932248a54c43799a84282cfe58d05a6449efd", size = 247633, upload-time = "2025-11-02T12:26:33.887Z" }, - { url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608, upload-time = "2025-11-02T12:26:36.136Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e1/88/bdd0a41e5857d5d703287598cbf08dad90aed56774ea52ae071bae9071b6/psutil-7.1.3.tar.gz", hash = "sha256:6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74", size = 489059 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/93/0c49e776b8734fef56ec9c5c57f923922f2cf0497d62e0f419465f28f3d0/psutil-7.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0005da714eee687b4b8decd3d6cc7c6db36215c9e74e5ad2264b90c3df7d92dc", size = 239751 }, + { url = "https://files.pythonhosted.org/packages/6f/8d/b31e39c769e70780f007969815195a55c81a63efebdd4dbe9e7a113adb2f/psutil-7.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19644c85dcb987e35eeeaefdc3915d059dac7bd1167cdcdbf27e0ce2df0c08c0", size = 240368 }, + { url = "https://files.pythonhosted.org/packages/62/61/23fd4acc3c9eebbf6b6c78bcd89e5d020cfde4acf0a9233e9d4e3fa698b4/psutil-7.1.3-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95ef04cf2e5ba0ab9eaafc4a11eaae91b44f4ef5541acd2ee91d9108d00d59a7", size = 287134 }, + { url = "https://files.pythonhosted.org/packages/30/1c/f921a009ea9ceb51aa355cb0cc118f68d354db36eae18174bab63affb3e6/psutil-7.1.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1068c303be3a72f8e18e412c5b2a8f6d31750fb152f9cb106b54090296c9d251", size = 289904 }, + { url = "https://files.pythonhosted.org/packages/a6/82/62d68066e13e46a5116df187d319d1724b3f437ddd0f958756fc052677f4/psutil-7.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:18349c5c24b06ac5612c0428ec2a0331c26443d259e2a0144a9b24b4395b58fa", size = 249642 }, + { url = "https://files.pythonhosted.org/packages/df/ad/c1cd5fe965c14a0392112f68362cfceb5230819dbb5b1888950d18a11d9f/psutil-7.1.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c525ffa774fe4496282fb0b1187725793de3e7c6b29e41562733cae9ada151ee", size = 245518 }, + { url = "https://files.pythonhosted.org/packages/2e/bb/6670bded3e3236eb4287c7bcdc167e9fae6e1e9286e437f7111caed2f909/psutil-7.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b403da1df4d6d43973dc004d19cee3b848e998ae3154cc8097d139b77156c353", size = 239843 }, + { url = "https://files.pythonhosted.org/packages/b8/66/853d50e75a38c9a7370ddbeefabdd3d3116b9c31ef94dc92c6729bc36bec/psutil-7.1.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad81425efc5e75da3f39b3e636293360ad8d0b49bed7df824c79764fb4ba9b8b", size = 240369 }, + { url = "https://files.pythonhosted.org/packages/41/bd/313aba97cb5bfb26916dc29cf0646cbe4dd6a89ca69e8c6edce654876d39/psutil-7.1.3-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f33a3702e167783a9213db10ad29650ebf383946e91bc77f28a5eb083496bc9", size = 288210 }, + { url = "https://files.pythonhosted.org/packages/c2/fa/76e3c06e760927a0cfb5705eb38164254de34e9bd86db656d4dbaa228b04/psutil-7.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fac9cd332c67f4422504297889da5ab7e05fd11e3c4392140f7370f4208ded1f", size = 291182 }, + { url = "https://files.pythonhosted.org/packages/0f/1d/5774a91607035ee5078b8fd747686ebec28a962f178712de100d00b78a32/psutil-7.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:3792983e23b69843aea49c8f5b8f115572c5ab64c153bada5270086a2123c7e7", size = 250466 }, + { url = "https://files.pythonhosted.org/packages/00/ca/e426584bacb43a5cb1ac91fae1937f478cd8fbe5e4ff96574e698a2c77cd/psutil-7.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:31d77fcedb7529f27bb3a0472bea9334349f9a04160e8e6e5020f22c59893264", size = 245756 }, + { url = "https://files.pythonhosted.org/packages/ef/94/46b9154a800253e7ecff5aaacdf8ebf43db99de4a2dfa18575b02548654e/psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab", size = 238359 }, + { url = "https://files.pythonhosted.org/packages/68/3a/9f93cff5c025029a36d9a92fef47220ab4692ee7f2be0fba9f92813d0cb8/psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880", size = 239171 }, + { url = "https://files.pythonhosted.org/packages/ce/b1/5f49af514f76431ba4eea935b8ad3725cdeb397e9245ab919dbc1d1dc20f/psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3", size = 263261 }, + { url = "https://files.pythonhosted.org/packages/e0/95/992c8816a74016eb095e73585d747e0a8ea21a061ed3689474fabb29a395/psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b", size = 264635 }, + { url = "https://files.pythonhosted.org/packages/55/4c/c3ed1a622b6ae2fd3c945a366e64eb35247a31e4db16cf5095e269e8eb3c/psutil-7.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:f39c2c19fe824b47484b96f9692932248a54c43799a84282cfe58d05a6449efd", size = 247633 }, + { url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608 }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, ] [[package]] name = "pycparser" version = "2.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, ] [[package]] @@ -3284,9 +3276,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 } 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 }, ] [[package]] @@ -3296,115 +3288,107 @@ 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/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, - { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, - { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, - { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, - { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, - { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, - { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, - { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, - { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, - { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, - { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, - { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, - { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, - { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, - { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, - { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, - { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, - { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, - { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, - { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, - { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, - { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, - { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, - { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, - { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, - { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, - { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, - { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, - { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, - { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, - { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, - { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, - { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, - { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, - { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, - { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, - { 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" }, - { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, - { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, - { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, - { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, - { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, - { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, - { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, - { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, - { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, - { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, - { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, - { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, - { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, - { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, - { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, - { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, - { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298 }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475 }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815 }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567 }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442 }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956 }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253 }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050 }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178 }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833 }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156 }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378 }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622 }, + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873 }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826 }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869 }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890 }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740 }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021 }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378 }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761 }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303 }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355 }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875 }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549 }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305 }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902 }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990 }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003 }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200 }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578 }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504 }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816 }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366 }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698 }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603 }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591 }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068 }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908 }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145 }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679 }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766 }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126 }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489 }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906 }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607 }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769 }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351 }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363 }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615 }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369 }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218 }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951 }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428 }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009 }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980 }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865 }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256 }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762 }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141 }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317 }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992 }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302 }, ] [[package]] @@ -3416,18 +3400,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 } 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 }, ] [[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 } 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 }, ] [[package]] @@ -3437,9 +3421,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/e0/57f914ae9fedbc91fe3ebe74b78c88903943ec9c232b6da15947bb3bf8ab/pypdf-6.4.1.tar.gz", hash = "sha256:36eb0b52730fc3077d2b8d4122751e696d46af9ef9e5383db492df1ab0cc4647", size = 5275322, upload-time = "2025-12-07T14:19:27.922Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/e0/57f914ae9fedbc91fe3ebe74b78c88903943ec9c232b6da15947bb3bf8ab/pypdf-6.4.1.tar.gz", hash = "sha256:36eb0b52730fc3077d2b8d4122751e696d46af9ef9e5383db492df1ab0cc4647", size = 5275322 } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/ef/68c0f473d8b8764b23f199450dfa035e6f2206e67e9bde5dd695bab9bdf0/pypdf-6.4.1-py3-none-any.whl", hash = "sha256:1782ee0766f0b77defc305f1eb2bafe738a2ef6313f3f3d2ee85b4542ba7e535", size = 328325, upload-time = "2025-12-07T14:19:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/db/ef/68c0f473d8b8764b23f199450dfa035e6f2206e67e9bde5dd695bab9bdf0/pypdf-6.4.1-py3-none-any.whl", hash = "sha256:1782ee0766f0b77defc305f1eb2bafe738a2ef6313f3f3d2ee85b4542ba7e535", size = 328325 }, ] [[package]] @@ -3455,9 +3439,9 @@ dependencies = [ { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668 }, ] [[package]] @@ -3469,9 +3453,9 @@ dependencies = [ { name = "pytest" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, + { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075 }, ] [[package]] @@ -3481,133 +3465,133 @@ 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 } 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 }, ] [[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 } 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 }, ] [[package]] name = "python-json-logger" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683 } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548 }, ] [[package]] name = "python-ulid" version = "3.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/7e/0d6c82b5ccc71e7c833aed43d9e8468e1f2ff0be1b3f657a6fcafbb8433d/python_ulid-3.1.0.tar.gz", hash = "sha256:ff0410a598bc5f6b01b602851a3296ede6f91389f913a5d5f8c496003836f636", size = 93175, upload-time = "2025-08-18T16:09:26.305Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/7e/0d6c82b5ccc71e7c833aed43d9e8468e1f2ff0be1b3f657a6fcafbb8433d/python_ulid-3.1.0.tar.gz", hash = "sha256:ff0410a598bc5f6b01b602851a3296ede6f91389f913a5d5f8c496003836f636", size = 93175 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/a0/4ed6632b70a52de845df056654162acdebaf97c20e3212c559ac43e7216e/python_ulid-3.1.0-py3-none-any.whl", hash = "sha256:e2cdc979c8c877029b4b7a38a6fba3bc4578e4f109a308419ff4d3ccf0a46619", size = 11577, upload-time = "2025-08-18T16:09:25.047Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a0/4ed6632b70a52de845df056654162acdebaf97c20e3212c559ac43e7216e/python_ulid-3.1.0-py3-none-any.whl", hash = "sha256:e2cdc979c8c877029b4b7a38a6fba3bc4578e4f109a308419ff4d3ccf0a46619", size = 11577 }, ] [[package]] name = "pytokens" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, + { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195 }, ] [[package]] name = "pytz" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, ] [[package]] name = "pywinpty" version = "3.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669, upload-time = "2025-10-03T21:16:29.205Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330, upload-time = "2025-10-03T21:20:15.656Z" }, - { url = "https://files.pythonhosted.org/packages/a6/a1/409c1651c9f874d598c10f51ff586c416625601df4bca315d08baec4c3e3/pywinpty-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:327790d70e4c841ebd9d0f295a780177149aeb405bca44c7115a3de5c2054b23", size = 2050304, upload-time = "2025-10-03T21:19:29.466Z" }, - { url = "https://files.pythonhosted.org/packages/02/4e/1098484e042c9485f56f16eb2b69b43b874bd526044ee401512234cf9e04/pywinpty-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:99fdd9b455f0ad6419aba6731a7a0d2f88ced83c3c94a80ff9533d95fa8d8a9e", size = 2050391, upload-time = "2025-10-03T21:19:01.642Z" }, - { url = "https://files.pythonhosted.org/packages/fc/19/b757fe28008236a4a713e813283721b8a40aa60cd7d3f83549f2e25a3155/pywinpty-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:18f78b81e4cfee6aabe7ea8688441d30247b73e52cd9657138015c5f4ee13a51", size = 2050057, upload-time = "2025-10-03T21:19:26.732Z" }, - { url = "https://files.pythonhosted.org/packages/cb/44/cbae12ecf6f4fa4129c36871fd09c6bef4f98d5f625ecefb5e2449765508/pywinpty-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:663383ecfab7fc382cc97ea5c4f7f0bb32c2f889259855df6ea34e5df42d305b", size = 2049874, upload-time = "2025-10-03T21:18:53.923Z" }, - { url = "https://files.pythonhosted.org/packages/ca/15/f12c6055e2d7a617d4d5820e8ac4ceaff849da4cb124640ef5116a230771/pywinpty-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:28297cecc37bee9f24d8889e47231972d6e9e84f7b668909de54f36ca785029a", size = 2050386, upload-time = "2025-10-03T21:18:50.477Z" }, - { url = "https://files.pythonhosted.org/packages/de/24/c6907c5bb06043df98ad6a0a0ff5db2e0affcecbc3b15c42404393a3f72a/pywinpty-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:34b55ae9a1b671fe3eae071d86618110538e8eaad18fcb1531c0830b91a82767", size = 2049834, upload-time = "2025-10-03T21:19:25.688Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330 }, + { url = "https://files.pythonhosted.org/packages/a6/a1/409c1651c9f874d598c10f51ff586c416625601df4bca315d08baec4c3e3/pywinpty-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:327790d70e4c841ebd9d0f295a780177149aeb405bca44c7115a3de5c2054b23", size = 2050304 }, + { url = "https://files.pythonhosted.org/packages/02/4e/1098484e042c9485f56f16eb2b69b43b874bd526044ee401512234cf9e04/pywinpty-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:99fdd9b455f0ad6419aba6731a7a0d2f88ced83c3c94a80ff9533d95fa8d8a9e", size = 2050391 }, + { url = "https://files.pythonhosted.org/packages/fc/19/b757fe28008236a4a713e813283721b8a40aa60cd7d3f83549f2e25a3155/pywinpty-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:18f78b81e4cfee6aabe7ea8688441d30247b73e52cd9657138015c5f4ee13a51", size = 2050057 }, + { url = "https://files.pythonhosted.org/packages/cb/44/cbae12ecf6f4fa4129c36871fd09c6bef4f98d5f625ecefb5e2449765508/pywinpty-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:663383ecfab7fc382cc97ea5c4f7f0bb32c2f889259855df6ea34e5df42d305b", size = 2049874 }, + { url = "https://files.pythonhosted.org/packages/ca/15/f12c6055e2d7a617d4d5820e8ac4ceaff849da4cb124640ef5116a230771/pywinpty-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:28297cecc37bee9f24d8889e47231972d6e9e84f7b668909de54f36ca785029a", size = 2050386 }, + { url = "https://files.pythonhosted.org/packages/de/24/c6907c5bb06043df98ad6a0a0ff5db2e0affcecbc3b15c42404393a3f72a/pywinpty-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:34b55ae9a1b671fe3eae071d86618110538e8eaad18fcb1531c0830b91a82767", size = 2049834 }, ] [[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/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826 }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577 }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556 }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114 }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638 }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463 }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986 }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543 }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763 }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063 }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973 }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116 }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011 }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870 }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089 }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181 }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658 }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003 }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427 }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090 }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429 }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062 }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, ] [[package]] @@ -3617,70 +3601,70 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, - { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, - { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, - { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, - { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, - { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, - { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, - { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, - { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, - { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038, upload-time = "2025-09-08T23:07:51.234Z" }, - { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531, upload-time = "2025-09-08T23:07:52.795Z" }, - { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786, upload-time = "2025-09-08T23:07:55.047Z" }, - { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220, upload-time = "2025-09-08T23:07:57.172Z" }, - { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155, upload-time = "2025-09-08T23:07:59.05Z" }, - { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428, upload-time = "2025-09-08T23:08:00.663Z" }, - { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497, upload-time = "2025-09-08T23:08:02.15Z" }, - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, - { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, - { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, - { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, - { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, - { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, - { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, - { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, - { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, - { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, - { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, - { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, - { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, - { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, - { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, - { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, - { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, - { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, - { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, - { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, - { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, - { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, - { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, - { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, - { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, - { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371, upload-time = "2025-09-08T23:09:54.563Z" }, - { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850 }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380 }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421 }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149 }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070 }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441 }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529 }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276 }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208 }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766 }, + { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328 }, + { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803 }, + { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836 }, + { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038 }, + { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531 }, + { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786 }, + { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220 }, + { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155 }, + { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428 }, + { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497 }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436 }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301 }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197 }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275 }, + { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469 }, + { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961 }, + { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282 }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468 }, + { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394 }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964 }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029 }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541 }, + { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197 }, + { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175 }, + { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427 }, + { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929 }, + { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193 }, + { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388 }, + { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316 }, + { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472 }, + { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401 }, + { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170 }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266 }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206 }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747 }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371 }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862 }, + { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265 }, + { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208 }, + { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747 }, + { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371 }, + { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862 }, ] [[package]] @@ -3691,9 +3675,9 @@ dependencies = [ { name = "async-timeout", version = "4.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "async-timeout", version = "5.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.11.3'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399, upload-time = "2025-08-07T08:10:11.441Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847, upload-time = "2025-08-07T08:10:09.84Z" }, + { url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847 }, ] [[package]] @@ -3711,9 +3695,9 @@ dependencies = [ { name = "redis" }, { name = "tenacity" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/ac/7c527765011d07652ff9d97fd16f563d625bd1887ad09bafe2626f77f225/redisvl-0.12.1.tar.gz", hash = "sha256:c4df3f7dd2d92c71a98e54ba32bcfb4f7bd526c749e4721de0fd1f08e0ecddec", size = 689730, upload-time = "2025-11-25T19:24:04.562Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/ac/7c527765011d07652ff9d97fd16f563d625bd1887ad09bafe2626f77f225/redisvl-0.12.1.tar.gz", hash = "sha256:c4df3f7dd2d92c71a98e54ba32bcfb4f7bd526c749e4721de0fd1f08e0ecddec", size = 689730 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/6a/f8c9f915a1d18fff2499684caff929d0c6e004ac5f6e5f9ecec88314cd2a/redisvl-0.12.1-py3-none-any.whl", hash = "sha256:c7aaea242508624b78a448362b7a33e3b411049271ce8bdc7ef95208b1095e6e", size = 176692, upload-time = "2025-11-25T19:24:03.013Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6a/f8c9f915a1d18fff2499684caff929d0c6e004ac5f6e5f9ecec88314cd2a/redisvl-0.12.1-py3-none-any.whl", hash = "sha256:c7aaea242508624b78a448362b7a33e3b411049271ce8bdc7ef95208b1095e6e", size = 176692 }, ] [[package]] @@ -3725,116 +3709,116 @@ dependencies = [ { name = "rpds-py" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -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 } 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 }, ] [[package]] name = "regex" version = "2025.11.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669, upload-time = "2025-11-03T21:34:22.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/d6/d788d52da01280a30a3f6268aef2aa71043bff359c618fea4c5b536654d5/regex-2025.11.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2b441a4ae2c8049106e8b39973bfbddfb25a179dda2bdb99b0eeb60c40a6a3af", size = 488087, upload-time = "2025-11-03T21:30:47.317Z" }, - { url = "https://files.pythonhosted.org/packages/69/39/abec3bd688ec9bbea3562de0fd764ff802976185f5ff22807bf0a2697992/regex-2025.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2fa2eed3f76677777345d2f81ee89f5de2f5745910e805f7af7386a920fa7313", size = 290544, upload-time = "2025-11-03T21:30:49.912Z" }, - { url = "https://files.pythonhosted.org/packages/39/b3/9a231475d5653e60002508f41205c61684bb2ffbf2401351ae2186897fc4/regex-2025.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8b4a27eebd684319bdf473d39f1d79eed36bf2cd34bd4465cdb4618d82b3d56", size = 288408, upload-time = "2025-11-03T21:30:51.344Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c5/1929a0491bd5ac2d1539a866768b88965fa8c405f3e16a8cef84313098d6/regex-2025.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cf77eac15bd264986c4a2c63353212c095b40f3affb2bc6b4ef80c4776c1a28", size = 781584, upload-time = "2025-11-03T21:30:52.596Z" }, - { url = "https://files.pythonhosted.org/packages/ce/fd/16aa16cf5d497ef727ec966f74164fbe75d6516d3d58ac9aa989bc9cdaad/regex-2025.11.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b7f9ee819f94c6abfa56ec7b1dbab586f41ebbdc0a57e6524bd5e7f487a878c7", size = 850733, upload-time = "2025-11-03T21:30:53.825Z" }, - { url = "https://files.pythonhosted.org/packages/e6/49/3294b988855a221cb6565189edf5dc43239957427df2d81d4a6b15244f64/regex-2025.11.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:838441333bc90b829406d4a03cb4b8bf7656231b84358628b0406d803931ef32", size = 898691, upload-time = "2025-11-03T21:30:55.575Z" }, - { url = "https://files.pythonhosted.org/packages/14/62/b56d29e70b03666193369bdbdedfdc23946dbe9f81dd78ce262c74d988ab/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfe6d3f0c9e3b7e8c0c694b24d25e677776f5ca26dce46fd6b0489f9c8339391", size = 791662, upload-time = "2025-11-03T21:30:57.262Z" }, - { url = "https://files.pythonhosted.org/packages/15/fc/e4c31d061eced63fbf1ce9d853975f912c61a7d406ea14eda2dd355f48e7/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2ab815eb8a96379a27c3b6157fcb127c8f59c36f043c1678110cea492868f1d5", size = 782587, upload-time = "2025-11-03T21:30:58.788Z" }, - { url = "https://files.pythonhosted.org/packages/b2/bb/5e30c7394bcf63f0537121c23e796be67b55a8847c3956ae6068f4c70702/regex-2025.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:728a9d2d173a65b62bdc380b7932dd8e74ed4295279a8fe1021204ce210803e7", size = 774709, upload-time = "2025-11-03T21:31:00.081Z" }, - { url = "https://files.pythonhosted.org/packages/c5/c4/fce773710af81b0cb37cb4ff0947e75d5d17dee304b93d940b87a67fc2f4/regex-2025.11.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:509dc827f89c15c66a0c216331260d777dd6c81e9a4e4f830e662b0bb296c313", size = 845773, upload-time = "2025-11-03T21:31:01.583Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5e/9466a7ec4b8ec282077095c6eb50a12a389d2e036581134d4919e8ca518c/regex-2025.11.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:849202cd789e5f3cf5dcc7822c34b502181b4824a65ff20ce82da5524e45e8e9", size = 836164, upload-time = "2025-11-03T21:31:03.244Z" }, - { url = "https://files.pythonhosted.org/packages/95/18/82980a60e8ed1594eb3c89eb814fb276ef51b9af7caeab1340bfd8564af6/regex-2025.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b6f78f98741dcc89607c16b1e9426ee46ce4bf31ac5e6b0d40e81c89f3481ea5", size = 779832, upload-time = "2025-11-03T21:31:04.876Z" }, - { url = "https://files.pythonhosted.org/packages/03/cc/90ab0fdbe6dce064a42015433f9152710139fb04a8b81b4fb57a1cb63ffa/regex-2025.11.3-cp310-cp310-win32.whl", hash = "sha256:149eb0bba95231fb4f6d37c8f760ec9fa6fabf65bab555e128dde5f2475193ec", size = 265802, upload-time = "2025-11-03T21:31:06.581Z" }, - { url = "https://files.pythonhosted.org/packages/34/9d/e9e8493a85f3b1ddc4a5014465f5c2b78c3ea1cbf238dcfde78956378041/regex-2025.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:ee3a83ce492074c35a74cc76cf8235d49e77b757193a5365ff86e3f2f93db9fd", size = 277722, upload-time = "2025-11-03T21:31:08.144Z" }, - { url = "https://files.pythonhosted.org/packages/15/c4/b54b24f553966564506dbf873a3e080aef47b356a3b39b5d5aba992b50db/regex-2025.11.3-cp310-cp310-win_arm64.whl", hash = "sha256:38af559ad934a7b35147716655d4a2f79fcef2d695ddfe06a06ba40ae631fa7e", size = 270289, upload-time = "2025-11-03T21:31:10.267Z" }, - { url = "https://files.pythonhosted.org/packages/f7/90/4fb5056e5f03a7048abd2b11f598d464f0c167de4f2a51aa868c376b8c70/regex-2025.11.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eadade04221641516fa25139273505a1c19f9bf97589a05bc4cfcd8b4a618031", size = 488081, upload-time = "2025-11-03T21:31:11.946Z" }, - { url = "https://files.pythonhosted.org/packages/85/23/63e481293fac8b069d84fba0299b6666df720d875110efd0338406b5d360/regex-2025.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:feff9e54ec0dd3833d659257f5c3f5322a12eee58ffa360984b716f8b92983f4", size = 290554, upload-time = "2025-11-03T21:31:13.387Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9d/b101d0262ea293a0066b4522dfb722eb6a8785a8c3e084396a5f2c431a46/regex-2025.11.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b30bc921d50365775c09a7ed446359e5c0179e9e2512beec4a60cbcef6ddd50", size = 288407, upload-time = "2025-11-03T21:31:14.809Z" }, - { url = "https://files.pythonhosted.org/packages/0c/64/79241c8209d5b7e00577ec9dca35cd493cc6be35b7d147eda367d6179f6d/regex-2025.11.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f99be08cfead2020c7ca6e396c13543baea32343b7a9a5780c462e323bd8872f", size = 793418, upload-time = "2025-11-03T21:31:16.556Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e2/23cd5d3573901ce8f9757c92ca4db4d09600b865919b6d3e7f69f03b1afd/regex-2025.11.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6dd329a1b61c0ee95ba95385fb0c07ea0d3fe1a21e1349fa2bec272636217118", size = 860448, upload-time = "2025-11-03T21:31:18.12Z" }, - { url = "https://files.pythonhosted.org/packages/2a/4c/aecf31beeaa416d0ae4ecb852148d38db35391aac19c687b5d56aedf3a8b/regex-2025.11.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c5238d32f3c5269d9e87be0cf096437b7622b6920f5eac4fd202468aaeb34d2", size = 907139, upload-time = "2025-11-03T21:31:20.753Z" }, - { url = "https://files.pythonhosted.org/packages/61/22/b8cb00df7d2b5e0875f60628594d44dba283e951b1ae17c12f99e332cc0a/regex-2025.11.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10483eefbfb0adb18ee9474498c9a32fcf4e594fbca0543bb94c48bac6183e2e", size = 800439, upload-time = "2025-11-03T21:31:22.069Z" }, - { url = "https://files.pythonhosted.org/packages/02/a8/c4b20330a5cdc7a8eb265f9ce593f389a6a88a0c5f280cf4d978f33966bc/regex-2025.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78c2d02bb6e1da0720eedc0bad578049cad3f71050ef8cd065ecc87691bed2b0", size = 782965, upload-time = "2025-11-03T21:31:23.598Z" }, - { url = "https://files.pythonhosted.org/packages/b4/4c/ae3e52988ae74af4b04d2af32fee4e8077f26e51b62ec2d12d246876bea2/regex-2025.11.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b49cd2aad93a1790ce9cffb18964f6d3a4b0b3dbdbd5de094b65296fce6e58", size = 854398, upload-time = "2025-11-03T21:31:25.008Z" }, - { url = "https://files.pythonhosted.org/packages/06/d1/a8b9cf45874eda14b2e275157ce3b304c87e10fb38d9fc26a6e14eb18227/regex-2025.11.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:885b26aa3ee56433b630502dc3d36ba78d186a00cc535d3806e6bfd9ed3c70ab", size = 845897, upload-time = "2025-11-03T21:31:26.427Z" }, - { url = "https://files.pythonhosted.org/packages/ea/fe/1830eb0236be93d9b145e0bd8ab499f31602fe0999b1f19e99955aa8fe20/regex-2025.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ddd76a9f58e6a00f8772e72cff8ebcff78e022be95edf018766707c730593e1e", size = 788906, upload-time = "2025-11-03T21:31:28.078Z" }, - { url = "https://files.pythonhosted.org/packages/66/47/dc2577c1f95f188c1e13e2e69d8825a5ac582ac709942f8a03af42ed6e93/regex-2025.11.3-cp311-cp311-win32.whl", hash = "sha256:3e816cc9aac1cd3cc9a4ec4d860f06d40f994b5c7b4d03b93345f44e08cc68bf", size = 265812, upload-time = "2025-11-03T21:31:29.72Z" }, - { url = "https://files.pythonhosted.org/packages/50/1e/15f08b2f82a9bbb510621ec9042547b54d11e83cb620643ebb54e4eb7d71/regex-2025.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:087511f5c8b7dfbe3a03f5d5ad0c2a33861b1fc387f21f6f60825a44865a385a", size = 277737, upload-time = "2025-11-03T21:31:31.422Z" }, - { url = "https://files.pythonhosted.org/packages/f4/fc/6500eb39f5f76c5e47a398df82e6b535a5e345f839581012a418b16f9cc3/regex-2025.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:1ff0d190c7f68ae7769cd0313fe45820ba07ffebfddfaa89cc1eb70827ba0ddc", size = 270290, upload-time = "2025-11-03T21:31:33.041Z" }, - { url = "https://files.pythonhosted.org/packages/e8/74/18f04cb53e58e3fb107439699bd8375cf5a835eec81084e0bddbd122e4c2/regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41", size = 489312, upload-time = "2025-11-03T21:31:34.343Z" }, - { url = "https://files.pythonhosted.org/packages/78/3f/37fcdd0d2b1e78909108a876580485ea37c91e1acf66d3bb8e736348f441/regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36", size = 291256, upload-time = "2025-11-03T21:31:35.675Z" }, - { url = "https://files.pythonhosted.org/packages/bf/26/0a575f58eb23b7ebd67a45fccbc02ac030b737b896b7e7a909ffe43ffd6a/regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1", size = 288921, upload-time = "2025-11-03T21:31:37.07Z" }, - { url = "https://files.pythonhosted.org/packages/ea/98/6a8dff667d1af907150432cf5abc05a17ccd32c72a3615410d5365ac167a/regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7", size = 798568, upload-time = "2025-11-03T21:31:38.784Z" }, - { url = "https://files.pythonhosted.org/packages/64/15/92c1db4fa4e12733dd5a526c2dd2b6edcbfe13257e135fc0f6c57f34c173/regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69", size = 864165, upload-time = "2025-11-03T21:31:40.559Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e7/3ad7da8cdee1ce66c7cd37ab5ab05c463a86ffeb52b1a25fe7bd9293b36c/regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48", size = 912182, upload-time = "2025-11-03T21:31:42.002Z" }, - { url = "https://files.pythonhosted.org/packages/84/bd/9ce9f629fcb714ffc2c3faf62b6766ecb7a585e1e885eb699bcf130a5209/regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c", size = 803501, upload-time = "2025-11-03T21:31:43.815Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0f/8dc2e4349d8e877283e6edd6c12bdcebc20f03744e86f197ab6e4492bf08/regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695", size = 787842, upload-time = "2025-11-03T21:31:45.353Z" }, - { url = "https://files.pythonhosted.org/packages/f9/73/cff02702960bc185164d5619c0c62a2f598a6abff6695d391b096237d4ab/regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98", size = 858519, upload-time = "2025-11-03T21:31:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/61/83/0e8d1ae71e15bc1dc36231c90b46ee35f9d52fab2e226b0e039e7ea9c10a/regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74", size = 850611, upload-time = "2025-11-03T21:31:48.289Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f5/70a5cdd781dcfaa12556f2955bf170cd603cb1c96a1827479f8faea2df97/regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0", size = 789759, upload-time = "2025-11-03T21:31:49.759Z" }, - { url = "https://files.pythonhosted.org/packages/59/9b/7c29be7903c318488983e7d97abcf8ebd3830e4c956c4c540005fcfb0462/regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204", size = 266194, upload-time = "2025-11-03T21:31:51.53Z" }, - { url = "https://files.pythonhosted.org/packages/1a/67/3b92df89f179d7c367be654ab5626ae311cb28f7d5c237b6bb976cd5fbbb/regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9", size = 277069, upload-time = "2025-11-03T21:31:53.151Z" }, - { url = "https://files.pythonhosted.org/packages/d7/55/85ba4c066fe5094d35b249c3ce8df0ba623cfd35afb22d6764f23a52a1c5/regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26", size = 270330, upload-time = "2025-11-03T21:31:54.514Z" }, - { url = "https://files.pythonhosted.org/packages/e1/a7/dda24ebd49da46a197436ad96378f17df30ceb40e52e859fc42cac45b850/regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4", size = 489081, upload-time = "2025-11-03T21:31:55.9Z" }, - { url = "https://files.pythonhosted.org/packages/19/22/af2dc751aacf88089836aa088a1a11c4f21a04707eb1b0478e8e8fb32847/regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76", size = 291123, upload-time = "2025-11-03T21:31:57.758Z" }, - { url = "https://files.pythonhosted.org/packages/a3/88/1a3ea5672f4b0a84802ee9891b86743438e7c04eb0b8f8c4e16a42375327/regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a", size = 288814, upload-time = "2025-11-03T21:32:01.12Z" }, - { url = "https://files.pythonhosted.org/packages/fb/8c/f5987895bf42b8ddeea1b315c9fedcfe07cadee28b9c98cf50d00adcb14d/regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361", size = 798592, upload-time = "2025-11-03T21:32:03.006Z" }, - { url = "https://files.pythonhosted.org/packages/99/2a/6591ebeede78203fa77ee46a1c36649e02df9eaa77a033d1ccdf2fcd5d4e/regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160", size = 864122, upload-time = "2025-11-03T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/94/d6/be32a87cf28cf8ed064ff281cfbd49aefd90242a83e4b08b5a86b38e8eb4/regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe", size = 912272, upload-time = "2025-11-03T21:32:06.148Z" }, - { url = "https://files.pythonhosted.org/packages/62/11/9bcef2d1445665b180ac7f230406ad80671f0fc2a6ffb93493b5dd8cd64c/regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850", size = 803497, upload-time = "2025-11-03T21:32:08.162Z" }, - { url = "https://files.pythonhosted.org/packages/e5/a7/da0dc273d57f560399aa16d8a68ae7f9b57679476fc7ace46501d455fe84/regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc", size = 787892, upload-time = "2025-11-03T21:32:09.769Z" }, - { url = "https://files.pythonhosted.org/packages/da/4b/732a0c5a9736a0b8d6d720d4945a2f1e6f38f87f48f3173559f53e8d5d82/regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9", size = 858462, upload-time = "2025-11-03T21:32:11.769Z" }, - { url = "https://files.pythonhosted.org/packages/0c/f5/a2a03df27dc4c2d0c769220f5110ba8c4084b0bfa9ab0f9b4fcfa3d2b0fc/regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b", size = 850528, upload-time = "2025-11-03T21:32:13.906Z" }, - { url = "https://files.pythonhosted.org/packages/d6/09/e1cd5bee3841c7f6eb37d95ca91cdee7100b8f88b81e41c2ef426910891a/regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7", size = 789866, upload-time = "2025-11-03T21:32:15.748Z" }, - { url = "https://files.pythonhosted.org/packages/eb/51/702f5ea74e2a9c13d855a6a85b7f80c30f9e72a95493260193c07f3f8d74/regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c", size = 266189, upload-time = "2025-11-03T21:32:17.493Z" }, - { url = "https://files.pythonhosted.org/packages/8b/00/6e29bb314e271a743170e53649db0fdb8e8ff0b64b4f425f5602f4eb9014/regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5", size = 277054, upload-time = "2025-11-03T21:32:19.042Z" }, - { url = "https://files.pythonhosted.org/packages/25/f1/b156ff9f2ec9ac441710764dda95e4edaf5f36aca48246d1eea3f1fd96ec/regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467", size = 270325, upload-time = "2025-11-03T21:32:21.338Z" }, - { url = "https://files.pythonhosted.org/packages/20/28/fd0c63357caefe5680b8ea052131acbd7f456893b69cc2a90cc3e0dc90d4/regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281", size = 491984, upload-time = "2025-11-03T21:32:23.466Z" }, - { url = "https://files.pythonhosted.org/packages/df/ec/7014c15626ab46b902b3bcc4b28a7bae46d8f281fc7ea9c95e22fcaaa917/regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39", size = 292673, upload-time = "2025-11-03T21:32:25.034Z" }, - { url = "https://files.pythonhosted.org/packages/23/ab/3b952ff7239f20d05f1f99e9e20188513905f218c81d52fb5e78d2bf7634/regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7", size = 291029, upload-time = "2025-11-03T21:32:26.528Z" }, - { url = "https://files.pythonhosted.org/packages/21/7e/3dc2749fc684f455f162dcafb8a187b559e2614f3826877d3844a131f37b/regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed", size = 807437, upload-time = "2025-11-03T21:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/1b/0b/d529a85ab349c6a25d1ca783235b6e3eedf187247eab536797021f7126c6/regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19", size = 873368, upload-time = "2025-11-03T21:32:30.4Z" }, - { url = "https://files.pythonhosted.org/packages/7d/18/2d868155f8c9e3e9d8f9e10c64e9a9f496bb8f7e037a88a8bed26b435af6/regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b", size = 914921, upload-time = "2025-11-03T21:32:32.123Z" }, - { url = "https://files.pythonhosted.org/packages/2d/71/9d72ff0f354fa783fe2ba913c8734c3b433b86406117a8db4ea2bf1c7a2f/regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a", size = 812708, upload-time = "2025-11-03T21:32:34.305Z" }, - { url = "https://files.pythonhosted.org/packages/e7/19/ce4bf7f5575c97f82b6e804ffb5c4e940c62609ab2a0d9538d47a7fdf7d4/regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6", size = 795472, upload-time = "2025-11-03T21:32:36.364Z" }, - { url = "https://files.pythonhosted.org/packages/03/86/fd1063a176ffb7b2315f9a1b08d17b18118b28d9df163132615b835a26ee/regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce", size = 868341, upload-time = "2025-11-03T21:32:38.042Z" }, - { url = "https://files.pythonhosted.org/packages/12/43/103fb2e9811205e7386366501bc866a164a0430c79dd59eac886a2822950/regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd", size = 854666, upload-time = "2025-11-03T21:32:40.079Z" }, - { url = "https://files.pythonhosted.org/packages/7d/22/e392e53f3869b75804762c7c848bd2dd2abf2b70fb0e526f58724638bd35/regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2", size = 799473, upload-time = "2025-11-03T21:32:42.148Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f9/8bd6b656592f925b6845fcbb4d57603a3ac2fb2373344ffa1ed70aa6820a/regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a", size = 268792, upload-time = "2025-11-03T21:32:44.13Z" }, - { url = "https://files.pythonhosted.org/packages/e5/87/0e7d603467775ff65cd2aeabf1b5b50cc1c3708556a8b849a2fa4dd1542b/regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c", size = 280214, upload-time = "2025-11-03T21:32:45.853Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d0/2afc6f8e94e2b64bfb738a7c2b6387ac1699f09f032d363ed9447fd2bb57/regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e", size = 271469, upload-time = "2025-11-03T21:32:48.026Z" }, - { url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089, upload-time = "2025-11-03T21:32:50.027Z" }, - { url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059, upload-time = "2025-11-03T21:32:51.682Z" }, - { url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900, upload-time = "2025-11-03T21:32:53.569Z" }, - { url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010, upload-time = "2025-11-03T21:32:55.222Z" }, - { url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893, upload-time = "2025-11-03T21:32:57.239Z" }, - { url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522, upload-time = "2025-11-03T21:32:59.274Z" }, - { url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272, upload-time = "2025-11-03T21:33:01.393Z" }, - { url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958, upload-time = "2025-11-03T21:33:03.379Z" }, - { url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289, upload-time = "2025-11-03T21:33:05.374Z" }, - { url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026, upload-time = "2025-11-03T21:33:07.131Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499, upload-time = "2025-11-03T21:33:09.141Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604, upload-time = "2025-11-03T21:33:10.9Z" }, - { url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320, upload-time = "2025-11-03T21:33:12.572Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372, upload-time = "2025-11-03T21:33:14.219Z" }, - { url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985, upload-time = "2025-11-03T21:33:16.555Z" }, - { url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669, upload-time = "2025-11-03T21:33:18.32Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030, upload-time = "2025-11-03T21:33:20.048Z" }, - { url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674, upload-time = "2025-11-03T21:33:21.797Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451, upload-time = "2025-11-03T21:33:23.741Z" }, - { url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980, upload-time = "2025-11-03T21:33:25.999Z" }, - { url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852, upload-time = "2025-11-03T21:33:27.852Z" }, - { url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566, upload-time = "2025-11-03T21:33:32.364Z" }, - { url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463, upload-time = "2025-11-03T21:33:34.459Z" }, - { url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694, upload-time = "2025-11-03T21:33:36.793Z" }, - { url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691, upload-time = "2025-11-03T21:33:39.079Z" }, - { url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583, upload-time = "2025-11-03T21:33:41.302Z" }, - { url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286, upload-time = "2025-11-03T21:33:43.324Z" }, - { url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741, upload-time = "2025-11-03T21:33:45.557Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/d6/d788d52da01280a30a3f6268aef2aa71043bff359c618fea4c5b536654d5/regex-2025.11.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2b441a4ae2c8049106e8b39973bfbddfb25a179dda2bdb99b0eeb60c40a6a3af", size = 488087 }, + { url = "https://files.pythonhosted.org/packages/69/39/abec3bd688ec9bbea3562de0fd764ff802976185f5ff22807bf0a2697992/regex-2025.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2fa2eed3f76677777345d2f81ee89f5de2f5745910e805f7af7386a920fa7313", size = 290544 }, + { url = "https://files.pythonhosted.org/packages/39/b3/9a231475d5653e60002508f41205c61684bb2ffbf2401351ae2186897fc4/regex-2025.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8b4a27eebd684319bdf473d39f1d79eed36bf2cd34bd4465cdb4618d82b3d56", size = 288408 }, + { url = "https://files.pythonhosted.org/packages/c3/c5/1929a0491bd5ac2d1539a866768b88965fa8c405f3e16a8cef84313098d6/regex-2025.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cf77eac15bd264986c4a2c63353212c095b40f3affb2bc6b4ef80c4776c1a28", size = 781584 }, + { url = "https://files.pythonhosted.org/packages/ce/fd/16aa16cf5d497ef727ec966f74164fbe75d6516d3d58ac9aa989bc9cdaad/regex-2025.11.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b7f9ee819f94c6abfa56ec7b1dbab586f41ebbdc0a57e6524bd5e7f487a878c7", size = 850733 }, + { url = "https://files.pythonhosted.org/packages/e6/49/3294b988855a221cb6565189edf5dc43239957427df2d81d4a6b15244f64/regex-2025.11.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:838441333bc90b829406d4a03cb4b8bf7656231b84358628b0406d803931ef32", size = 898691 }, + { url = "https://files.pythonhosted.org/packages/14/62/b56d29e70b03666193369bdbdedfdc23946dbe9f81dd78ce262c74d988ab/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfe6d3f0c9e3b7e8c0c694b24d25e677776f5ca26dce46fd6b0489f9c8339391", size = 791662 }, + { url = "https://files.pythonhosted.org/packages/15/fc/e4c31d061eced63fbf1ce9d853975f912c61a7d406ea14eda2dd355f48e7/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2ab815eb8a96379a27c3b6157fcb127c8f59c36f043c1678110cea492868f1d5", size = 782587 }, + { url = "https://files.pythonhosted.org/packages/b2/bb/5e30c7394bcf63f0537121c23e796be67b55a8847c3956ae6068f4c70702/regex-2025.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:728a9d2d173a65b62bdc380b7932dd8e74ed4295279a8fe1021204ce210803e7", size = 774709 }, + { url = "https://files.pythonhosted.org/packages/c5/c4/fce773710af81b0cb37cb4ff0947e75d5d17dee304b93d940b87a67fc2f4/regex-2025.11.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:509dc827f89c15c66a0c216331260d777dd6c81e9a4e4f830e662b0bb296c313", size = 845773 }, + { url = "https://files.pythonhosted.org/packages/7b/5e/9466a7ec4b8ec282077095c6eb50a12a389d2e036581134d4919e8ca518c/regex-2025.11.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:849202cd789e5f3cf5dcc7822c34b502181b4824a65ff20ce82da5524e45e8e9", size = 836164 }, + { url = "https://files.pythonhosted.org/packages/95/18/82980a60e8ed1594eb3c89eb814fb276ef51b9af7caeab1340bfd8564af6/regex-2025.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b6f78f98741dcc89607c16b1e9426ee46ce4bf31ac5e6b0d40e81c89f3481ea5", size = 779832 }, + { url = "https://files.pythonhosted.org/packages/03/cc/90ab0fdbe6dce064a42015433f9152710139fb04a8b81b4fb57a1cb63ffa/regex-2025.11.3-cp310-cp310-win32.whl", hash = "sha256:149eb0bba95231fb4f6d37c8f760ec9fa6fabf65bab555e128dde5f2475193ec", size = 265802 }, + { url = "https://files.pythonhosted.org/packages/34/9d/e9e8493a85f3b1ddc4a5014465f5c2b78c3ea1cbf238dcfde78956378041/regex-2025.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:ee3a83ce492074c35a74cc76cf8235d49e77b757193a5365ff86e3f2f93db9fd", size = 277722 }, + { url = "https://files.pythonhosted.org/packages/15/c4/b54b24f553966564506dbf873a3e080aef47b356a3b39b5d5aba992b50db/regex-2025.11.3-cp310-cp310-win_arm64.whl", hash = "sha256:38af559ad934a7b35147716655d4a2f79fcef2d695ddfe06a06ba40ae631fa7e", size = 270289 }, + { url = "https://files.pythonhosted.org/packages/f7/90/4fb5056e5f03a7048abd2b11f598d464f0c167de4f2a51aa868c376b8c70/regex-2025.11.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eadade04221641516fa25139273505a1c19f9bf97589a05bc4cfcd8b4a618031", size = 488081 }, + { url = "https://files.pythonhosted.org/packages/85/23/63e481293fac8b069d84fba0299b6666df720d875110efd0338406b5d360/regex-2025.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:feff9e54ec0dd3833d659257f5c3f5322a12eee58ffa360984b716f8b92983f4", size = 290554 }, + { url = "https://files.pythonhosted.org/packages/2b/9d/b101d0262ea293a0066b4522dfb722eb6a8785a8c3e084396a5f2c431a46/regex-2025.11.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b30bc921d50365775c09a7ed446359e5c0179e9e2512beec4a60cbcef6ddd50", size = 288407 }, + { url = "https://files.pythonhosted.org/packages/0c/64/79241c8209d5b7e00577ec9dca35cd493cc6be35b7d147eda367d6179f6d/regex-2025.11.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f99be08cfead2020c7ca6e396c13543baea32343b7a9a5780c462e323bd8872f", size = 793418 }, + { url = "https://files.pythonhosted.org/packages/3d/e2/23cd5d3573901ce8f9757c92ca4db4d09600b865919b6d3e7f69f03b1afd/regex-2025.11.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6dd329a1b61c0ee95ba95385fb0c07ea0d3fe1a21e1349fa2bec272636217118", size = 860448 }, + { url = "https://files.pythonhosted.org/packages/2a/4c/aecf31beeaa416d0ae4ecb852148d38db35391aac19c687b5d56aedf3a8b/regex-2025.11.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c5238d32f3c5269d9e87be0cf096437b7622b6920f5eac4fd202468aaeb34d2", size = 907139 }, + { url = "https://files.pythonhosted.org/packages/61/22/b8cb00df7d2b5e0875f60628594d44dba283e951b1ae17c12f99e332cc0a/regex-2025.11.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10483eefbfb0adb18ee9474498c9a32fcf4e594fbca0543bb94c48bac6183e2e", size = 800439 }, + { url = "https://files.pythonhosted.org/packages/02/a8/c4b20330a5cdc7a8eb265f9ce593f389a6a88a0c5f280cf4d978f33966bc/regex-2025.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78c2d02bb6e1da0720eedc0bad578049cad3f71050ef8cd065ecc87691bed2b0", size = 782965 }, + { url = "https://files.pythonhosted.org/packages/b4/4c/ae3e52988ae74af4b04d2af32fee4e8077f26e51b62ec2d12d246876bea2/regex-2025.11.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b49cd2aad93a1790ce9cffb18964f6d3a4b0b3dbdbd5de094b65296fce6e58", size = 854398 }, + { url = "https://files.pythonhosted.org/packages/06/d1/a8b9cf45874eda14b2e275157ce3b304c87e10fb38d9fc26a6e14eb18227/regex-2025.11.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:885b26aa3ee56433b630502dc3d36ba78d186a00cc535d3806e6bfd9ed3c70ab", size = 845897 }, + { url = "https://files.pythonhosted.org/packages/ea/fe/1830eb0236be93d9b145e0bd8ab499f31602fe0999b1f19e99955aa8fe20/regex-2025.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ddd76a9f58e6a00f8772e72cff8ebcff78e022be95edf018766707c730593e1e", size = 788906 }, + { url = "https://files.pythonhosted.org/packages/66/47/dc2577c1f95f188c1e13e2e69d8825a5ac582ac709942f8a03af42ed6e93/regex-2025.11.3-cp311-cp311-win32.whl", hash = "sha256:3e816cc9aac1cd3cc9a4ec4d860f06d40f994b5c7b4d03b93345f44e08cc68bf", size = 265812 }, + { url = "https://files.pythonhosted.org/packages/50/1e/15f08b2f82a9bbb510621ec9042547b54d11e83cb620643ebb54e4eb7d71/regex-2025.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:087511f5c8b7dfbe3a03f5d5ad0c2a33861b1fc387f21f6f60825a44865a385a", size = 277737 }, + { url = "https://files.pythonhosted.org/packages/f4/fc/6500eb39f5f76c5e47a398df82e6b535a5e345f839581012a418b16f9cc3/regex-2025.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:1ff0d190c7f68ae7769cd0313fe45820ba07ffebfddfaa89cc1eb70827ba0ddc", size = 270290 }, + { url = "https://files.pythonhosted.org/packages/e8/74/18f04cb53e58e3fb107439699bd8375cf5a835eec81084e0bddbd122e4c2/regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41", size = 489312 }, + { url = "https://files.pythonhosted.org/packages/78/3f/37fcdd0d2b1e78909108a876580485ea37c91e1acf66d3bb8e736348f441/regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36", size = 291256 }, + { url = "https://files.pythonhosted.org/packages/bf/26/0a575f58eb23b7ebd67a45fccbc02ac030b737b896b7e7a909ffe43ffd6a/regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1", size = 288921 }, + { url = "https://files.pythonhosted.org/packages/ea/98/6a8dff667d1af907150432cf5abc05a17ccd32c72a3615410d5365ac167a/regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7", size = 798568 }, + { url = "https://files.pythonhosted.org/packages/64/15/92c1db4fa4e12733dd5a526c2dd2b6edcbfe13257e135fc0f6c57f34c173/regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69", size = 864165 }, + { url = "https://files.pythonhosted.org/packages/f9/e7/3ad7da8cdee1ce66c7cd37ab5ab05c463a86ffeb52b1a25fe7bd9293b36c/regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48", size = 912182 }, + { url = "https://files.pythonhosted.org/packages/84/bd/9ce9f629fcb714ffc2c3faf62b6766ecb7a585e1e885eb699bcf130a5209/regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c", size = 803501 }, + { url = "https://files.pythonhosted.org/packages/7c/0f/8dc2e4349d8e877283e6edd6c12bdcebc20f03744e86f197ab6e4492bf08/regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695", size = 787842 }, + { url = "https://files.pythonhosted.org/packages/f9/73/cff02702960bc185164d5619c0c62a2f598a6abff6695d391b096237d4ab/regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98", size = 858519 }, + { url = "https://files.pythonhosted.org/packages/61/83/0e8d1ae71e15bc1dc36231c90b46ee35f9d52fab2e226b0e039e7ea9c10a/regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74", size = 850611 }, + { url = "https://files.pythonhosted.org/packages/c8/f5/70a5cdd781dcfaa12556f2955bf170cd603cb1c96a1827479f8faea2df97/regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0", size = 789759 }, + { url = "https://files.pythonhosted.org/packages/59/9b/7c29be7903c318488983e7d97abcf8ebd3830e4c956c4c540005fcfb0462/regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204", size = 266194 }, + { url = "https://files.pythonhosted.org/packages/1a/67/3b92df89f179d7c367be654ab5626ae311cb28f7d5c237b6bb976cd5fbbb/regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9", size = 277069 }, + { url = "https://files.pythonhosted.org/packages/d7/55/85ba4c066fe5094d35b249c3ce8df0ba623cfd35afb22d6764f23a52a1c5/regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26", size = 270330 }, + { url = "https://files.pythonhosted.org/packages/e1/a7/dda24ebd49da46a197436ad96378f17df30ceb40e52e859fc42cac45b850/regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4", size = 489081 }, + { url = "https://files.pythonhosted.org/packages/19/22/af2dc751aacf88089836aa088a1a11c4f21a04707eb1b0478e8e8fb32847/regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76", size = 291123 }, + { url = "https://files.pythonhosted.org/packages/a3/88/1a3ea5672f4b0a84802ee9891b86743438e7c04eb0b8f8c4e16a42375327/regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a", size = 288814 }, + { url = "https://files.pythonhosted.org/packages/fb/8c/f5987895bf42b8ddeea1b315c9fedcfe07cadee28b9c98cf50d00adcb14d/regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361", size = 798592 }, + { url = "https://files.pythonhosted.org/packages/99/2a/6591ebeede78203fa77ee46a1c36649e02df9eaa77a033d1ccdf2fcd5d4e/regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160", size = 864122 }, + { url = "https://files.pythonhosted.org/packages/94/d6/be32a87cf28cf8ed064ff281cfbd49aefd90242a83e4b08b5a86b38e8eb4/regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe", size = 912272 }, + { url = "https://files.pythonhosted.org/packages/62/11/9bcef2d1445665b180ac7f230406ad80671f0fc2a6ffb93493b5dd8cd64c/regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850", size = 803497 }, + { url = "https://files.pythonhosted.org/packages/e5/a7/da0dc273d57f560399aa16d8a68ae7f9b57679476fc7ace46501d455fe84/regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc", size = 787892 }, + { url = "https://files.pythonhosted.org/packages/da/4b/732a0c5a9736a0b8d6d720d4945a2f1e6f38f87f48f3173559f53e8d5d82/regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9", size = 858462 }, + { url = "https://files.pythonhosted.org/packages/0c/f5/a2a03df27dc4c2d0c769220f5110ba8c4084b0bfa9ab0f9b4fcfa3d2b0fc/regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b", size = 850528 }, + { url = "https://files.pythonhosted.org/packages/d6/09/e1cd5bee3841c7f6eb37d95ca91cdee7100b8f88b81e41c2ef426910891a/regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7", size = 789866 }, + { url = "https://files.pythonhosted.org/packages/eb/51/702f5ea74e2a9c13d855a6a85b7f80c30f9e72a95493260193c07f3f8d74/regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c", size = 266189 }, + { url = "https://files.pythonhosted.org/packages/8b/00/6e29bb314e271a743170e53649db0fdb8e8ff0b64b4f425f5602f4eb9014/regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5", size = 277054 }, + { url = "https://files.pythonhosted.org/packages/25/f1/b156ff9f2ec9ac441710764dda95e4edaf5f36aca48246d1eea3f1fd96ec/regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467", size = 270325 }, + { url = "https://files.pythonhosted.org/packages/20/28/fd0c63357caefe5680b8ea052131acbd7f456893b69cc2a90cc3e0dc90d4/regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281", size = 491984 }, + { url = "https://files.pythonhosted.org/packages/df/ec/7014c15626ab46b902b3bcc4b28a7bae46d8f281fc7ea9c95e22fcaaa917/regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39", size = 292673 }, + { url = "https://files.pythonhosted.org/packages/23/ab/3b952ff7239f20d05f1f99e9e20188513905f218c81d52fb5e78d2bf7634/regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7", size = 291029 }, + { url = "https://files.pythonhosted.org/packages/21/7e/3dc2749fc684f455f162dcafb8a187b559e2614f3826877d3844a131f37b/regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed", size = 807437 }, + { url = "https://files.pythonhosted.org/packages/1b/0b/d529a85ab349c6a25d1ca783235b6e3eedf187247eab536797021f7126c6/regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19", size = 873368 }, + { url = "https://files.pythonhosted.org/packages/7d/18/2d868155f8c9e3e9d8f9e10c64e9a9f496bb8f7e037a88a8bed26b435af6/regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b", size = 914921 }, + { url = "https://files.pythonhosted.org/packages/2d/71/9d72ff0f354fa783fe2ba913c8734c3b433b86406117a8db4ea2bf1c7a2f/regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a", size = 812708 }, + { url = "https://files.pythonhosted.org/packages/e7/19/ce4bf7f5575c97f82b6e804ffb5c4e940c62609ab2a0d9538d47a7fdf7d4/regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6", size = 795472 }, + { url = "https://files.pythonhosted.org/packages/03/86/fd1063a176ffb7b2315f9a1b08d17b18118b28d9df163132615b835a26ee/regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce", size = 868341 }, + { url = "https://files.pythonhosted.org/packages/12/43/103fb2e9811205e7386366501bc866a164a0430c79dd59eac886a2822950/regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd", size = 854666 }, + { url = "https://files.pythonhosted.org/packages/7d/22/e392e53f3869b75804762c7c848bd2dd2abf2b70fb0e526f58724638bd35/regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2", size = 799473 }, + { url = "https://files.pythonhosted.org/packages/4f/f9/8bd6b656592f925b6845fcbb4d57603a3ac2fb2373344ffa1ed70aa6820a/regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a", size = 268792 }, + { url = "https://files.pythonhosted.org/packages/e5/87/0e7d603467775ff65cd2aeabf1b5b50cc1c3708556a8b849a2fa4dd1542b/regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c", size = 280214 }, + { url = "https://files.pythonhosted.org/packages/8d/d0/2afc6f8e94e2b64bfb738a7c2b6387ac1699f09f032d363ed9447fd2bb57/regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e", size = 271469 }, + { url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089 }, + { url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059 }, + { url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900 }, + { url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010 }, + { url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893 }, + { url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522 }, + { url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272 }, + { url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958 }, + { url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289 }, + { url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026 }, + { url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499 }, + { url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604 }, + { url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320 }, + { url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372 }, + { url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985 }, + { url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669 }, + { url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030 }, + { url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674 }, + { url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451 }, + { url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980 }, + { url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852 }, + { url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566 }, + { url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463 }, + { url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694 }, + { url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691 }, + { url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583 }, + { url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286 }, + { url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741 }, ] [[package]] @@ -3847,9 +3831,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 } 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 }, ] [[package]] @@ -3859,9 +3843,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481 }, ] [[package]] @@ -3871,18 +3855,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490 }, ] [[package]] name = "rfc3986-validator" version = "0.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, ] [[package]] @@ -3892,9 +3876,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046 }, ] [[package]] @@ -3905,183 +3889,183 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393 }, ] [[package]] name = "rpds-py" version = "0.29.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/33/23b3b3419b6a3e0f559c7c0d2ca8fc1b9448382b25245033788785921332/rpds_py-0.29.0.tar.gz", hash = "sha256:fe55fe686908f50154d1dc599232016e50c243b438c3b7432f24e2895b0e5359", size = 69359, upload-time = "2025-11-16T14:50:39.532Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/7a/c5b2ff381b74bc742768e8d870f26babac4ef256ba160bdbf8d57af56461/rpds_py-0.29.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4ae4b88c6617e1b9e5038ab3fccd7bac0842fdda2b703117b2aa99bc85379113", size = 372385, upload-time = "2025-11-16T14:47:36.287Z" }, - { url = "https://files.pythonhosted.org/packages/28/36/531f1eb4d5bed4a9c150f363a7ec4a98d2dc746151bba5473bc38ee85dec/rpds_py-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7d9128ec9d8cecda6f044001fde4fb71ea7c24325336612ef8179091eb9596b9", size = 362869, upload-time = "2025-11-16T14:47:38.196Z" }, - { url = "https://files.pythonhosted.org/packages/54/df/7e9c0493a2015d9c82807a2d5f023ea9774e27a4c15b33ef1cdb7456138d/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37812c3da8e06f2bb35b3cf10e4a7b68e776a706c13058997238762b4e07f4f", size = 391582, upload-time = "2025-11-16T14:47:39.746Z" }, - { url = "https://files.pythonhosted.org/packages/15/38/42a981c3592ef46fbd7e17adbf8730cc5ec87e6aa1770c658c44bbb52960/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66786c3fb1d8de416a7fa8e1cb1ec6ba0a745b2b0eee42f9b7daa26f1a495545", size = 405685, upload-time = "2025-11-16T14:47:41.472Z" }, - { url = "https://files.pythonhosted.org/packages/12/45/628b8c15856c3849c3f52ec6dac93c046ed5faeed4a435af03b70525fd29/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58f5c77f1af888b5fd1876c9a0d9858f6f88a39c9dd7c073a88e57e577da66d", size = 527067, upload-time = "2025-11-16T14:47:43.036Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ba/6b56d09badeabd95098016d72a437d4a0fd82d4672ce92a7607df5d70a42/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:799156ef1f3529ed82c36eb012b5d7a4cf4b6ef556dd7cc192148991d07206ae", size = 412532, upload-time = "2025-11-16T14:47:44.484Z" }, - { url = "https://files.pythonhosted.org/packages/f1/39/2f1f3db92888314b50b8f9641f679188bd24b3665a8cb9923b7201ae8011/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:453783477aa4f2d9104c4b59b08c871431647cb7af51b549bbf2d9eb9c827756", size = 392736, upload-time = "2025-11-16T14:47:46.053Z" }, - { url = "https://files.pythonhosted.org/packages/60/43/3c3b1dcd827e50f2ae28786d846b8a351080d8a69a3b49bc10ae44cc39b1/rpds_py-0.29.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:24a7231493e3c4a4b30138b50cca089a598e52c34cf60b2f35cebf62f274fdea", size = 406300, upload-time = "2025-11-16T14:47:47.268Z" }, - { url = "https://files.pythonhosted.org/packages/da/02/bc96021b67f8525e6bcdd68935c4543ada61e1f3dcb067ed037d68b8c6d2/rpds_py-0.29.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7033c1010b1f57bb44d8067e8c25aa6fa2e944dbf46ccc8c92b25043839c3fd2", size = 423641, upload-time = "2025-11-16T14:47:48.878Z" }, - { url = "https://files.pythonhosted.org/packages/38/e9/c435ddb602ced19a80b8277a41371734f33ad3f91cc4ceb4d82596800a3c/rpds_py-0.29.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0248b19405422573621172ab8e3a1f29141362d13d9f72bafa2e28ea0cdca5a2", size = 574153, upload-time = "2025-11-16T14:47:50.435Z" }, - { url = "https://files.pythonhosted.org/packages/84/82/dc3c32e1f89ecba8a59600d4cd65fe0ad81b6c636ccdbf6cd177fd6a7bac/rpds_py-0.29.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f9f436aee28d13b9ad2c764fc273e0457e37c2e61529a07b928346b219fcde3b", size = 600304, upload-time = "2025-11-16T14:47:51.599Z" }, - { url = "https://files.pythonhosted.org/packages/35/98/785290e0b7142470735dc1b1f68fb33aae29e5296f062c88396eedf796c8/rpds_py-0.29.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24a16cb7163933906c62c272de20ea3c228e4542c8c45c1d7dc2b9913e17369a", size = 562211, upload-time = "2025-11-16T14:47:53.094Z" }, - { url = "https://files.pythonhosted.org/packages/30/58/4eeddcb0737c6875f3e30c65dc9d7e7a10dfd5779646a990fa602c6d56c5/rpds_py-0.29.0-cp310-cp310-win32.whl", hash = "sha256:1a409b0310a566bfd1be82119891fefbdce615ccc8aa558aff7835c27988cbef", size = 221803, upload-time = "2025-11-16T14:47:54.404Z" }, - { url = "https://files.pythonhosted.org/packages/54/77/b35a8dbdcbeb32505500547cdafaa9f8863e85f8faac50ef34464ec5a256/rpds_py-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5523b0009e7c3c1263471b69d8da1c7d41b3ecb4cb62ef72be206b92040a950", size = 235530, upload-time = "2025-11-16T14:47:56.061Z" }, - { url = "https://files.pythonhosted.org/packages/36/ab/7fb95163a53ab122c74a7c42d2d2f012819af2cf3deb43fb0d5acf45cc1a/rpds_py-0.29.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b9c764a11fd637e0322a488560533112837f5334ffeb48b1be20f6d98a7b437", size = 372344, upload-time = "2025-11-16T14:47:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/b3/45/f3c30084c03b0d0f918cb4c5ae2c20b0a148b51ba2b3f6456765b629bedd/rpds_py-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fd2164d73812026ce970d44c3ebd51e019d2a26a4425a5dcbdfa93a34abc383", size = 363041, upload-time = "2025-11-16T14:47:58.908Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e9/4d044a1662608c47a87cbb37b999d4d5af54c6d6ebdda93a4d8bbf8b2a10/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a097b7f7f7274164566ae90a221fd725363c0e9d243e2e9ed43d195ccc5495c", size = 391775, upload-time = "2025-11-16T14:48:00.197Z" }, - { url = "https://files.pythonhosted.org/packages/50/c9/7616d3ace4e6731aeb6e3cd85123e03aec58e439044e214b9c5c60fd8eb1/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cdc0490374e31cedefefaa1520d5fe38e82fde8748cbc926e7284574c714d6b", size = 405624, upload-time = "2025-11-16T14:48:01.496Z" }, - { url = "https://files.pythonhosted.org/packages/c2/e2/6d7d6941ca0843609fd2d72c966a438d6f22617baf22d46c3d2156c31350/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89ca2e673ddd5bde9b386da9a0aac0cab0e76f40c8f0aaf0d6311b6bbf2aa311", size = 527894, upload-time = "2025-11-16T14:48:03.167Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f7/aee14dc2db61bb2ae1e3068f134ca9da5f28c586120889a70ff504bb026f/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5d9da3ff5af1ca1249b1adb8ef0573b94c76e6ae880ba1852f033bf429d4588", size = 412720, upload-time = "2025-11-16T14:48:04.413Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e2/2293f236e887c0360c2723d90c00d48dee296406994d6271faf1712e94ec/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8238d1d310283e87376c12f658b61e1ee23a14c0e54c7c0ce953efdbdc72deed", size = 392945, upload-time = "2025-11-16T14:48:06.252Z" }, - { url = "https://files.pythonhosted.org/packages/14/cd/ceea6147acd3bd1fd028d1975228f08ff19d62098078d5ec3eed49703797/rpds_py-0.29.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:2d6fb2ad1c36f91c4646989811e84b1ea5e0c3cf9690b826b6e32b7965853a63", size = 406385, upload-time = "2025-11-16T14:48:07.575Z" }, - { url = "https://files.pythonhosted.org/packages/52/36/fe4dead19e45eb77a0524acfdbf51e6cda597b26fc5b6dddbff55fbbb1a5/rpds_py-0.29.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:534dc9df211387547267ccdb42253aa30527482acb38dd9b21c5c115d66a96d2", size = 423943, upload-time = "2025-11-16T14:48:10.175Z" }, - { url = "https://files.pythonhosted.org/packages/a1/7b/4551510803b582fa4abbc8645441a2d15aa0c962c3b21ebb380b7e74f6a1/rpds_py-0.29.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d456e64724a075441e4ed648d7f154dc62e9aabff29bcdf723d0c00e9e1d352f", size = 574204, upload-time = "2025-11-16T14:48:11.499Z" }, - { url = "https://files.pythonhosted.org/packages/64/ba/071ccdd7b171e727a6ae079f02c26f75790b41555f12ca8f1151336d2124/rpds_py-0.29.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a738f2da2f565989401bd6fd0b15990a4d1523c6d7fe83f300b7e7d17212feca", size = 600587, upload-time = "2025-11-16T14:48:12.822Z" }, - { url = "https://files.pythonhosted.org/packages/03/09/96983d48c8cf5a1e03c7d9cc1f4b48266adfb858ae48c7c2ce978dbba349/rpds_py-0.29.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a110e14508fd26fd2e472bb541f37c209409876ba601cf57e739e87d8a53cf95", size = 562287, upload-time = "2025-11-16T14:48:14.108Z" }, - { url = "https://files.pythonhosted.org/packages/40/f0/8c01aaedc0fa92156f0391f39ea93b5952bc0ec56b897763858f95da8168/rpds_py-0.29.0-cp311-cp311-win32.whl", hash = "sha256:923248a56dd8d158389a28934f6f69ebf89f218ef96a6b216a9be6861804d3f4", size = 221394, upload-time = "2025-11-16T14:48:15.374Z" }, - { url = "https://files.pythonhosted.org/packages/7e/a5/a8b21c54c7d234efdc83dc034a4d7cd9668e3613b6316876a29b49dece71/rpds_py-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:539eb77eb043afcc45314d1be09ea6d6cafb3addc73e0547c171c6d636957f60", size = 235713, upload-time = "2025-11-16T14:48:16.636Z" }, - { url = "https://files.pythonhosted.org/packages/a7/1f/df3c56219523947b1be402fa12e6323fe6d61d883cf35d6cb5d5bb6db9d9/rpds_py-0.29.0-cp311-cp311-win_arm64.whl", hash = "sha256:bdb67151ea81fcf02d8f494703fb728d4d34d24556cbff5f417d74f6f5792e7c", size = 229157, upload-time = "2025-11-16T14:48:17.891Z" }, - { url = "https://files.pythonhosted.org/packages/3c/50/bc0e6e736d94e420df79be4deb5c9476b63165c87bb8f19ef75d100d21b3/rpds_py-0.29.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0891cfd8db43e085c0ab93ab7e9b0c8fee84780d436d3b266b113e51e79f954", size = 376000, upload-time = "2025-11-16T14:48:19.141Z" }, - { url = "https://files.pythonhosted.org/packages/3e/3a/46676277160f014ae95f24de53bed0e3b7ea66c235e7de0b9df7bd5d68ba/rpds_py-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3897924d3f9a0361472d884051f9a2460358f9a45b1d85a39a158d2f8f1ad71c", size = 360575, upload-time = "2025-11-16T14:48:20.443Z" }, - { url = "https://files.pythonhosted.org/packages/75/ba/411d414ed99ea1afdd185bbabeeaac00624bd1e4b22840b5e9967ade6337/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21deb8e0d1571508c6491ce5ea5e25669b1dd4adf1c9d64b6314842f708b5d", size = 392159, upload-time = "2025-11-16T14:48:22.12Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b1/e18aa3a331f705467a48d0296778dc1fea9d7f6cf675bd261f9a846c7e90/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9efe71687d6427737a0a2de9ca1c0a216510e6cd08925c44162be23ed7bed2d5", size = 410602, upload-time = "2025-11-16T14:48:23.563Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6c/04f27f0c9f2299274c76612ac9d2c36c5048bb2c6c2e52c38c60bf3868d9/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40f65470919dc189c833e86b2c4bd21bd355f98436a2cef9e0a9a92aebc8e57e", size = 515808, upload-time = "2025-11-16T14:48:24.949Z" }, - { url = "https://files.pythonhosted.org/packages/83/56/a8412aa464fb151f8bc0d91fb0bb888adc9039bd41c1c6ba8d94990d8cf8/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:def48ff59f181130f1a2cb7c517d16328efac3ec03951cca40c1dc2049747e83", size = 416015, upload-time = "2025-11-16T14:48:26.782Z" }, - { url = "https://files.pythonhosted.org/packages/04/4c/f9b8a05faca3d9e0a6397c90d13acb9307c9792b2bff621430c58b1d6e76/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7bd570be92695d89285a4b373006930715b78d96449f686af422debb4d3949", size = 395325, upload-time = "2025-11-16T14:48:28.055Z" }, - { url = "https://files.pythonhosted.org/packages/34/60/869f3bfbf8ed7b54f1ad9a5543e0fdffdd40b5a8f587fe300ee7b4f19340/rpds_py-0.29.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:5a572911cd053137bbff8e3a52d31c5d2dba51d3a67ad902629c70185f3f2181", size = 410160, upload-time = "2025-11-16T14:48:29.338Z" }, - { url = "https://files.pythonhosted.org/packages/91/aa/e5b496334e3aba4fe4c8a80187b89f3c1294c5c36f2a926da74338fa5a73/rpds_py-0.29.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d583d4403bcbf10cffc3ab5cee23d7643fcc960dff85973fd3c2d6c86e8dbb0c", size = 425309, upload-time = "2025-11-16T14:48:30.691Z" }, - { url = "https://files.pythonhosted.org/packages/85/68/4e24a34189751ceb6d66b28f18159922828dd84155876551f7ca5b25f14f/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:070befbb868f257d24c3bb350dbd6e2f645e83731f31264b19d7231dd5c396c7", size = 574644, upload-time = "2025-11-16T14:48:31.964Z" }, - { url = "https://files.pythonhosted.org/packages/8c/cf/474a005ea4ea9c3b4f17b6108b6b13cebfc98ebaff11d6e1b193204b3a93/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fc935f6b20b0c9f919a8ff024739174522abd331978f750a74bb68abd117bd19", size = 601605, upload-time = "2025-11-16T14:48:33.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/b1/c56f6a9ab8c5f6bb5c65c4b5f8229167a3a525245b0773f2c0896686b64e/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c5a8ecaa44ce2d8d9d20a68a2483a74c07f05d72e94a4dff88906c8807e77b0", size = 564593, upload-time = "2025-11-16T14:48:34.643Z" }, - { url = "https://files.pythonhosted.org/packages/b3/13/0494cecce4848f68501e0a229432620b4b57022388b071eeff95f3e1e75b/rpds_py-0.29.0-cp312-cp312-win32.whl", hash = "sha256:ba5e1aeaf8dd6d8f6caba1f5539cddda87d511331714b7b5fc908b6cfc3636b7", size = 223853, upload-time = "2025-11-16T14:48:36.419Z" }, - { url = "https://files.pythonhosted.org/packages/1f/6a/51e9aeb444a00cdc520b032a28b07e5f8dc7bc328b57760c53e7f96997b4/rpds_py-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:b5f6134faf54b3cb83375db0f113506f8b7770785be1f95a631e7e2892101977", size = 239895, upload-time = "2025-11-16T14:48:37.956Z" }, - { url = "https://files.pythonhosted.org/packages/d1/d4/8bce56cdad1ab873e3f27cb31c6a51d8f384d66b022b820525b879f8bed1/rpds_py-0.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:b016eddf00dca7944721bf0cd85b6af7f6c4efaf83ee0b37c4133bd39757a8c7", size = 230321, upload-time = "2025-11-16T14:48:39.71Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d9/c5de60d9d371bbb186c3e9bf75f4fc5665e11117a25a06a6b2e0afb7380e/rpds_py-0.29.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1585648d0760b88292eecab5181f5651111a69d90eff35d6b78aa32998886a61", size = 375710, upload-time = "2025-11-16T14:48:41.063Z" }, - { url = "https://files.pythonhosted.org/packages/b3/b3/0860cdd012291dc21272895ce107f1e98e335509ba986dd83d72658b82b9/rpds_py-0.29.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:521807963971a23996ddaf764c682b3e46459b3c58ccd79fefbe16718db43154", size = 360582, upload-time = "2025-11-16T14:48:42.423Z" }, - { url = "https://files.pythonhosted.org/packages/92/8a/a18c2f4a61b3407e56175f6aab6deacdf9d360191a3d6f38566e1eaf7266/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8896986efaa243ab713c69e6491a4138410f0fe36f2f4c71e18bd5501e8014", size = 391172, upload-time = "2025-11-16T14:48:43.75Z" }, - { url = "https://files.pythonhosted.org/packages/fd/49/e93354258508c50abc15cdcd5fcf7ac4117f67bb6233ad7859f75e7372a0/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d24564a700ef41480a984c5ebed62b74e6ce5860429b98b1fede76049e953e6", size = 409586, upload-time = "2025-11-16T14:48:45.498Z" }, - { url = "https://files.pythonhosted.org/packages/5a/8d/a27860dae1c19a6bdc901f90c81f0d581df1943355802961a57cdb5b6cd1/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6596b93c010d386ae46c9fba9bfc9fc5965fa8228edeac51576299182c2e31c", size = 516339, upload-time = "2025-11-16T14:48:47.308Z" }, - { url = "https://files.pythonhosted.org/packages/fc/ad/a75e603161e79b7110c647163d130872b271c6b28712c803c65d492100f7/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5cc58aac218826d054c7da7f95821eba94125d88be673ff44267bb89d12a5866", size = 416201, upload-time = "2025-11-16T14:48:48.615Z" }, - { url = "https://files.pythonhosted.org/packages/b9/42/555b4ee17508beafac135c8b450816ace5a96194ce97fefc49d58e5652ea/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de73e40ebc04dd5d9556f50180395322193a78ec247e637e741c1b954810f295", size = 395095, upload-time = "2025-11-16T14:48:50.027Z" }, - { url = "https://files.pythonhosted.org/packages/cd/f0/c90b671b9031e800ec45112be42ea9f027f94f9ac25faaac8770596a16a1/rpds_py-0.29.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:295ce5ac7f0cf69a651ea75c8f76d02a31f98e5698e82a50a5f4d4982fbbae3b", size = 410077, upload-time = "2025-11-16T14:48:51.515Z" }, - { url = "https://files.pythonhosted.org/packages/3d/80/9af8b640b81fe21e6f718e9dec36c0b5f670332747243130a5490f292245/rpds_py-0.29.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ea59b23ea931d494459c8338056fe7d93458c0bf3ecc061cd03916505369d55", size = 424548, upload-time = "2025-11-16T14:48:53.237Z" }, - { url = "https://files.pythonhosted.org/packages/e4/0b/b5647446e991736e6a495ef510e6710df91e880575a586e763baeb0aa770/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f49d41559cebd608042fdcf54ba597a4a7555b49ad5c1c0c03e0af82692661cd", size = 573661, upload-time = "2025-11-16T14:48:54.769Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b3/1b1c9576839ff583d1428efbf59f9ee70498d8ce6c0b328ac02f1e470879/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:05a2bd42768ea988294ca328206efbcc66e220d2d9b7836ee5712c07ad6340ea", size = 600937, upload-time = "2025-11-16T14:48:56.247Z" }, - { url = "https://files.pythonhosted.org/packages/6c/7b/b6cfca2f9fee4c4494ce54f7fb1b9f578867495a9aa9fc0d44f5f735c8e0/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33ca7bdfedd83339ca55da3a5e1527ee5870d4b8369456b5777b197756f3ca22", size = 564496, upload-time = "2025-11-16T14:48:57.691Z" }, - { url = "https://files.pythonhosted.org/packages/b9/fb/ba29ec7f0f06eb801bac5a23057a9ff7670623b5e8013bd59bec4aa09de8/rpds_py-0.29.0-cp313-cp313-win32.whl", hash = "sha256:20c51ae86a0bb9accc9ad4e6cdeec58d5ebb7f1b09dd4466331fc65e1766aae7", size = 223126, upload-time = "2025-11-16T14:48:59.058Z" }, - { url = "https://files.pythonhosted.org/packages/3c/6b/0229d3bed4ddaa409e6d90b0ae967ed4380e4bdd0dad6e59b92c17d42457/rpds_py-0.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:6410e66f02803600edb0b1889541f4b5cc298a5ccda0ad789cc50ef23b54813e", size = 239771, upload-time = "2025-11-16T14:49:00.872Z" }, - { url = "https://files.pythonhosted.org/packages/e4/38/d2868f058b164f8efd89754d85d7b1c08b454f5c07ac2e6cc2e9bd4bd05b/rpds_py-0.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:56838e1cd9174dc23c5691ee29f1d1be9eab357f27efef6bded1328b23e1ced2", size = 229994, upload-time = "2025-11-16T14:49:02.673Z" }, - { url = "https://files.pythonhosted.org/packages/52/91/5de91c5ec7d41759beec9b251630824dbb8e32d20c3756da1a9a9d309709/rpds_py-0.29.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:37d94eadf764d16b9a04307f2ab1d7af6dc28774bbe0535c9323101e14877b4c", size = 365886, upload-time = "2025-11-16T14:49:04.133Z" }, - { url = "https://files.pythonhosted.org/packages/85/7c/415d8c1b016d5f47ecec5145d9d6d21002d39dce8761b30f6c88810b455a/rpds_py-0.29.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d472cf73efe5726a067dce63eebe8215b14beabea7c12606fd9994267b3cfe2b", size = 355262, upload-time = "2025-11-16T14:49:05.543Z" }, - { url = "https://files.pythonhosted.org/packages/3d/14/bf83e2daa4f980e4dc848aed9299792a8b84af95e12541d9e7562f84a6ef/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72fdfd5ff8992e4636621826371e3ac5f3e3b8323e9d0e48378e9c13c3dac9d0", size = 384826, upload-time = "2025-11-16T14:49:07.301Z" }, - { url = "https://files.pythonhosted.org/packages/33/b8/53330c50a810ae22b4fbba5e6cf961b68b9d72d9bd6780a7c0a79b070857/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2549d833abdf8275c901313b9e8ff8fba57e50f6a495035a2a4e30621a2f7cc4", size = 394234, upload-time = "2025-11-16T14:49:08.782Z" }, - { url = "https://files.pythonhosted.org/packages/cc/32/01e2e9645cef0e584f518cfde4567563e57db2257244632b603f61b40e50/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4448dad428f28a6a767c3e3b80cde3446a22a0efbddaa2360f4bb4dc836d0688", size = 520008, upload-time = "2025-11-16T14:49:10.253Z" }, - { url = "https://files.pythonhosted.org/packages/98/c3/0d1b95a81affae2b10f950782e33a1fd2edd6ce2a479966cac98c9a66f57/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:115f48170fd4296a33938d8c11f697f5f26e0472e43d28f35624764173a60e4d", size = 409569, upload-time = "2025-11-16T14:49:12.478Z" }, - { url = "https://files.pythonhosted.org/packages/fa/60/aa3b8678f3f009f675b99174fa2754302a7fbfe749162e8043d111de2d88/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e5bb73ffc029820f4348e9b66b3027493ae00bca6629129cd433fd7a76308ee", size = 385188, upload-time = "2025-11-16T14:49:13.88Z" }, - { url = "https://files.pythonhosted.org/packages/92/02/5546c1c8aa89c18d40c1fcffdcc957ba730dee53fb7c3ca3a46f114761d2/rpds_py-0.29.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:b1581fcde18fcdf42ea2403a16a6b646f8eb1e58d7f90a0ce693da441f76942e", size = 398587, upload-time = "2025-11-16T14:49:15.339Z" }, - { url = "https://files.pythonhosted.org/packages/6c/e0/ad6eeaf47e236eba052fa34c4073078b9e092bd44da6bbb35aaae9580669/rpds_py-0.29.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16e9da2bda9eb17ea318b4c335ec9ac1818e88922cbe03a5743ea0da9ecf74fb", size = 416641, upload-time = "2025-11-16T14:49:16.832Z" }, - { url = "https://files.pythonhosted.org/packages/1a/93/0acedfd50ad9cdd3879c615a6dc8c5f1ce78d2fdf8b87727468bb5bb4077/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:28fd300326dd21198f311534bdb6d7e989dd09b3418b3a91d54a0f384c700967", size = 566683, upload-time = "2025-11-16T14:49:18.342Z" }, - { url = "https://files.pythonhosted.org/packages/62/53/8c64e0f340a9e801459fc6456821abc15b3582cb5dc3932d48705a9d9ac7/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2aba991e041d031c7939e1358f583ae405a7bf04804ca806b97a5c0e0af1ea5e", size = 592730, upload-time = "2025-11-16T14:49:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/85/ef/3109b6584f8c4b0d2490747c916df833c127ecfa82be04d9a40a376f2090/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f437026dbbc3f08c99cc41a5b2570c6e1a1ddbe48ab19a9b814254128d4ea7a", size = 557361, upload-time = "2025-11-16T14:49:21.574Z" }, - { url = "https://files.pythonhosted.org/packages/ff/3b/61586475e82d57f01da2c16edb9115a618afe00ce86fe1b58936880b15af/rpds_py-0.29.0-cp313-cp313t-win32.whl", hash = "sha256:6e97846e9800a5d0fe7be4d008f0c93d0feeb2700da7b1f7528dabafb31dfadb", size = 211227, upload-time = "2025-11-16T14:49:23.03Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3a/12dc43f13594a54ea0c9d7e9d43002116557330e3ad45bc56097ddf266e2/rpds_py-0.29.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f49196aec7c4b406495f60e6f947ad71f317a765f956d74bbd83996b9edc0352", size = 225248, upload-time = "2025-11-16T14:49:24.841Z" }, - { url = "https://files.pythonhosted.org/packages/89/b1/0b1474e7899371d9540d3bbb2a499a3427ae1fc39c998563fe9035a1073b/rpds_py-0.29.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:394d27e4453d3b4d82bb85665dc1fcf4b0badc30fc84282defed71643b50e1a1", size = 363731, upload-time = "2025-11-16T14:49:26.683Z" }, - { url = "https://files.pythonhosted.org/packages/28/12/3b7cf2068d0a334ed1d7b385a9c3c8509f4c2bcba3d4648ea71369de0881/rpds_py-0.29.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55d827b2ae95425d3be9bc9a5838b6c29d664924f98146557f7715e331d06df8", size = 354343, upload-time = "2025-11-16T14:49:28.24Z" }, - { url = "https://files.pythonhosted.org/packages/eb/73/5afcf8924bc02a749416eda64e17ac9c9b28f825f4737385295a0e99b0c1/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc31a07ed352e5462d3ee1b22e89285f4ce97d5266f6d1169da1142e78045626", size = 385406, upload-time = "2025-11-16T14:49:29.943Z" }, - { url = "https://files.pythonhosted.org/packages/c8/37/5db736730662508535221737a21563591b6f43c77f2e388951c42f143242/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4695dd224212f6105db7ea62197144230b808d6b2bba52238906a2762f1d1e7", size = 396162, upload-time = "2025-11-16T14:49:31.833Z" }, - { url = "https://files.pythonhosted.org/packages/70/0d/491c1017d14f62ce7bac07c32768d209a50ec567d76d9f383b4cfad19b80/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcae1770b401167f8b9e1e3f566562e6966ffa9ce63639916248a9e25fa8a244", size = 517719, upload-time = "2025-11-16T14:49:33.804Z" }, - { url = "https://files.pythonhosted.org/packages/d7/25/b11132afcb17cd5d82db173f0c8dab270ffdfaba43e5ce7a591837ae9649/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90f30d15f45048448b8da21c41703b31c61119c06c216a1bf8c245812a0f0c17", size = 409498, upload-time = "2025-11-16T14:49:35.222Z" }, - { url = "https://files.pythonhosted.org/packages/0f/7d/e6543cedfb2e6403a1845710a5ab0e0ccf8fc288e0b5af9a70bfe2c12053/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a91e0ab77bdc0004b43261a4b8cd6d6b451e8d443754cfda830002b5745b32", size = 382743, upload-time = "2025-11-16T14:49:36.704Z" }, - { url = "https://files.pythonhosted.org/packages/75/11/a4ebc9f654293ae9fefb83b2b6be7f3253e85ea42a5db2f77d50ad19aaeb/rpds_py-0.29.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:4aa195e5804d32c682e453b34474f411ca108e4291c6a0f824ebdc30a91c973c", size = 400317, upload-time = "2025-11-16T14:49:39.132Z" }, - { url = "https://files.pythonhosted.org/packages/52/18/97677a60a81c7f0e5f64e51fb3f8271c5c8fcabf3a2df18e97af53d7c2bf/rpds_py-0.29.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7971bdb7bf4ee0f7e6f67fa4c7fbc6019d9850cc977d126904392d363f6f8318", size = 416979, upload-time = "2025-11-16T14:49:40.575Z" }, - { url = "https://files.pythonhosted.org/packages/f0/69/28ab391a9968f6c746b2a2db181eaa4d16afaa859fedc9c2f682d19f7e18/rpds_py-0.29.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8ae33ad9ce580c7a47452c3b3f7d8a9095ef6208e0a0c7e4e2384f9fc5bf8212", size = 567288, upload-time = "2025-11-16T14:49:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/3b/d3/0c7afdcdb830eee94f5611b64e71354ffe6ac8df82d00c2faf2bfffd1d4e/rpds_py-0.29.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c661132ab2fb4eeede2ef69670fd60da5235209874d001a98f1542f31f2a8a94", size = 593157, upload-time = "2025-11-16T14:49:43.782Z" }, - { url = "https://files.pythonhosted.org/packages/e2/ac/a0fcbc2feed4241cf26d32268c195eb88ddd4bd862adfc9d4b25edfba535/rpds_py-0.29.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb78b3a0d31ac1bde132c67015a809948db751cb4e92cdb3f0b242e430b6ed0d", size = 554741, upload-time = "2025-11-16T14:49:45.557Z" }, - { url = "https://files.pythonhosted.org/packages/0f/f1/fcc24137c470df8588674a677f33719d5800ec053aaacd1de8a5d5d84d9e/rpds_py-0.29.0-cp314-cp314-win32.whl", hash = "sha256:f475f103488312e9bd4000bc890a95955a07b2d0b6e8884aef4be56132adbbf1", size = 215508, upload-time = "2025-11-16T14:49:47.562Z" }, - { url = "https://files.pythonhosted.org/packages/7b/c7/1d169b2045512eac019918fc1021ea07c30e84a4343f9f344e3e0aa8c788/rpds_py-0.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:b9cf2359a4fca87cfb6801fae83a76aedf66ee1254a7a151f1341632acf67f1b", size = 228125, upload-time = "2025-11-16T14:49:49.064Z" }, - { url = "https://files.pythonhosted.org/packages/be/36/0cec88aaba70ec4a6e381c444b0d916738497d27f0c30406e3d9fcbd3bc2/rpds_py-0.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:9ba8028597e824854f0f1733d8b964e914ae3003b22a10c2c664cb6927e0feb9", size = 221992, upload-time = "2025-11-16T14:49:50.777Z" }, - { url = "https://files.pythonhosted.org/packages/b1/fa/a2e524631717c9c0eb5d90d30f648cfba6b731047821c994acacb618406c/rpds_py-0.29.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e71136fd0612556b35c575dc2726ae04a1669e6a6c378f2240312cf5d1a2ab10", size = 366425, upload-time = "2025-11-16T14:49:52.691Z" }, - { url = "https://files.pythonhosted.org/packages/a2/a4/6d43ebe0746ff694a30233f63f454aed1677bd50ab7a59ff6b2bb5ac61f2/rpds_py-0.29.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:76fe96632d53f3bf0ea31ede2f53bbe3540cc2736d4aec3b3801b0458499ef3a", size = 355282, upload-time = "2025-11-16T14:49:54.292Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a7/52fd8270e0320b09eaf295766ae81dd175f65394687906709b3e75c71d06/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9459a33f077130dbb2c7c3cea72ee9932271fb3126404ba2a2661e4fe9eb7b79", size = 384968, upload-time = "2025-11-16T14:49:55.857Z" }, - { url = "https://files.pythonhosted.org/packages/f4/7d/e6bc526b7a14e1ef80579a52c1d4ad39260a058a51d66c6039035d14db9d/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5c9546cfdd5d45e562cc0444b6dddc191e625c62e866bf567a2c69487c7ad28a", size = 394714, upload-time = "2025-11-16T14:49:57.343Z" }, - { url = "https://files.pythonhosted.org/packages/c0/3f/f0ade3954e7db95c791e7eaf978aa7e08a756d2046e8bdd04d08146ed188/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12597d11d97b8f7e376c88929a6e17acb980e234547c92992f9f7c058f1a7310", size = 520136, upload-time = "2025-11-16T14:49:59.162Z" }, - { url = "https://files.pythonhosted.org/packages/87/b3/07122ead1b97009715ab9d4082be6d9bd9546099b2b03fae37c3116f72be/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28de03cf48b8a9e6ec10318f2197b83946ed91e2891f651a109611be4106ac4b", size = 409250, upload-time = "2025-11-16T14:50:00.698Z" }, - { url = "https://files.pythonhosted.org/packages/c9/c6/dcbee61fd1dc892aedcb1b489ba661313101aa82ec84b1a015d4c63ebfda/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd7951c964069039acc9d67a8ff1f0a7f34845ae180ca542b17dc1456b1f1808", size = 384940, upload-time = "2025-11-16T14:50:02.312Z" }, - { url = "https://files.pythonhosted.org/packages/47/11/914ecb6f3574cf9bf8b38aced4063e0f787d6e1eb30b181a7efbc6c1da9a/rpds_py-0.29.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:c07d107b7316088f1ac0177a7661ca0c6670d443f6fe72e836069025e6266761", size = 399392, upload-time = "2025-11-16T14:50:03.829Z" }, - { url = "https://files.pythonhosted.org/packages/f5/fd/2f4bd9433f58f816434bb934313584caa47dbc6f03ce5484df8ac8980561/rpds_py-0.29.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de2345af363d25696969befc0c1688a6cb5e8b1d32b515ef84fc245c6cddba3", size = 416796, upload-time = "2025-11-16T14:50:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/79/a5/449f0281af33efa29d5c71014399d74842342ae908d8cd38260320167692/rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:00e56b12d2199ca96068057e1ae7f9998ab6e99cda82431afafd32f3ec98cca9", size = 566843, upload-time = "2025-11-16T14:50:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/ab/32/0a6a1ccee2e37fcb1b7ba9afde762b77182dbb57937352a729c6cd3cf2bb/rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3919a3bbecee589300ed25000b6944174e07cd20db70552159207b3f4bbb45b8", size = 593956, upload-time = "2025-11-16T14:50:09.029Z" }, - { url = "https://files.pythonhosted.org/packages/4a/3d/eb820f95dce4306f07a495ede02fb61bef36ea201d9137d4fcd5ab94ec1e/rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7fa2ccc312bbd91e43aa5e0869e46bc03278a3dddb8d58833150a18b0f0283a", size = 557288, upload-time = "2025-11-16T14:50:10.73Z" }, - { url = "https://files.pythonhosted.org/packages/e9/f8/b8ff786f40470462a252918e0836e0db903c28e88e3eec66bc4a7856ee5d/rpds_py-0.29.0-cp314-cp314t-win32.whl", hash = "sha256:97c817863ffc397f1e6a6e9d2d89fe5408c0a9922dac0329672fb0f35c867ea5", size = 211382, upload-time = "2025-11-16T14:50:12.827Z" }, - { url = "https://files.pythonhosted.org/packages/c9/7f/1a65ae870bc9d0576aebb0c501ea5dccf1ae2178fe2821042150ebd2e707/rpds_py-0.29.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2023473f444752f0f82a58dfcbee040d0a1b3d1b3c2ec40e884bd25db6d117d2", size = 225919, upload-time = "2025-11-16T14:50:14.734Z" }, - { url = "https://files.pythonhosted.org/packages/f2/ac/b97e80bf107159e5b9ba9c91df1ab95f69e5e41b435f27bdd737f0d583ac/rpds_py-0.29.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:acd82a9e39082dc5f4492d15a6b6c8599aa21db5c35aaf7d6889aea16502c07d", size = 373963, upload-time = "2025-11-16T14:50:16.205Z" }, - { url = "https://files.pythonhosted.org/packages/40/5a/55e72962d5d29bd912f40c594e68880d3c7a52774b0f75542775f9250712/rpds_py-0.29.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:715b67eac317bf1c7657508170a3e011a1ea6ccb1c9d5f296e20ba14196be6b3", size = 364644, upload-time = "2025-11-16T14:50:18.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/2a/6b6524d0191b7fc1351c3c0840baac42250515afb48ae40c7ed15499a6a2/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3b1b87a237cb2dba4db18bcfaaa44ba4cd5936b91121b62292ff21df577fc43", size = 393847, upload-time = "2025-11-16T14:50:20.012Z" }, - { url = "https://files.pythonhosted.org/packages/1c/b8/c5692a7df577b3c0c7faed7ac01ee3c608b81750fc5d89f84529229b6873/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1c3c3e8101bb06e337c88eb0c0ede3187131f19d97d43ea0e1c5407ea74c0cbf", size = 407281, upload-time = "2025-11-16T14:50:21.64Z" }, - { url = "https://files.pythonhosted.org/packages/f0/57/0546c6f84031b7ea08b76646a8e33e45607cc6bd879ff1917dc077bb881e/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8e54d6e61f3ecd3abe032065ce83ea63417a24f437e4a3d73d2f85ce7b7cfe", size = 529213, upload-time = "2025-11-16T14:50:23.219Z" }, - { url = "https://files.pythonhosted.org/packages/fa/c1/01dd5f444233605555bc11fe5fed6a5c18f379f02013870c176c8e630a23/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3fbd4e9aebf110473a420dea85a238b254cf8a15acb04b22a5a6b5ce8925b760", size = 413808, upload-time = "2025-11-16T14:50:25.262Z" }, - { url = "https://files.pythonhosted.org/packages/aa/0a/60f98b06156ea2a7af849fb148e00fbcfdb540909a5174a5ed10c93745c7/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fdf53d36e6c72819993e35d1ebeeb8e8fc688d0c6c2b391b55e335b3afba5a", size = 394600, upload-time = "2025-11-16T14:50:26.956Z" }, - { url = "https://files.pythonhosted.org/packages/37/f1/dc9312fc9bec040ece08396429f2bd9e0977924ba7a11c5ad7056428465e/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:ea7173df5d86f625f8dde6d5929629ad811ed8decda3b60ae603903839ac9ac0", size = 408634, upload-time = "2025-11-16T14:50:28.989Z" }, - { url = "https://files.pythonhosted.org/packages/ed/41/65024c9fd40c89bb7d604cf73beda4cbdbcebe92d8765345dd65855b6449/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:76054d540061eda273274f3d13a21a4abdde90e13eaefdc205db37c05230efce", size = 426064, upload-time = "2025-11-16T14:50:30.674Z" }, - { url = "https://files.pythonhosted.org/packages/a2/e0/cf95478881fc88ca2fdbf56381d7df36567cccc39a05394beac72182cd62/rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f84c549746a5be3bc7415830747a3a0312573afc9f95785eb35228bb17742ec", size = 575871, upload-time = "2025-11-16T14:50:33.428Z" }, - { url = "https://files.pythonhosted.org/packages/ea/c0/df88097e64339a0218b57bd5f9ca49898e4c394db756c67fccc64add850a/rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:0ea962671af5cb9a260489e311fa22b2e97103e3f9f0caaea6f81390af96a9ed", size = 601702, upload-time = "2025-11-16T14:50:36.051Z" }, - { url = "https://files.pythonhosted.org/packages/87/f4/09ffb3ebd0cbb9e2c7c9b84d252557ecf434cd71584ee1e32f66013824df/rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f7728653900035fb7b8d06e1e5900545d8088efc9d5d4545782da7df03ec803f", size = 564054, upload-time = "2025-11-16T14:50:37.733Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/98/33/23b3b3419b6a3e0f559c7c0d2ca8fc1b9448382b25245033788785921332/rpds_py-0.29.0.tar.gz", hash = "sha256:fe55fe686908f50154d1dc599232016e50c243b438c3b7432f24e2895b0e5359", size = 69359 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/7a/c5b2ff381b74bc742768e8d870f26babac4ef256ba160bdbf8d57af56461/rpds_py-0.29.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4ae4b88c6617e1b9e5038ab3fccd7bac0842fdda2b703117b2aa99bc85379113", size = 372385 }, + { url = "https://files.pythonhosted.org/packages/28/36/531f1eb4d5bed4a9c150f363a7ec4a98d2dc746151bba5473bc38ee85dec/rpds_py-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7d9128ec9d8cecda6f044001fde4fb71ea7c24325336612ef8179091eb9596b9", size = 362869 }, + { url = "https://files.pythonhosted.org/packages/54/df/7e9c0493a2015d9c82807a2d5f023ea9774e27a4c15b33ef1cdb7456138d/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37812c3da8e06f2bb35b3cf10e4a7b68e776a706c13058997238762b4e07f4f", size = 391582 }, + { url = "https://files.pythonhosted.org/packages/15/38/42a981c3592ef46fbd7e17adbf8730cc5ec87e6aa1770c658c44bbb52960/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66786c3fb1d8de416a7fa8e1cb1ec6ba0a745b2b0eee42f9b7daa26f1a495545", size = 405685 }, + { url = "https://files.pythonhosted.org/packages/12/45/628b8c15856c3849c3f52ec6dac93c046ed5faeed4a435af03b70525fd29/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58f5c77f1af888b5fd1876c9a0d9858f6f88a39c9dd7c073a88e57e577da66d", size = 527067 }, + { url = "https://files.pythonhosted.org/packages/dc/ba/6b56d09badeabd95098016d72a437d4a0fd82d4672ce92a7607df5d70a42/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:799156ef1f3529ed82c36eb012b5d7a4cf4b6ef556dd7cc192148991d07206ae", size = 412532 }, + { url = "https://files.pythonhosted.org/packages/f1/39/2f1f3db92888314b50b8f9641f679188bd24b3665a8cb9923b7201ae8011/rpds_py-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:453783477aa4f2d9104c4b59b08c871431647cb7af51b549bbf2d9eb9c827756", size = 392736 }, + { url = "https://files.pythonhosted.org/packages/60/43/3c3b1dcd827e50f2ae28786d846b8a351080d8a69a3b49bc10ae44cc39b1/rpds_py-0.29.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:24a7231493e3c4a4b30138b50cca089a598e52c34cf60b2f35cebf62f274fdea", size = 406300 }, + { url = "https://files.pythonhosted.org/packages/da/02/bc96021b67f8525e6bcdd68935c4543ada61e1f3dcb067ed037d68b8c6d2/rpds_py-0.29.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7033c1010b1f57bb44d8067e8c25aa6fa2e944dbf46ccc8c92b25043839c3fd2", size = 423641 }, + { url = "https://files.pythonhosted.org/packages/38/e9/c435ddb602ced19a80b8277a41371734f33ad3f91cc4ceb4d82596800a3c/rpds_py-0.29.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0248b19405422573621172ab8e3a1f29141362d13d9f72bafa2e28ea0cdca5a2", size = 574153 }, + { url = "https://files.pythonhosted.org/packages/84/82/dc3c32e1f89ecba8a59600d4cd65fe0ad81b6c636ccdbf6cd177fd6a7bac/rpds_py-0.29.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f9f436aee28d13b9ad2c764fc273e0457e37c2e61529a07b928346b219fcde3b", size = 600304 }, + { url = "https://files.pythonhosted.org/packages/35/98/785290e0b7142470735dc1b1f68fb33aae29e5296f062c88396eedf796c8/rpds_py-0.29.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24a16cb7163933906c62c272de20ea3c228e4542c8c45c1d7dc2b9913e17369a", size = 562211 }, + { url = "https://files.pythonhosted.org/packages/30/58/4eeddcb0737c6875f3e30c65dc9d7e7a10dfd5779646a990fa602c6d56c5/rpds_py-0.29.0-cp310-cp310-win32.whl", hash = "sha256:1a409b0310a566bfd1be82119891fefbdce615ccc8aa558aff7835c27988cbef", size = 221803 }, + { url = "https://files.pythonhosted.org/packages/54/77/b35a8dbdcbeb32505500547cdafaa9f8863e85f8faac50ef34464ec5a256/rpds_py-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5523b0009e7c3c1263471b69d8da1c7d41b3ecb4cb62ef72be206b92040a950", size = 235530 }, + { url = "https://files.pythonhosted.org/packages/36/ab/7fb95163a53ab122c74a7c42d2d2f012819af2cf3deb43fb0d5acf45cc1a/rpds_py-0.29.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b9c764a11fd637e0322a488560533112837f5334ffeb48b1be20f6d98a7b437", size = 372344 }, + { url = "https://files.pythonhosted.org/packages/b3/45/f3c30084c03b0d0f918cb4c5ae2c20b0a148b51ba2b3f6456765b629bedd/rpds_py-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fd2164d73812026ce970d44c3ebd51e019d2a26a4425a5dcbdfa93a34abc383", size = 363041 }, + { url = "https://files.pythonhosted.org/packages/e3/e9/4d044a1662608c47a87cbb37b999d4d5af54c6d6ebdda93a4d8bbf8b2a10/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a097b7f7f7274164566ae90a221fd725363c0e9d243e2e9ed43d195ccc5495c", size = 391775 }, + { url = "https://files.pythonhosted.org/packages/50/c9/7616d3ace4e6731aeb6e3cd85123e03aec58e439044e214b9c5c60fd8eb1/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cdc0490374e31cedefefaa1520d5fe38e82fde8748cbc926e7284574c714d6b", size = 405624 }, + { url = "https://files.pythonhosted.org/packages/c2/e2/6d7d6941ca0843609fd2d72c966a438d6f22617baf22d46c3d2156c31350/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89ca2e673ddd5bde9b386da9a0aac0cab0e76f40c8f0aaf0d6311b6bbf2aa311", size = 527894 }, + { url = "https://files.pythonhosted.org/packages/8d/f7/aee14dc2db61bb2ae1e3068f134ca9da5f28c586120889a70ff504bb026f/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5d9da3ff5af1ca1249b1adb8ef0573b94c76e6ae880ba1852f033bf429d4588", size = 412720 }, + { url = "https://files.pythonhosted.org/packages/2f/e2/2293f236e887c0360c2723d90c00d48dee296406994d6271faf1712e94ec/rpds_py-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8238d1d310283e87376c12f658b61e1ee23a14c0e54c7c0ce953efdbdc72deed", size = 392945 }, + { url = "https://files.pythonhosted.org/packages/14/cd/ceea6147acd3bd1fd028d1975228f08ff19d62098078d5ec3eed49703797/rpds_py-0.29.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:2d6fb2ad1c36f91c4646989811e84b1ea5e0c3cf9690b826b6e32b7965853a63", size = 406385 }, + { url = "https://files.pythonhosted.org/packages/52/36/fe4dead19e45eb77a0524acfdbf51e6cda597b26fc5b6dddbff55fbbb1a5/rpds_py-0.29.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:534dc9df211387547267ccdb42253aa30527482acb38dd9b21c5c115d66a96d2", size = 423943 }, + { url = "https://files.pythonhosted.org/packages/a1/7b/4551510803b582fa4abbc8645441a2d15aa0c962c3b21ebb380b7e74f6a1/rpds_py-0.29.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d456e64724a075441e4ed648d7f154dc62e9aabff29bcdf723d0c00e9e1d352f", size = 574204 }, + { url = "https://files.pythonhosted.org/packages/64/ba/071ccdd7b171e727a6ae079f02c26f75790b41555f12ca8f1151336d2124/rpds_py-0.29.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a738f2da2f565989401bd6fd0b15990a4d1523c6d7fe83f300b7e7d17212feca", size = 600587 }, + { url = "https://files.pythonhosted.org/packages/03/09/96983d48c8cf5a1e03c7d9cc1f4b48266adfb858ae48c7c2ce978dbba349/rpds_py-0.29.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a110e14508fd26fd2e472bb541f37c209409876ba601cf57e739e87d8a53cf95", size = 562287 }, + { url = "https://files.pythonhosted.org/packages/40/f0/8c01aaedc0fa92156f0391f39ea93b5952bc0ec56b897763858f95da8168/rpds_py-0.29.0-cp311-cp311-win32.whl", hash = "sha256:923248a56dd8d158389a28934f6f69ebf89f218ef96a6b216a9be6861804d3f4", size = 221394 }, + { url = "https://files.pythonhosted.org/packages/7e/a5/a8b21c54c7d234efdc83dc034a4d7cd9668e3613b6316876a29b49dece71/rpds_py-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:539eb77eb043afcc45314d1be09ea6d6cafb3addc73e0547c171c6d636957f60", size = 235713 }, + { url = "https://files.pythonhosted.org/packages/a7/1f/df3c56219523947b1be402fa12e6323fe6d61d883cf35d6cb5d5bb6db9d9/rpds_py-0.29.0-cp311-cp311-win_arm64.whl", hash = "sha256:bdb67151ea81fcf02d8f494703fb728d4d34d24556cbff5f417d74f6f5792e7c", size = 229157 }, + { url = "https://files.pythonhosted.org/packages/3c/50/bc0e6e736d94e420df79be4deb5c9476b63165c87bb8f19ef75d100d21b3/rpds_py-0.29.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0891cfd8db43e085c0ab93ab7e9b0c8fee84780d436d3b266b113e51e79f954", size = 376000 }, + { url = "https://files.pythonhosted.org/packages/3e/3a/46676277160f014ae95f24de53bed0e3b7ea66c235e7de0b9df7bd5d68ba/rpds_py-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3897924d3f9a0361472d884051f9a2460358f9a45b1d85a39a158d2f8f1ad71c", size = 360575 }, + { url = "https://files.pythonhosted.org/packages/75/ba/411d414ed99ea1afdd185bbabeeaac00624bd1e4b22840b5e9967ade6337/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21deb8e0d1571508c6491ce5ea5e25669b1dd4adf1c9d64b6314842f708b5d", size = 392159 }, + { url = "https://files.pythonhosted.org/packages/8f/b1/e18aa3a331f705467a48d0296778dc1fea9d7f6cf675bd261f9a846c7e90/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9efe71687d6427737a0a2de9ca1c0a216510e6cd08925c44162be23ed7bed2d5", size = 410602 }, + { url = "https://files.pythonhosted.org/packages/2f/6c/04f27f0c9f2299274c76612ac9d2c36c5048bb2c6c2e52c38c60bf3868d9/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40f65470919dc189c833e86b2c4bd21bd355f98436a2cef9e0a9a92aebc8e57e", size = 515808 }, + { url = "https://files.pythonhosted.org/packages/83/56/a8412aa464fb151f8bc0d91fb0bb888adc9039bd41c1c6ba8d94990d8cf8/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:def48ff59f181130f1a2cb7c517d16328efac3ec03951cca40c1dc2049747e83", size = 416015 }, + { url = "https://files.pythonhosted.org/packages/04/4c/f9b8a05faca3d9e0a6397c90d13acb9307c9792b2bff621430c58b1d6e76/rpds_py-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7bd570be92695d89285a4b373006930715b78d96449f686af422debb4d3949", size = 395325 }, + { url = "https://files.pythonhosted.org/packages/34/60/869f3bfbf8ed7b54f1ad9a5543e0fdffdd40b5a8f587fe300ee7b4f19340/rpds_py-0.29.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:5a572911cd053137bbff8e3a52d31c5d2dba51d3a67ad902629c70185f3f2181", size = 410160 }, + { url = "https://files.pythonhosted.org/packages/91/aa/e5b496334e3aba4fe4c8a80187b89f3c1294c5c36f2a926da74338fa5a73/rpds_py-0.29.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d583d4403bcbf10cffc3ab5cee23d7643fcc960dff85973fd3c2d6c86e8dbb0c", size = 425309 }, + { url = "https://files.pythonhosted.org/packages/85/68/4e24a34189751ceb6d66b28f18159922828dd84155876551f7ca5b25f14f/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:070befbb868f257d24c3bb350dbd6e2f645e83731f31264b19d7231dd5c396c7", size = 574644 }, + { url = "https://files.pythonhosted.org/packages/8c/cf/474a005ea4ea9c3b4f17b6108b6b13cebfc98ebaff11d6e1b193204b3a93/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fc935f6b20b0c9f919a8ff024739174522abd331978f750a74bb68abd117bd19", size = 601605 }, + { url = "https://files.pythonhosted.org/packages/f4/b1/c56f6a9ab8c5f6bb5c65c4b5f8229167a3a525245b0773f2c0896686b64e/rpds_py-0.29.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c5a8ecaa44ce2d8d9d20a68a2483a74c07f05d72e94a4dff88906c8807e77b0", size = 564593 }, + { url = "https://files.pythonhosted.org/packages/b3/13/0494cecce4848f68501e0a229432620b4b57022388b071eeff95f3e1e75b/rpds_py-0.29.0-cp312-cp312-win32.whl", hash = "sha256:ba5e1aeaf8dd6d8f6caba1f5539cddda87d511331714b7b5fc908b6cfc3636b7", size = 223853 }, + { url = "https://files.pythonhosted.org/packages/1f/6a/51e9aeb444a00cdc520b032a28b07e5f8dc7bc328b57760c53e7f96997b4/rpds_py-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:b5f6134faf54b3cb83375db0f113506f8b7770785be1f95a631e7e2892101977", size = 239895 }, + { url = "https://files.pythonhosted.org/packages/d1/d4/8bce56cdad1ab873e3f27cb31c6a51d8f384d66b022b820525b879f8bed1/rpds_py-0.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:b016eddf00dca7944721bf0cd85b6af7f6c4efaf83ee0b37c4133bd39757a8c7", size = 230321 }, + { url = "https://files.pythonhosted.org/packages/fd/d9/c5de60d9d371bbb186c3e9bf75f4fc5665e11117a25a06a6b2e0afb7380e/rpds_py-0.29.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1585648d0760b88292eecab5181f5651111a69d90eff35d6b78aa32998886a61", size = 375710 }, + { url = "https://files.pythonhosted.org/packages/b3/b3/0860cdd012291dc21272895ce107f1e98e335509ba986dd83d72658b82b9/rpds_py-0.29.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:521807963971a23996ddaf764c682b3e46459b3c58ccd79fefbe16718db43154", size = 360582 }, + { url = "https://files.pythonhosted.org/packages/92/8a/a18c2f4a61b3407e56175f6aab6deacdf9d360191a3d6f38566e1eaf7266/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8896986efaa243ab713c69e6491a4138410f0fe36f2f4c71e18bd5501e8014", size = 391172 }, + { url = "https://files.pythonhosted.org/packages/fd/49/e93354258508c50abc15cdcd5fcf7ac4117f67bb6233ad7859f75e7372a0/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d24564a700ef41480a984c5ebed62b74e6ce5860429b98b1fede76049e953e6", size = 409586 }, + { url = "https://files.pythonhosted.org/packages/5a/8d/a27860dae1c19a6bdc901f90c81f0d581df1943355802961a57cdb5b6cd1/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6596b93c010d386ae46c9fba9bfc9fc5965fa8228edeac51576299182c2e31c", size = 516339 }, + { url = "https://files.pythonhosted.org/packages/fc/ad/a75e603161e79b7110c647163d130872b271c6b28712c803c65d492100f7/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5cc58aac218826d054c7da7f95821eba94125d88be673ff44267bb89d12a5866", size = 416201 }, + { url = "https://files.pythonhosted.org/packages/b9/42/555b4ee17508beafac135c8b450816ace5a96194ce97fefc49d58e5652ea/rpds_py-0.29.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de73e40ebc04dd5d9556f50180395322193a78ec247e637e741c1b954810f295", size = 395095 }, + { url = "https://files.pythonhosted.org/packages/cd/f0/c90b671b9031e800ec45112be42ea9f027f94f9ac25faaac8770596a16a1/rpds_py-0.29.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:295ce5ac7f0cf69a651ea75c8f76d02a31f98e5698e82a50a5f4d4982fbbae3b", size = 410077 }, + { url = "https://files.pythonhosted.org/packages/3d/80/9af8b640b81fe21e6f718e9dec36c0b5f670332747243130a5490f292245/rpds_py-0.29.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ea59b23ea931d494459c8338056fe7d93458c0bf3ecc061cd03916505369d55", size = 424548 }, + { url = "https://files.pythonhosted.org/packages/e4/0b/b5647446e991736e6a495ef510e6710df91e880575a586e763baeb0aa770/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f49d41559cebd608042fdcf54ba597a4a7555b49ad5c1c0c03e0af82692661cd", size = 573661 }, + { url = "https://files.pythonhosted.org/packages/f7/b3/1b1c9576839ff583d1428efbf59f9ee70498d8ce6c0b328ac02f1e470879/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:05a2bd42768ea988294ca328206efbcc66e220d2d9b7836ee5712c07ad6340ea", size = 600937 }, + { url = "https://files.pythonhosted.org/packages/6c/7b/b6cfca2f9fee4c4494ce54f7fb1b9f578867495a9aa9fc0d44f5f735c8e0/rpds_py-0.29.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33ca7bdfedd83339ca55da3a5e1527ee5870d4b8369456b5777b197756f3ca22", size = 564496 }, + { url = "https://files.pythonhosted.org/packages/b9/fb/ba29ec7f0f06eb801bac5a23057a9ff7670623b5e8013bd59bec4aa09de8/rpds_py-0.29.0-cp313-cp313-win32.whl", hash = "sha256:20c51ae86a0bb9accc9ad4e6cdeec58d5ebb7f1b09dd4466331fc65e1766aae7", size = 223126 }, + { url = "https://files.pythonhosted.org/packages/3c/6b/0229d3bed4ddaa409e6d90b0ae967ed4380e4bdd0dad6e59b92c17d42457/rpds_py-0.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:6410e66f02803600edb0b1889541f4b5cc298a5ccda0ad789cc50ef23b54813e", size = 239771 }, + { url = "https://files.pythonhosted.org/packages/e4/38/d2868f058b164f8efd89754d85d7b1c08b454f5c07ac2e6cc2e9bd4bd05b/rpds_py-0.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:56838e1cd9174dc23c5691ee29f1d1be9eab357f27efef6bded1328b23e1ced2", size = 229994 }, + { url = "https://files.pythonhosted.org/packages/52/91/5de91c5ec7d41759beec9b251630824dbb8e32d20c3756da1a9a9d309709/rpds_py-0.29.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:37d94eadf764d16b9a04307f2ab1d7af6dc28774bbe0535c9323101e14877b4c", size = 365886 }, + { url = "https://files.pythonhosted.org/packages/85/7c/415d8c1b016d5f47ecec5145d9d6d21002d39dce8761b30f6c88810b455a/rpds_py-0.29.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d472cf73efe5726a067dce63eebe8215b14beabea7c12606fd9994267b3cfe2b", size = 355262 }, + { url = "https://files.pythonhosted.org/packages/3d/14/bf83e2daa4f980e4dc848aed9299792a8b84af95e12541d9e7562f84a6ef/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72fdfd5ff8992e4636621826371e3ac5f3e3b8323e9d0e48378e9c13c3dac9d0", size = 384826 }, + { url = "https://files.pythonhosted.org/packages/33/b8/53330c50a810ae22b4fbba5e6cf961b68b9d72d9bd6780a7c0a79b070857/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2549d833abdf8275c901313b9e8ff8fba57e50f6a495035a2a4e30621a2f7cc4", size = 394234 }, + { url = "https://files.pythonhosted.org/packages/cc/32/01e2e9645cef0e584f518cfde4567563e57db2257244632b603f61b40e50/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4448dad428f28a6a767c3e3b80cde3446a22a0efbddaa2360f4bb4dc836d0688", size = 520008 }, + { url = "https://files.pythonhosted.org/packages/98/c3/0d1b95a81affae2b10f950782e33a1fd2edd6ce2a479966cac98c9a66f57/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:115f48170fd4296a33938d8c11f697f5f26e0472e43d28f35624764173a60e4d", size = 409569 }, + { url = "https://files.pythonhosted.org/packages/fa/60/aa3b8678f3f009f675b99174fa2754302a7fbfe749162e8043d111de2d88/rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e5bb73ffc029820f4348e9b66b3027493ae00bca6629129cd433fd7a76308ee", size = 385188 }, + { url = "https://files.pythonhosted.org/packages/92/02/5546c1c8aa89c18d40c1fcffdcc957ba730dee53fb7c3ca3a46f114761d2/rpds_py-0.29.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:b1581fcde18fcdf42ea2403a16a6b646f8eb1e58d7f90a0ce693da441f76942e", size = 398587 }, + { url = "https://files.pythonhosted.org/packages/6c/e0/ad6eeaf47e236eba052fa34c4073078b9e092bd44da6bbb35aaae9580669/rpds_py-0.29.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16e9da2bda9eb17ea318b4c335ec9ac1818e88922cbe03a5743ea0da9ecf74fb", size = 416641 }, + { url = "https://files.pythonhosted.org/packages/1a/93/0acedfd50ad9cdd3879c615a6dc8c5f1ce78d2fdf8b87727468bb5bb4077/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:28fd300326dd21198f311534bdb6d7e989dd09b3418b3a91d54a0f384c700967", size = 566683 }, + { url = "https://files.pythonhosted.org/packages/62/53/8c64e0f340a9e801459fc6456821abc15b3582cb5dc3932d48705a9d9ac7/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2aba991e041d031c7939e1358f583ae405a7bf04804ca806b97a5c0e0af1ea5e", size = 592730 }, + { url = "https://files.pythonhosted.org/packages/85/ef/3109b6584f8c4b0d2490747c916df833c127ecfa82be04d9a40a376f2090/rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f437026dbbc3f08c99cc41a5b2570c6e1a1ddbe48ab19a9b814254128d4ea7a", size = 557361 }, + { url = "https://files.pythonhosted.org/packages/ff/3b/61586475e82d57f01da2c16edb9115a618afe00ce86fe1b58936880b15af/rpds_py-0.29.0-cp313-cp313t-win32.whl", hash = "sha256:6e97846e9800a5d0fe7be4d008f0c93d0feeb2700da7b1f7528dabafb31dfadb", size = 211227 }, + { url = "https://files.pythonhosted.org/packages/3b/3a/12dc43f13594a54ea0c9d7e9d43002116557330e3ad45bc56097ddf266e2/rpds_py-0.29.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f49196aec7c4b406495f60e6f947ad71f317a765f956d74bbd83996b9edc0352", size = 225248 }, + { url = "https://files.pythonhosted.org/packages/89/b1/0b1474e7899371d9540d3bbb2a499a3427ae1fc39c998563fe9035a1073b/rpds_py-0.29.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:394d27e4453d3b4d82bb85665dc1fcf4b0badc30fc84282defed71643b50e1a1", size = 363731 }, + { url = "https://files.pythonhosted.org/packages/28/12/3b7cf2068d0a334ed1d7b385a9c3c8509f4c2bcba3d4648ea71369de0881/rpds_py-0.29.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55d827b2ae95425d3be9bc9a5838b6c29d664924f98146557f7715e331d06df8", size = 354343 }, + { url = "https://files.pythonhosted.org/packages/eb/73/5afcf8924bc02a749416eda64e17ac9c9b28f825f4737385295a0e99b0c1/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc31a07ed352e5462d3ee1b22e89285f4ce97d5266f6d1169da1142e78045626", size = 385406 }, + { url = "https://files.pythonhosted.org/packages/c8/37/5db736730662508535221737a21563591b6f43c77f2e388951c42f143242/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4695dd224212f6105db7ea62197144230b808d6b2bba52238906a2762f1d1e7", size = 396162 }, + { url = "https://files.pythonhosted.org/packages/70/0d/491c1017d14f62ce7bac07c32768d209a50ec567d76d9f383b4cfad19b80/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcae1770b401167f8b9e1e3f566562e6966ffa9ce63639916248a9e25fa8a244", size = 517719 }, + { url = "https://files.pythonhosted.org/packages/d7/25/b11132afcb17cd5d82db173f0c8dab270ffdfaba43e5ce7a591837ae9649/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90f30d15f45048448b8da21c41703b31c61119c06c216a1bf8c245812a0f0c17", size = 409498 }, + { url = "https://files.pythonhosted.org/packages/0f/7d/e6543cedfb2e6403a1845710a5ab0e0ccf8fc288e0b5af9a70bfe2c12053/rpds_py-0.29.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a91e0ab77bdc0004b43261a4b8cd6d6b451e8d443754cfda830002b5745b32", size = 382743 }, + { url = "https://files.pythonhosted.org/packages/75/11/a4ebc9f654293ae9fefb83b2b6be7f3253e85ea42a5db2f77d50ad19aaeb/rpds_py-0.29.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:4aa195e5804d32c682e453b34474f411ca108e4291c6a0f824ebdc30a91c973c", size = 400317 }, + { url = "https://files.pythonhosted.org/packages/52/18/97677a60a81c7f0e5f64e51fb3f8271c5c8fcabf3a2df18e97af53d7c2bf/rpds_py-0.29.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7971bdb7bf4ee0f7e6f67fa4c7fbc6019d9850cc977d126904392d363f6f8318", size = 416979 }, + { url = "https://files.pythonhosted.org/packages/f0/69/28ab391a9968f6c746b2a2db181eaa4d16afaa859fedc9c2f682d19f7e18/rpds_py-0.29.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8ae33ad9ce580c7a47452c3b3f7d8a9095ef6208e0a0c7e4e2384f9fc5bf8212", size = 567288 }, + { url = "https://files.pythonhosted.org/packages/3b/d3/0c7afdcdb830eee94f5611b64e71354ffe6ac8df82d00c2faf2bfffd1d4e/rpds_py-0.29.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c661132ab2fb4eeede2ef69670fd60da5235209874d001a98f1542f31f2a8a94", size = 593157 }, + { url = "https://files.pythonhosted.org/packages/e2/ac/a0fcbc2feed4241cf26d32268c195eb88ddd4bd862adfc9d4b25edfba535/rpds_py-0.29.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb78b3a0d31ac1bde132c67015a809948db751cb4e92cdb3f0b242e430b6ed0d", size = 554741 }, + { url = "https://files.pythonhosted.org/packages/0f/f1/fcc24137c470df8588674a677f33719d5800ec053aaacd1de8a5d5d84d9e/rpds_py-0.29.0-cp314-cp314-win32.whl", hash = "sha256:f475f103488312e9bd4000bc890a95955a07b2d0b6e8884aef4be56132adbbf1", size = 215508 }, + { url = "https://files.pythonhosted.org/packages/7b/c7/1d169b2045512eac019918fc1021ea07c30e84a4343f9f344e3e0aa8c788/rpds_py-0.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:b9cf2359a4fca87cfb6801fae83a76aedf66ee1254a7a151f1341632acf67f1b", size = 228125 }, + { url = "https://files.pythonhosted.org/packages/be/36/0cec88aaba70ec4a6e381c444b0d916738497d27f0c30406e3d9fcbd3bc2/rpds_py-0.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:9ba8028597e824854f0f1733d8b964e914ae3003b22a10c2c664cb6927e0feb9", size = 221992 }, + { url = "https://files.pythonhosted.org/packages/b1/fa/a2e524631717c9c0eb5d90d30f648cfba6b731047821c994acacb618406c/rpds_py-0.29.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e71136fd0612556b35c575dc2726ae04a1669e6a6c378f2240312cf5d1a2ab10", size = 366425 }, + { url = "https://files.pythonhosted.org/packages/a2/a4/6d43ebe0746ff694a30233f63f454aed1677bd50ab7a59ff6b2bb5ac61f2/rpds_py-0.29.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:76fe96632d53f3bf0ea31ede2f53bbe3540cc2736d4aec3b3801b0458499ef3a", size = 355282 }, + { url = "https://files.pythonhosted.org/packages/fa/a7/52fd8270e0320b09eaf295766ae81dd175f65394687906709b3e75c71d06/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9459a33f077130dbb2c7c3cea72ee9932271fb3126404ba2a2661e4fe9eb7b79", size = 384968 }, + { url = "https://files.pythonhosted.org/packages/f4/7d/e6bc526b7a14e1ef80579a52c1d4ad39260a058a51d66c6039035d14db9d/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5c9546cfdd5d45e562cc0444b6dddc191e625c62e866bf567a2c69487c7ad28a", size = 394714 }, + { url = "https://files.pythonhosted.org/packages/c0/3f/f0ade3954e7db95c791e7eaf978aa7e08a756d2046e8bdd04d08146ed188/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12597d11d97b8f7e376c88929a6e17acb980e234547c92992f9f7c058f1a7310", size = 520136 }, + { url = "https://files.pythonhosted.org/packages/87/b3/07122ead1b97009715ab9d4082be6d9bd9546099b2b03fae37c3116f72be/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28de03cf48b8a9e6ec10318f2197b83946ed91e2891f651a109611be4106ac4b", size = 409250 }, + { url = "https://files.pythonhosted.org/packages/c9/c6/dcbee61fd1dc892aedcb1b489ba661313101aa82ec84b1a015d4c63ebfda/rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd7951c964069039acc9d67a8ff1f0a7f34845ae180ca542b17dc1456b1f1808", size = 384940 }, + { url = "https://files.pythonhosted.org/packages/47/11/914ecb6f3574cf9bf8b38aced4063e0f787d6e1eb30b181a7efbc6c1da9a/rpds_py-0.29.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:c07d107b7316088f1ac0177a7661ca0c6670d443f6fe72e836069025e6266761", size = 399392 }, + { url = "https://files.pythonhosted.org/packages/f5/fd/2f4bd9433f58f816434bb934313584caa47dbc6f03ce5484df8ac8980561/rpds_py-0.29.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de2345af363d25696969befc0c1688a6cb5e8b1d32b515ef84fc245c6cddba3", size = 416796 }, + { url = "https://files.pythonhosted.org/packages/79/a5/449f0281af33efa29d5c71014399d74842342ae908d8cd38260320167692/rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:00e56b12d2199ca96068057e1ae7f9998ab6e99cda82431afafd32f3ec98cca9", size = 566843 }, + { url = "https://files.pythonhosted.org/packages/ab/32/0a6a1ccee2e37fcb1b7ba9afde762b77182dbb57937352a729c6cd3cf2bb/rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3919a3bbecee589300ed25000b6944174e07cd20db70552159207b3f4bbb45b8", size = 593956 }, + { url = "https://files.pythonhosted.org/packages/4a/3d/eb820f95dce4306f07a495ede02fb61bef36ea201d9137d4fcd5ab94ec1e/rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7fa2ccc312bbd91e43aa5e0869e46bc03278a3dddb8d58833150a18b0f0283a", size = 557288 }, + { url = "https://files.pythonhosted.org/packages/e9/f8/b8ff786f40470462a252918e0836e0db903c28e88e3eec66bc4a7856ee5d/rpds_py-0.29.0-cp314-cp314t-win32.whl", hash = "sha256:97c817863ffc397f1e6a6e9d2d89fe5408c0a9922dac0329672fb0f35c867ea5", size = 211382 }, + { url = "https://files.pythonhosted.org/packages/c9/7f/1a65ae870bc9d0576aebb0c501ea5dccf1ae2178fe2821042150ebd2e707/rpds_py-0.29.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2023473f444752f0f82a58dfcbee040d0a1b3d1b3c2ec40e884bd25db6d117d2", size = 225919 }, + { url = "https://files.pythonhosted.org/packages/f2/ac/b97e80bf107159e5b9ba9c91df1ab95f69e5e41b435f27bdd737f0d583ac/rpds_py-0.29.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:acd82a9e39082dc5f4492d15a6b6c8599aa21db5c35aaf7d6889aea16502c07d", size = 373963 }, + { url = "https://files.pythonhosted.org/packages/40/5a/55e72962d5d29bd912f40c594e68880d3c7a52774b0f75542775f9250712/rpds_py-0.29.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:715b67eac317bf1c7657508170a3e011a1ea6ccb1c9d5f296e20ba14196be6b3", size = 364644 }, + { url = "https://files.pythonhosted.org/packages/99/2a/6b6524d0191b7fc1351c3c0840baac42250515afb48ae40c7ed15499a6a2/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3b1b87a237cb2dba4db18bcfaaa44ba4cd5936b91121b62292ff21df577fc43", size = 393847 }, + { url = "https://files.pythonhosted.org/packages/1c/b8/c5692a7df577b3c0c7faed7ac01ee3c608b81750fc5d89f84529229b6873/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1c3c3e8101bb06e337c88eb0c0ede3187131f19d97d43ea0e1c5407ea74c0cbf", size = 407281 }, + { url = "https://files.pythonhosted.org/packages/f0/57/0546c6f84031b7ea08b76646a8e33e45607cc6bd879ff1917dc077bb881e/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8e54d6e61f3ecd3abe032065ce83ea63417a24f437e4a3d73d2f85ce7b7cfe", size = 529213 }, + { url = "https://files.pythonhosted.org/packages/fa/c1/01dd5f444233605555bc11fe5fed6a5c18f379f02013870c176c8e630a23/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3fbd4e9aebf110473a420dea85a238b254cf8a15acb04b22a5a6b5ce8925b760", size = 413808 }, + { url = "https://files.pythonhosted.org/packages/aa/0a/60f98b06156ea2a7af849fb148e00fbcfdb540909a5174a5ed10c93745c7/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fdf53d36e6c72819993e35d1ebeeb8e8fc688d0c6c2b391b55e335b3afba5a", size = 394600 }, + { url = "https://files.pythonhosted.org/packages/37/f1/dc9312fc9bec040ece08396429f2bd9e0977924ba7a11c5ad7056428465e/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:ea7173df5d86f625f8dde6d5929629ad811ed8decda3b60ae603903839ac9ac0", size = 408634 }, + { url = "https://files.pythonhosted.org/packages/ed/41/65024c9fd40c89bb7d604cf73beda4cbdbcebe92d8765345dd65855b6449/rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:76054d540061eda273274f3d13a21a4abdde90e13eaefdc205db37c05230efce", size = 426064 }, + { url = "https://files.pythonhosted.org/packages/a2/e0/cf95478881fc88ca2fdbf56381d7df36567cccc39a05394beac72182cd62/rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f84c549746a5be3bc7415830747a3a0312573afc9f95785eb35228bb17742ec", size = 575871 }, + { url = "https://files.pythonhosted.org/packages/ea/c0/df88097e64339a0218b57bd5f9ca49898e4c394db756c67fccc64add850a/rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:0ea962671af5cb9a260489e311fa22b2e97103e3f9f0caaea6f81390af96a9ed", size = 601702 }, + { url = "https://files.pythonhosted.org/packages/87/f4/09ffb3ebd0cbb9e2c7c9b84d252557ecf434cd71584ee1e32f66013824df/rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f7728653900035fb7b8d06e1e5900545d8088efc9d5d4545782da7df03ec803f", size = 564054 }, ] [[package]] name = "ruff" version = "0.14.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/f0/62b5a1a723fe183650109407fa56abb433b00aa1c0b9ba555f9c4efec2c6/ruff-0.14.6.tar.gz", hash = "sha256:6f0c742ca6a7783a736b867a263b9a7a80a45ce9bee391eeda296895f1b4e1cc", size = 5669501, upload-time = "2025-11-21T14:26:17.903Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/d2/7dd544116d107fffb24a0064d41a5d2ed1c9d6372d142f9ba108c8e39207/ruff-0.14.6-py3-none-linux_armv6l.whl", hash = "sha256:d724ac2f1c240dbd01a2ae98db5d1d9a5e1d9e96eba999d1c48e30062df578a3", size = 13326119, upload-time = "2025-11-21T14:25:24.2Z" }, - { url = "https://files.pythonhosted.org/packages/36/6a/ad66d0a3315d6327ed6b01f759d83df3c4d5f86c30462121024361137b6a/ruff-0.14.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9f7539ea257aa4d07b7ce87aed580e485c40143f2473ff2f2b75aee003186004", size = 13526007, upload-time = "2025-11-21T14:25:26.906Z" }, - { url = "https://files.pythonhosted.org/packages/a3/9d/dae6db96df28e0a15dea8e986ee393af70fc97fd57669808728080529c37/ruff-0.14.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7f6007e55b90a2a7e93083ba48a9f23c3158c433591c33ee2e99a49b889c6332", size = 12676572, upload-time = "2025-11-21T14:25:29.826Z" }, - { url = "https://files.pythonhosted.org/packages/76/a4/f319e87759949062cfee1b26245048e92e2acce900ad3a909285f9db1859/ruff-0.14.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8e7b9d73d8728b68f632aa8e824ef041d068d231d8dbc7808532d3629a6bef", size = 13140745, upload-time = "2025-11-21T14:25:32.788Z" }, - { url = "https://files.pythonhosted.org/packages/95/d3/248c1efc71a0a8ed4e8e10b4b2266845d7dfc7a0ab64354afe049eaa1310/ruff-0.14.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d50d45d4553a3ebcbd33e7c5e0fe6ca4aafd9a9122492de357205c2c48f00775", size = 13076486, upload-time = "2025-11-21T14:25:35.601Z" }, - { url = "https://files.pythonhosted.org/packages/a5/19/b68d4563fe50eba4b8c92aa842149bb56dd24d198389c0ed12e7faff4f7d/ruff-0.14.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:118548dd121f8a21bfa8ab2c5b80e5b4aed67ead4b7567790962554f38e598ce", size = 13727563, upload-time = "2025-11-21T14:25:38.514Z" }, - { url = "https://files.pythonhosted.org/packages/47/ac/943169436832d4b0e867235abbdb57ce3a82367b47e0280fa7b4eabb7593/ruff-0.14.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:57256efafbfefcb8748df9d1d766062f62b20150691021f8ab79e2d919f7c11f", size = 15199755, upload-time = "2025-11-21T14:25:41.516Z" }, - { url = "https://files.pythonhosted.org/packages/c9/b9/288bb2399860a36d4bb0541cb66cce3c0f4156aaff009dc8499be0c24bf2/ruff-0.14.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff18134841e5c68f8e5df1999a64429a02d5549036b394fafbe410f886e1989d", size = 14850608, upload-time = "2025-11-21T14:25:44.428Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b1/a0d549dd4364e240f37e7d2907e97ee80587480d98c7799d2d8dc7a2f605/ruff-0.14.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c4b7ec1e66a105d5c27bd57fa93203637d66a26d10ca9809dc7fc18ec58440", size = 14118754, upload-time = "2025-11-21T14:25:47.214Z" }, - { url = "https://files.pythonhosted.org/packages/13/ac/9b9fe63716af8bdfddfacd0882bc1586f29985d3b988b3c62ddce2e202c3/ruff-0.14.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167843a6f78680746d7e226f255d920aeed5e4ad9c03258094a2d49d3028b105", size = 13949214, upload-time = "2025-11-21T14:25:50.002Z" }, - { url = "https://files.pythonhosted.org/packages/12/27/4dad6c6a77fede9560b7df6802b1b697e97e49ceabe1f12baf3ea20862e9/ruff-0.14.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:16a33af621c9c523b1ae006b1b99b159bf5ac7e4b1f20b85b2572455018e0821", size = 14106112, upload-time = "2025-11-21T14:25:52.841Z" }, - { url = "https://files.pythonhosted.org/packages/6a/db/23e322d7177873eaedea59a7932ca5084ec5b7e20cb30f341ab594130a71/ruff-0.14.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1432ab6e1ae2dc565a7eea707d3b03a0c234ef401482a6f1621bc1f427c2ff55", size = 13035010, upload-time = "2025-11-21T14:25:55.536Z" }, - { url = "https://files.pythonhosted.org/packages/a8/9c/20e21d4d69dbb35e6a1df7691e02f363423658a20a2afacf2a2c011800dc/ruff-0.14.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4c55cfbbe7abb61eb914bfd20683d14cdfb38a6d56c6c66efa55ec6570ee4e71", size = 13054082, upload-time = "2025-11-21T14:25:58.625Z" }, - { url = "https://files.pythonhosted.org/packages/66/25/906ee6a0464c3125c8d673c589771a974965c2be1a1e28b5c3b96cb6ef88/ruff-0.14.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:efea3c0f21901a685fff4befda6d61a1bf4cb43de16da87e8226a281d614350b", size = 13303354, upload-time = "2025-11-21T14:26:01.816Z" }, - { url = "https://files.pythonhosted.org/packages/4c/58/60577569e198d56922b7ead07b465f559002b7b11d53f40937e95067ca1c/ruff-0.14.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:344d97172576d75dc6afc0e9243376dbe1668559c72de1864439c4fc95f78185", size = 14054487, upload-time = "2025-11-21T14:26:05.058Z" }, - { url = "https://files.pythonhosted.org/packages/67/0b/8e4e0639e4cc12547f41cb771b0b44ec8225b6b6a93393176d75fe6f7d40/ruff-0.14.6-py3-none-win32.whl", hash = "sha256:00169c0c8b85396516fdd9ce3446c7ca20c2a8f90a77aa945ba6b8f2bfe99e85", size = 13013361, upload-time = "2025-11-21T14:26:08.152Z" }, - { url = "https://files.pythonhosted.org/packages/fb/02/82240553b77fd1341f80ebb3eaae43ba011c7a91b4224a9f317d8e6591af/ruff-0.14.6-py3-none-win_amd64.whl", hash = "sha256:390e6480c5e3659f8a4c8d6a0373027820419ac14fa0d2713bd8e6c3e125b8b9", size = 14432087, upload-time = "2025-11-21T14:26:10.891Z" }, - { url = "https://files.pythonhosted.org/packages/a5/1f/93f9b0fad9470e4c829a5bb678da4012f0c710d09331b860ee555216f4ea/ruff-0.14.6-py3-none-win_arm64.whl", hash = "sha256:d43c81fbeae52cfa8728d8766bbf46ee4298c888072105815b392da70ca836b2", size = 13520930, upload-time = "2025-11-21T14:26:13.951Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/52/f0/62b5a1a723fe183650109407fa56abb433b00aa1c0b9ba555f9c4efec2c6/ruff-0.14.6.tar.gz", hash = "sha256:6f0c742ca6a7783a736b867a263b9a7a80a45ce9bee391eeda296895f1b4e1cc", size = 5669501 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/d2/7dd544116d107fffb24a0064d41a5d2ed1c9d6372d142f9ba108c8e39207/ruff-0.14.6-py3-none-linux_armv6l.whl", hash = "sha256:d724ac2f1c240dbd01a2ae98db5d1d9a5e1d9e96eba999d1c48e30062df578a3", size = 13326119 }, + { url = "https://files.pythonhosted.org/packages/36/6a/ad66d0a3315d6327ed6b01f759d83df3c4d5f86c30462121024361137b6a/ruff-0.14.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9f7539ea257aa4d07b7ce87aed580e485c40143f2473ff2f2b75aee003186004", size = 13526007 }, + { url = "https://files.pythonhosted.org/packages/a3/9d/dae6db96df28e0a15dea8e986ee393af70fc97fd57669808728080529c37/ruff-0.14.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7f6007e55b90a2a7e93083ba48a9f23c3158c433591c33ee2e99a49b889c6332", size = 12676572 }, + { url = "https://files.pythonhosted.org/packages/76/a4/f319e87759949062cfee1b26245048e92e2acce900ad3a909285f9db1859/ruff-0.14.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8e7b9d73d8728b68f632aa8e824ef041d068d231d8dbc7808532d3629a6bef", size = 13140745 }, + { url = "https://files.pythonhosted.org/packages/95/d3/248c1efc71a0a8ed4e8e10b4b2266845d7dfc7a0ab64354afe049eaa1310/ruff-0.14.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d50d45d4553a3ebcbd33e7c5e0fe6ca4aafd9a9122492de357205c2c48f00775", size = 13076486 }, + { url = "https://files.pythonhosted.org/packages/a5/19/b68d4563fe50eba4b8c92aa842149bb56dd24d198389c0ed12e7faff4f7d/ruff-0.14.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:118548dd121f8a21bfa8ab2c5b80e5b4aed67ead4b7567790962554f38e598ce", size = 13727563 }, + { url = "https://files.pythonhosted.org/packages/47/ac/943169436832d4b0e867235abbdb57ce3a82367b47e0280fa7b4eabb7593/ruff-0.14.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:57256efafbfefcb8748df9d1d766062f62b20150691021f8ab79e2d919f7c11f", size = 15199755 }, + { url = "https://files.pythonhosted.org/packages/c9/b9/288bb2399860a36d4bb0541cb66cce3c0f4156aaff009dc8499be0c24bf2/ruff-0.14.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff18134841e5c68f8e5df1999a64429a02d5549036b394fafbe410f886e1989d", size = 14850608 }, + { url = "https://files.pythonhosted.org/packages/ee/b1/a0d549dd4364e240f37e7d2907e97ee80587480d98c7799d2d8dc7a2f605/ruff-0.14.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c4b7ec1e66a105d5c27bd57fa93203637d66a26d10ca9809dc7fc18ec58440", size = 14118754 }, + { url = "https://files.pythonhosted.org/packages/13/ac/9b9fe63716af8bdfddfacd0882bc1586f29985d3b988b3c62ddce2e202c3/ruff-0.14.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167843a6f78680746d7e226f255d920aeed5e4ad9c03258094a2d49d3028b105", size = 13949214 }, + { url = "https://files.pythonhosted.org/packages/12/27/4dad6c6a77fede9560b7df6802b1b697e97e49ceabe1f12baf3ea20862e9/ruff-0.14.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:16a33af621c9c523b1ae006b1b99b159bf5ac7e4b1f20b85b2572455018e0821", size = 14106112 }, + { url = "https://files.pythonhosted.org/packages/6a/db/23e322d7177873eaedea59a7932ca5084ec5b7e20cb30f341ab594130a71/ruff-0.14.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1432ab6e1ae2dc565a7eea707d3b03a0c234ef401482a6f1621bc1f427c2ff55", size = 13035010 }, + { url = "https://files.pythonhosted.org/packages/a8/9c/20e21d4d69dbb35e6a1df7691e02f363423658a20a2afacf2a2c011800dc/ruff-0.14.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4c55cfbbe7abb61eb914bfd20683d14cdfb38a6d56c6c66efa55ec6570ee4e71", size = 13054082 }, + { url = "https://files.pythonhosted.org/packages/66/25/906ee6a0464c3125c8d673c589771a974965c2be1a1e28b5c3b96cb6ef88/ruff-0.14.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:efea3c0f21901a685fff4befda6d61a1bf4cb43de16da87e8226a281d614350b", size = 13303354 }, + { url = "https://files.pythonhosted.org/packages/4c/58/60577569e198d56922b7ead07b465f559002b7b11d53f40937e95067ca1c/ruff-0.14.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:344d97172576d75dc6afc0e9243376dbe1668559c72de1864439c4fc95f78185", size = 14054487 }, + { url = "https://files.pythonhosted.org/packages/67/0b/8e4e0639e4cc12547f41cb771b0b44ec8225b6b6a93393176d75fe6f7d40/ruff-0.14.6-py3-none-win32.whl", hash = "sha256:00169c0c8b85396516fdd9ce3446c7ca20c2a8f90a77aa945ba6b8f2bfe99e85", size = 13013361 }, + { url = "https://files.pythonhosted.org/packages/fb/02/82240553b77fd1341f80ebb3eaae43ba011c7a91b4224a9f317d8e6591af/ruff-0.14.6-py3-none-win_amd64.whl", hash = "sha256:390e6480c5e3659f8a4c8d6a0373027820419ac14fa0d2713bd8e6c3e125b8b9", size = 14432087 }, + { url = "https://files.pythonhosted.org/packages/a5/1f/93f9b0fad9470e4c829a5bb678da4012f0c710d09331b860ee555216f4ea/ruff-0.14.6-py3-none-win_arm64.whl", hash = "sha256:d43c81fbeae52cfa8728d8766bbf46ee4298c888072105815b392da70ca836b2", size = 13520930 }, ] [[package]] name = "safetensors" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781 }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058 }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748 }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881 }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463 }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855 }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152 }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856 }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060 }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715 }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377 }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368 }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423 }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380 }, + { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430 }, + { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890 }, + { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885 }, ] [[package]] @@ -4096,38 +4080,38 @@ dependencies = [ { name = "scipy", version = "1.16.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, - { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, - { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, - { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, - { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967, upload-time = "2025-09-09T08:20:32.421Z" }, - { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645, upload-time = "2025-09-09T08:20:34.436Z" }, - { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424, upload-time = "2025-09-09T08:20:36.776Z" }, - { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234, upload-time = "2025-09-09T08:20:38.957Z" }, - { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244, upload-time = "2025-09-09T08:20:41.166Z" }, - { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" }, - { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" }, - { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" }, - { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" }, - { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" }, - { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382, upload-time = "2025-09-09T08:20:54.731Z" }, - { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042, upload-time = "2025-09-09T08:20:57.313Z" }, - { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180, upload-time = "2025-09-09T08:20:59.671Z" }, - { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660, upload-time = "2025-09-09T08:21:01.71Z" }, - { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057, upload-time = "2025-09-09T08:21:04.234Z" }, - { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731, upload-time = "2025-09-09T08:21:06.381Z" }, - { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852, upload-time = "2025-09-09T08:21:08.628Z" }, - { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094, upload-time = "2025-09-09T08:21:11.486Z" }, - { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436, upload-time = "2025-09-09T08:21:13.602Z" }, - { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749, upload-time = "2025-09-09T08:21:15.96Z" }, - { url = "https://files.pythonhosted.org/packages/d9/82/dee5acf66837852e8e68df6d8d3a6cb22d3df997b733b032f513d95205b7/scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33", size = 9208906, upload-time = "2025-09-09T08:21:18.557Z" }, - { url = "https://files.pythonhosted.org/packages/3c/30/9029e54e17b87cb7d50d51a5926429c683d5b4c1732f0507a6c3bed9bf65/scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615", size = 8627836, upload-time = "2025-09-09T08:21:20.695Z" }, - { url = "https://files.pythonhosted.org/packages/60/18/4a52c635c71b536879f4b971c2cedf32c35ee78f48367885ed8025d1f7ee/scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106", size = 9426236, upload-time = "2025-09-09T08:21:22.645Z" }, - { url = "https://files.pythonhosted.org/packages/99/7e/290362f6ab582128c53445458a5befd471ed1ea37953d5bcf80604619250/scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61", size = 9312593, upload-time = "2025-09-09T08:21:24.65Z" }, - { url = "https://files.pythonhosted.org/packages/8e/87/24f541b6d62b1794939ae6422f8023703bbf6900378b2b34e0b4384dfefd/scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8", size = 8820007, upload-time = "2025-09-09T08:21:26.713Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221 }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834 }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938 }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818 }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969 }, + { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967 }, + { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645 }, + { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424 }, + { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234 }, + { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244 }, + { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818 }, + { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997 }, + { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381 }, + { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296 }, + { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256 }, + { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382 }, + { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042 }, + { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180 }, + { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660 }, + { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057 }, + { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731 }, + { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852 }, + { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094 }, + { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436 }, + { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749 }, + { url = "https://files.pythonhosted.org/packages/d9/82/dee5acf66837852e8e68df6d8d3a6cb22d3df997b733b032f513d95205b7/scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33", size = 9208906 }, + { url = "https://files.pythonhosted.org/packages/3c/30/9029e54e17b87cb7d50d51a5926429c683d5b4c1732f0507a6c3bed9bf65/scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615", size = 8627836 }, + { url = "https://files.pythonhosted.org/packages/60/18/4a52c635c71b536879f4b971c2cedf32c35ee78f48367885ed8025d1f7ee/scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106", size = 9426236 }, + { url = "https://files.pythonhosted.org/packages/99/7e/290362f6ab582128c53445458a5befd471ed1ea37953d5bcf80604619250/scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61", size = 9312593 }, + { url = "https://files.pythonhosted.org/packages/8e/87/24f541b6d62b1794939ae6422f8023703bbf6900378b2b34e0b4384dfefd/scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8", size = 8820007 }, ] [[package]] @@ -4140,53 +4124,53 @@ resolution-markers = [ dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, - { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, - { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, - { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, - { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, - { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, - { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, - { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, - { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, - { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, - { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, - { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, - { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, - { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, - { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, - { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, - { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, - { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, - { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, - { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, - { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, - { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, - { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, - { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, - { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, - { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, - { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, - { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, - { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, - { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, - { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, - { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, - { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, - { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, - { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770 }, + { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511 }, + { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151 }, + { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732 }, + { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617 }, + { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964 }, + { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749 }, + { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383 }, + { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201 }, + { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255 }, + { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035 }, + { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499 }, + { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602 }, + { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415 }, + { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622 }, + { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796 }, + { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684 }, + { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504 }, + { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735 }, + { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284 }, + { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958 }, + { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454 }, + { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199 }, + { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455 }, + { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140 }, + { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549 }, + { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184 }, + { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256 }, + { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540 }, + { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115 }, + { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884 }, + { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018 }, + { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716 }, + { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342 }, + { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869 }, + { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851 }, + { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011 }, + { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407 }, + { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030 }, + { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709 }, + { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045 }, + { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062 }, + { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132 }, + { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503 }, + { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097 }, ] [[package]] @@ -4202,77 +4186,77 @@ resolution-markers = [ dependencies = [ { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881, upload-time = "2025-10-28T17:31:47.104Z" }, - { url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012, upload-time = "2025-10-28T17:31:53.411Z" }, - { url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935, upload-time = "2025-10-28T17:31:57.361Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466, upload-time = "2025-10-28T17:32:01.875Z" }, - { url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618, upload-time = "2025-10-28T17:32:06.902Z" }, - { url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798, upload-time = "2025-10-28T17:32:12.665Z" }, - { url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154, upload-time = "2025-10-28T17:32:17.961Z" }, - { url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540, upload-time = "2025-10-28T17:32:23.907Z" }, - { url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107, upload-time = "2025-10-28T17:32:29.921Z" }, - { url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272, upload-time = "2025-10-28T17:32:34.577Z" }, - { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043, upload-time = "2025-10-28T17:32:40.285Z" }, - { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986, upload-time = "2025-10-28T17:32:45.325Z" }, - { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814, upload-time = "2025-10-28T17:32:49.277Z" }, - { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795, upload-time = "2025-10-28T17:32:53.337Z" }, - { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476, upload-time = "2025-10-28T17:32:58.353Z" }, - { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692, upload-time = "2025-10-28T17:33:03.88Z" }, - { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345, upload-time = "2025-10-28T17:33:09.773Z" }, - { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975, upload-time = "2025-10-28T17:33:15.809Z" }, - { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926, upload-time = "2025-10-28T17:33:21.388Z" }, - { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014, upload-time = "2025-10-28T17:33:25.975Z" }, - { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, - { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, - { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, - { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, - { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, - { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, - { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, - { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, - { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, - { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, - { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, - { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, - { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, - { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, - { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, - { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, - { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, - { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, - { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, - { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, - { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, - { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, - { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, - { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, - { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, - { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, - { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, - { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, - { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, - { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, - { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, - { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, - { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881 }, + { url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012 }, + { url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935 }, + { url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466 }, + { url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618 }, + { url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798 }, + { url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154 }, + { url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540 }, + { url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107 }, + { url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272 }, + { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043 }, + { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986 }, + { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814 }, + { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795 }, + { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476 }, + { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692 }, + { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345 }, + { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975 }, + { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926 }, + { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014 }, + { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856 }, + { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306 }, + { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371 }, + { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877 }, + { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103 }, + { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297 }, + { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756 }, + { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566 }, + { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877 }, + { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366 }, + { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931 }, + { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081 }, + { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244 }, + { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753 }, + { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912 }, + { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371 }, + { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477 }, + { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678 }, + { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178 }, + { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246 }, + { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469 }, + { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043 }, + { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952 }, + { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512 }, + { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639 }, + { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729 }, + { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251 }, + { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681 }, + { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423 }, + { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027 }, + { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379 }, + { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052 }, + { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183 }, + { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174 }, + { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852 }, + { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595 }, + { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269 }, + { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779 }, + { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128 }, + { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127 }, ] [[package]] name = "send2trash" version = "1.8.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/3a/aec9b02217bb79b87bbc1a21bc6abc51e3d5dcf65c30487ac96c0908c722/Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf", size = 17394, upload-time = "2024-04-07T00:01:09.267Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/3a/aec9b02217bb79b87bbc1a21bc6abc51e3d5dcf65c30487ac96c0908c722/Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf", size = 17394 } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072, upload-time = "2024-04-07T00:01:07.438Z" }, + { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072 }, ] [[package]] @@ -4290,45 +4274,45 @@ dependencies = [ { name = "transformers" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0f/96/f3f3409179d14dbfdbea8622e2e9eaa3c8836ddcaecd2cd5ff0a11731d20/sentence_transformers-5.1.2.tar.gz", hash = "sha256:0f6c8bd916a78dc65b366feb8d22fd885efdb37432e7630020d113233af2b856", size = 375185, upload-time = "2025-10-22T12:47:55.019Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/96/f3f3409179d14dbfdbea8622e2e9eaa3c8836ddcaecd2cd5ff0a11731d20/sentence_transformers-5.1.2.tar.gz", hash = "sha256:0f6c8bd916a78dc65b366feb8d22fd885efdb37432e7630020d113233af2b856", size = 375185 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/a6/a607a737dc1a00b7afe267b9bfde101b8cee2529e197e57471d23137d4e5/sentence_transformers-5.1.2-py3-none-any.whl", hash = "sha256:724ce0ea62200f413f1a5059712aff66495bc4e815a1493f7f9bca242414c333", size = 488009, upload-time = "2025-10-22T12:47:53.433Z" }, + { url = "https://files.pythonhosted.org/packages/bb/a6/a607a737dc1a00b7afe267b9bfde101b8cee2529e197e57471d23137d4e5/sentence_transformers-5.1.2-py3-none-any.whl", hash = "sha256:724ce0ea62200f413f1a5059712aff66495bc4e815a1493f7f9bca242414c333", size = 488009 }, ] [[package]] name = "setuptools" version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 }, ] [[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 } 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 }, ] [[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 } 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 }, ] [[package]] name = "soupsieve" version = "2.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472 } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, + { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679 }, ] [[package]] @@ -4339,41 +4323,41 @@ 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/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830, upload-time = "2025-10-10T14:39:12.935Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/a7/e9ccfa7eecaf34c6f57d8cb0bb7cbdeeff27017cc0f5d0ca90fdde7a7c0d/sqlalchemy-2.0.44-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce", size = 2137282, upload-time = "2025-10-10T15:36:10.965Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e1/50bc121885bdf10833a4f65ecbe9fe229a3215f4d65a58da8a181734cae3/sqlalchemy-2.0.44-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985", size = 2127322, upload-time = "2025-10-10T15:36:12.428Z" }, - { url = "https://files.pythonhosted.org/packages/46/f2/a8573b7230a3ce5ee4b961a2d510d71b43872513647398e595b744344664/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0", size = 3214772, upload-time = "2025-10-10T15:34:15.09Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d8/c63d8adb6a7edaf8dcb6f75a2b1e9f8577960a1e489606859c4d73e7d32b/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e", size = 3214434, upload-time = "2025-10-10T15:47:00.473Z" }, - { url = "https://files.pythonhosted.org/packages/ee/a6/243d277a4b54fae74d4797957a7320a5c210c293487f931cbe036debb697/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749", size = 3155365, upload-time = "2025-10-10T15:34:17.932Z" }, - { url = "https://files.pythonhosted.org/packages/5f/f8/6a39516ddd75429fd4ee5a0d72e4c80639fab329b2467c75f363c2ed9751/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2", size = 3178910, upload-time = "2025-10-10T15:47:02.346Z" }, - { url = "https://files.pythonhosted.org/packages/43/f0/118355d4ad3c39d9a2f5ee4c7304a9665b3571482777357fa9920cd7a6b4/sqlalchemy-2.0.44-cp310-cp310-win32.whl", hash = "sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165", size = 2105624, upload-time = "2025-10-10T15:38:15.552Z" }, - { url = "https://files.pythonhosted.org/packages/61/83/6ae5f9466f8aa5d0dcebfff8c9c33b98b27ce23292df3b990454b3d434fd/sqlalchemy-2.0.44-cp310-cp310-win_amd64.whl", hash = "sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5", size = 2129240, upload-time = "2025-10-10T15:38:17.175Z" }, - { url = "https://files.pythonhosted.org/packages/e3/81/15d7c161c9ddf0900b076b55345872ed04ff1ed6a0666e5e94ab44b0163c/sqlalchemy-2.0.44-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd", size = 2140517, upload-time = "2025-10-10T15:36:15.64Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d5/4abd13b245c7d91bdf131d4916fd9e96a584dac74215f8b5bc945206a974/sqlalchemy-2.0.44-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa", size = 2130738, upload-time = "2025-10-10T15:36:16.91Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3c/8418969879c26522019c1025171cefbb2a8586b6789ea13254ac602986c0/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e", size = 3304145, upload-time = "2025-10-10T15:34:19.569Z" }, - { url = "https://files.pythonhosted.org/packages/94/2d/fdb9246d9d32518bda5d90f4b65030b9bf403a935cfe4c36a474846517cb/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e", size = 3304511, upload-time = "2025-10-10T15:47:05.088Z" }, - { url = "https://files.pythonhosted.org/packages/7d/fb/40f2ad1da97d5c83f6c1269664678293d3fe28e90ad17a1093b735420549/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399", size = 3235161, upload-time = "2025-10-10T15:34:21.193Z" }, - { url = "https://files.pythonhosted.org/packages/95/cb/7cf4078b46752dca917d18cf31910d4eff6076e5b513c2d66100c4293d83/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b", size = 3261426, upload-time = "2025-10-10T15:47:07.196Z" }, - { url = "https://files.pythonhosted.org/packages/f8/3b/55c09b285cb2d55bdfa711e778bdffdd0dc3ffa052b0af41f1c5d6e582fa/sqlalchemy-2.0.44-cp311-cp311-win32.whl", hash = "sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3", size = 2105392, upload-time = "2025-10-10T15:38:20.051Z" }, - { url = "https://files.pythonhosted.org/packages/c7/23/907193c2f4d680aedbfbdf7bf24c13925e3c7c292e813326c1b84a0b878e/sqlalchemy-2.0.44-cp311-cp311-win_amd64.whl", hash = "sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5", size = 2130293, upload-time = "2025-10-10T15:38:21.601Z" }, - { url = "https://files.pythonhosted.org/packages/62/c4/59c7c9b068e6813c898b771204aad36683c96318ed12d4233e1b18762164/sqlalchemy-2.0.44-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250", size = 2139675, upload-time = "2025-10-10T16:03:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/d6/ae/eeb0920537a6f9c5a3708e4a5fc55af25900216bdb4847ec29cfddf3bf3a/sqlalchemy-2.0.44-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29", size = 2127726, upload-time = "2025-10-10T16:03:35.934Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2ebbabe0379418eda8041c06b0b551f213576bfe4c2f09d77c06c07c8cc5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44", size = 3327603, upload-time = "2025-10-10T15:35:28.322Z" }, - { url = "https://files.pythonhosted.org/packages/45/e5/5aa65852dadc24b7d8ae75b7efb8d19303ed6ac93482e60c44a585930ea5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1", size = 3337842, upload-time = "2025-10-10T15:43:45.431Z" }, - { url = "https://files.pythonhosted.org/packages/41/92/648f1afd3f20b71e880ca797a960f638d39d243e233a7082c93093c22378/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7", size = 3264558, upload-time = "2025-10-10T15:35:29.93Z" }, - { url = "https://files.pythonhosted.org/packages/40/cf/e27d7ee61a10f74b17740918e23cbc5bc62011b48282170dc4c66da8ec0f/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d", size = 3301570, upload-time = "2025-10-10T15:43:48.407Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3d/3116a9a7b63e780fb402799b6da227435be878b6846b192f076d2f838654/sqlalchemy-2.0.44-cp312-cp312-win32.whl", hash = "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4", size = 2103447, upload-time = "2025-10-10T15:03:21.678Z" }, - { url = "https://files.pythonhosted.org/packages/25/83/24690e9dfc241e6ab062df82cc0df7f4231c79ba98b273fa496fb3dd78ed/sqlalchemy-2.0.44-cp312-cp312-win_amd64.whl", hash = "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e", size = 2130912, upload-time = "2025-10-10T15:03:24.656Z" }, - { url = "https://files.pythonhosted.org/packages/45/d3/c67077a2249fdb455246e6853166360054c331db4613cda3e31ab1cadbef/sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1", size = 2135479, upload-time = "2025-10-10T16:03:37.671Z" }, - { url = "https://files.pythonhosted.org/packages/2b/91/eabd0688330d6fd114f5f12c4f89b0d02929f525e6bf7ff80aa17ca802af/sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45", size = 2123212, upload-time = "2025-10-10T16:03:41.755Z" }, - { url = "https://files.pythonhosted.org/packages/b0/bb/43e246cfe0e81c018076a16036d9b548c4cc649de241fa27d8d9ca6f85ab/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976", size = 3255353, upload-time = "2025-10-10T15:35:31.221Z" }, - { url = "https://files.pythonhosted.org/packages/b9/96/c6105ed9a880abe346b64d3b6ddef269ddfcab04f7f3d90a0bf3c5a88e82/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c", size = 3260222, upload-time = "2025-10-10T15:43:50.124Z" }, - { url = "https://files.pythonhosted.org/packages/44/16/1857e35a47155b5ad927272fee81ae49d398959cb749edca6eaa399b582f/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d", size = 3189614, upload-time = "2025-10-10T15:35:32.578Z" }, - { url = "https://files.pythonhosted.org/packages/88/ee/4afb39a8ee4fc786e2d716c20ab87b5b1fb33d4ac4129a1aaa574ae8a585/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40", size = 3226248, upload-time = "2025-10-10T15:43:51.862Z" }, - { url = "https://files.pythonhosted.org/packages/32/d5/0e66097fc64fa266f29a7963296b40a80d6a997b7ac13806183700676f86/sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73", size = 2101275, upload-time = "2025-10-10T15:03:26.096Z" }, - { url = "https://files.pythonhosted.org/packages/03/51/665617fe4f8c6450f42a6d8d69243f9420f5677395572c2fe9d21b493b7b/sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e", size = 2127901, upload-time = "2025-10-10T15:03:27.548Z" }, - { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718, upload-time = "2025-10-10T15:29:45.32Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/a7/e9ccfa7eecaf34c6f57d8cb0bb7cbdeeff27017cc0f5d0ca90fdde7a7c0d/sqlalchemy-2.0.44-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce", size = 2137282 }, + { url = "https://files.pythonhosted.org/packages/b1/e1/50bc121885bdf10833a4f65ecbe9fe229a3215f4d65a58da8a181734cae3/sqlalchemy-2.0.44-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985", size = 2127322 }, + { url = "https://files.pythonhosted.org/packages/46/f2/a8573b7230a3ce5ee4b961a2d510d71b43872513647398e595b744344664/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0", size = 3214772 }, + { url = "https://files.pythonhosted.org/packages/4a/d8/c63d8adb6a7edaf8dcb6f75a2b1e9f8577960a1e489606859c4d73e7d32b/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e", size = 3214434 }, + { url = "https://files.pythonhosted.org/packages/ee/a6/243d277a4b54fae74d4797957a7320a5c210c293487f931cbe036debb697/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749", size = 3155365 }, + { url = "https://files.pythonhosted.org/packages/5f/f8/6a39516ddd75429fd4ee5a0d72e4c80639fab329b2467c75f363c2ed9751/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2", size = 3178910 }, + { url = "https://files.pythonhosted.org/packages/43/f0/118355d4ad3c39d9a2f5ee4c7304a9665b3571482777357fa9920cd7a6b4/sqlalchemy-2.0.44-cp310-cp310-win32.whl", hash = "sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165", size = 2105624 }, + { url = "https://files.pythonhosted.org/packages/61/83/6ae5f9466f8aa5d0dcebfff8c9c33b98b27ce23292df3b990454b3d434fd/sqlalchemy-2.0.44-cp310-cp310-win_amd64.whl", hash = "sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5", size = 2129240 }, + { url = "https://files.pythonhosted.org/packages/e3/81/15d7c161c9ddf0900b076b55345872ed04ff1ed6a0666e5e94ab44b0163c/sqlalchemy-2.0.44-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd", size = 2140517 }, + { url = "https://files.pythonhosted.org/packages/d4/d5/4abd13b245c7d91bdf131d4916fd9e96a584dac74215f8b5bc945206a974/sqlalchemy-2.0.44-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa", size = 2130738 }, + { url = "https://files.pythonhosted.org/packages/cb/3c/8418969879c26522019c1025171cefbb2a8586b6789ea13254ac602986c0/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e", size = 3304145 }, + { url = "https://files.pythonhosted.org/packages/94/2d/fdb9246d9d32518bda5d90f4b65030b9bf403a935cfe4c36a474846517cb/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e", size = 3304511 }, + { url = "https://files.pythonhosted.org/packages/7d/fb/40f2ad1da97d5c83f6c1269664678293d3fe28e90ad17a1093b735420549/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399", size = 3235161 }, + { url = "https://files.pythonhosted.org/packages/95/cb/7cf4078b46752dca917d18cf31910d4eff6076e5b513c2d66100c4293d83/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b", size = 3261426 }, + { url = "https://files.pythonhosted.org/packages/f8/3b/55c09b285cb2d55bdfa711e778bdffdd0dc3ffa052b0af41f1c5d6e582fa/sqlalchemy-2.0.44-cp311-cp311-win32.whl", hash = "sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3", size = 2105392 }, + { url = "https://files.pythonhosted.org/packages/c7/23/907193c2f4d680aedbfbdf7bf24c13925e3c7c292e813326c1b84a0b878e/sqlalchemy-2.0.44-cp311-cp311-win_amd64.whl", hash = "sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5", size = 2130293 }, + { url = "https://files.pythonhosted.org/packages/62/c4/59c7c9b068e6813c898b771204aad36683c96318ed12d4233e1b18762164/sqlalchemy-2.0.44-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250", size = 2139675 }, + { url = "https://files.pythonhosted.org/packages/d6/ae/eeb0920537a6f9c5a3708e4a5fc55af25900216bdb4847ec29cfddf3bf3a/sqlalchemy-2.0.44-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29", size = 2127726 }, + { url = "https://files.pythonhosted.org/packages/d8/d5/2ebbabe0379418eda8041c06b0b551f213576bfe4c2f09d77c06c07c8cc5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44", size = 3327603 }, + { url = "https://files.pythonhosted.org/packages/45/e5/5aa65852dadc24b7d8ae75b7efb8d19303ed6ac93482e60c44a585930ea5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1", size = 3337842 }, + { url = "https://files.pythonhosted.org/packages/41/92/648f1afd3f20b71e880ca797a960f638d39d243e233a7082c93093c22378/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7", size = 3264558 }, + { url = "https://files.pythonhosted.org/packages/40/cf/e27d7ee61a10f74b17740918e23cbc5bc62011b48282170dc4c66da8ec0f/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d", size = 3301570 }, + { url = "https://files.pythonhosted.org/packages/3b/3d/3116a9a7b63e780fb402799b6da227435be878b6846b192f076d2f838654/sqlalchemy-2.0.44-cp312-cp312-win32.whl", hash = "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4", size = 2103447 }, + { url = "https://files.pythonhosted.org/packages/25/83/24690e9dfc241e6ab062df82cc0df7f4231c79ba98b273fa496fb3dd78ed/sqlalchemy-2.0.44-cp312-cp312-win_amd64.whl", hash = "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e", size = 2130912 }, + { url = "https://files.pythonhosted.org/packages/45/d3/c67077a2249fdb455246e6853166360054c331db4613cda3e31ab1cadbef/sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1", size = 2135479 }, + { url = "https://files.pythonhosted.org/packages/2b/91/eabd0688330d6fd114f5f12c4f89b0d02929f525e6bf7ff80aa17ca802af/sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45", size = 2123212 }, + { url = "https://files.pythonhosted.org/packages/b0/bb/43e246cfe0e81c018076a16036d9b548c4cc649de241fa27d8d9ca6f85ab/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976", size = 3255353 }, + { url = "https://files.pythonhosted.org/packages/b9/96/c6105ed9a880abe346b64d3b6ddef269ddfcab04f7f3d90a0bf3c5a88e82/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c", size = 3260222 }, + { url = "https://files.pythonhosted.org/packages/44/16/1857e35a47155b5ad927272fee81ae49d398959cb749edca6eaa399b582f/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d", size = 3189614 }, + { url = "https://files.pythonhosted.org/packages/88/ee/4afb39a8ee4fc786e2d716c20ab87b5b1fb33d4ac4129a1aaa574ae8a585/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40", size = 3226248 }, + { url = "https://files.pythonhosted.org/packages/32/d5/0e66097fc64fa266f29a7963296b40a80d6a997b7ac13806183700676f86/sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73", size = 2101275 }, + { url = "https://files.pythonhosted.org/packages/03/51/665617fe4f8c6450f42a6d8d69243f9420f5677395572c2fe9d21b493b7b/sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e", size = 2127901 }, + { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718 }, ] [[package]] @@ -4385,9 +4369,9 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, ] [[package]] @@ -4397,18 +4381,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, ] [[package]] name = "tenacity" version = "9.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 }, ] [[package]] @@ -4420,18 +4404,18 @@ dependencies = [ { name = "pywinpty", marker = "os_name == 'nt'" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, ] [[package]] name = "threadpoolctl" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274 } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638 }, ] [[package]] @@ -4442,57 +4426,57 @@ 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/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991, upload-time = "2025-10-06T20:21:34.098Z" }, - { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798, upload-time = "2025-10-06T20:21:35.579Z" }, - { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865, upload-time = "2025-10-06T20:21:36.675Z" }, - { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856, upload-time = "2025-10-06T20:21:37.873Z" }, - { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308, upload-time = "2025-10-06T20:21:39.577Z" }, - { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697, upload-time = "2025-10-06T20:21:41.154Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375, upload-time = "2025-10-06T20:21:43.201Z" }, - { url = "https://files.pythonhosted.org/packages/de/46/21ea696b21f1d6d1efec8639c204bdf20fde8bafb351e1355c72c5d7de52/tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb", size = 1051565, upload-time = "2025-10-06T20:21:44.566Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d9/35c5d2d9e22bb2a5f74ba48266fb56c63d76ae6f66e02feb628671c0283e/tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa", size = 995284, upload-time = "2025-10-06T20:21:45.622Z" }, - { url = "https://files.pythonhosted.org/packages/01/84/961106c37b8e49b9fdcf33fe007bb3a8fdcc380c528b20cc7fbba80578b8/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc", size = 1129201, upload-time = "2025-10-06T20:21:47.074Z" }, - { url = "https://files.pythonhosted.org/packages/6a/d0/3d9275198e067f8b65076a68894bb52fd253875f3644f0a321a720277b8a/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded", size = 1152444, upload-time = "2025-10-06T20:21:48.139Z" }, - { url = "https://files.pythonhosted.org/packages/78/db/a58e09687c1698a7c592e1038e01c206569b86a0377828d51635561f8ebf/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd", size = 1195080, upload-time = "2025-10-06T20:21:49.246Z" }, - { url = "https://files.pythonhosted.org/packages/9e/1b/a9e4d2bf91d515c0f74afc526fd773a812232dd6cda33ebea7f531202325/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967", size = 1255240, upload-time = "2025-10-06T20:21:50.274Z" }, - { url = "https://files.pythonhosted.org/packages/9d/15/963819345f1b1fb0809070a79e9dd96938d4ca41297367d471733e79c76c/tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def", size = 879422, upload-time = "2025-10-06T20:21:51.734Z" }, - { url = "https://files.pythonhosted.org/packages/a4/85/be65d39d6b647c79800fd9d29241d081d4eeb06271f383bb87200d74cf76/tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8", size = 1050728, upload-time = "2025-10-06T20:21:52.756Z" }, - { url = "https://files.pythonhosted.org/packages/4a/42/6573e9129bc55c9bf7300b3a35bef2c6b9117018acca0dc760ac2d93dffe/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b", size = 994049, upload-time = "2025-10-06T20:21:53.782Z" }, - { url = "https://files.pythonhosted.org/packages/66/c5/ed88504d2f4a5fd6856990b230b56d85a777feab84e6129af0822f5d0f70/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37", size = 1129008, upload-time = "2025-10-06T20:21:54.832Z" }, - { url = "https://files.pythonhosted.org/packages/f4/90/3dae6cc5436137ebd38944d396b5849e167896fc2073da643a49f372dc4f/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad", size = 1152665, upload-time = "2025-10-06T20:21:56.129Z" }, - { url = "https://files.pythonhosted.org/packages/a3/fe/26df24ce53ffde419a42f5f53d755b995c9318908288c17ec3f3448313a3/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5", size = 1194230, upload-time = "2025-10-06T20:21:57.546Z" }, - { url = "https://files.pythonhosted.org/packages/20/cc/b064cae1a0e9fac84b0d2c46b89f4e57051a5f41324e385d10225a984c24/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3", size = 1254688, upload-time = "2025-10-06T20:21:58.619Z" }, - { url = "https://files.pythonhosted.org/packages/81/10/b8523105c590c5b8349f2587e2fdfe51a69544bd5a76295fc20f2374f470/tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd", size = 878694, upload-time = "2025-10-06T20:21:59.876Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991 }, + { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798 }, + { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865 }, + { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856 }, + { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308 }, + { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697 }, + { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, + { url = "https://files.pythonhosted.org/packages/de/46/21ea696b21f1d6d1efec8639c204bdf20fde8bafb351e1355c72c5d7de52/tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb", size = 1051565 }, + { url = "https://files.pythonhosted.org/packages/c9/d9/35c5d2d9e22bb2a5f74ba48266fb56c63d76ae6f66e02feb628671c0283e/tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa", size = 995284 }, + { url = "https://files.pythonhosted.org/packages/01/84/961106c37b8e49b9fdcf33fe007bb3a8fdcc380c528b20cc7fbba80578b8/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc", size = 1129201 }, + { url = "https://files.pythonhosted.org/packages/6a/d0/3d9275198e067f8b65076a68894bb52fd253875f3644f0a321a720277b8a/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded", size = 1152444 }, + { url = "https://files.pythonhosted.org/packages/78/db/a58e09687c1698a7c592e1038e01c206569b86a0377828d51635561f8ebf/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd", size = 1195080 }, + { url = "https://files.pythonhosted.org/packages/9e/1b/a9e4d2bf91d515c0f74afc526fd773a812232dd6cda33ebea7f531202325/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967", size = 1255240 }, + { url = "https://files.pythonhosted.org/packages/9d/15/963819345f1b1fb0809070a79e9dd96938d4ca41297367d471733e79c76c/tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def", size = 879422 }, + { url = "https://files.pythonhosted.org/packages/a4/85/be65d39d6b647c79800fd9d29241d081d4eeb06271f383bb87200d74cf76/tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8", size = 1050728 }, + { url = "https://files.pythonhosted.org/packages/4a/42/6573e9129bc55c9bf7300b3a35bef2c6b9117018acca0dc760ac2d93dffe/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b", size = 994049 }, + { url = "https://files.pythonhosted.org/packages/66/c5/ed88504d2f4a5fd6856990b230b56d85a777feab84e6129af0822f5d0f70/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37", size = 1129008 }, + { url = "https://files.pythonhosted.org/packages/f4/90/3dae6cc5436137ebd38944d396b5849e167896fc2073da643a49f372dc4f/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad", size = 1152665 }, + { url = "https://files.pythonhosted.org/packages/a3/fe/26df24ce53ffde419a42f5f53d755b995c9318908288c17ec3f3448313a3/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5", size = 1194230 }, + { url = "https://files.pythonhosted.org/packages/20/cc/b064cae1a0e9fac84b0d2c46b89f4e57051a5f41324e385d10225a984c24/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3", size = 1254688 }, + { url = "https://files.pythonhosted.org/packages/81/10/b8523105c590c5b8349f2587e2fdfe51a69544bd5a76295fc20f2374f470/tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd", size = 878694 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/8e/32/45d02e2e0ea2be3a9ed22afc47d93741247e75018aac967b713b2941f8ea/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697", size = 879117 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/93/e0/6cc82a562bc6365785a3ff0af27a2a092d57c47d7a81d9e2295d8c36f011/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f", size = 878777 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/80/57/ce64fd16ac390fafde001268c364d559447ba09b509181b2808622420eec/tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3", size = 921067 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667 }, ] [[package]] @@ -4502,9 +4486,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, ] [[package]] @@ -4514,71 +4498,71 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1c/46/fb6854cec3278fbfa4a75b50232c77622bc517ac886156e6afbfa4d8fc6e/tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9", size = 363123, upload-time = "2025-09-19T09:49:23.424Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/46/fb6854cec3278fbfa4a75b50232c77622bc517ac886156e6afbfa4d8fc6e/tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9", size = 363123 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/33/f4b2d94ada7ab297328fc671fed209368ddb82f965ec2224eb1892674c3a/tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73", size = 3069318, upload-time = "2025-09-19T09:49:11.848Z" }, - { url = "https://files.pythonhosted.org/packages/1c/58/2aa8c874d02b974990e89ff95826a4852a8b2a273c7d1b4411cdd45a4565/tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc", size = 2926478, upload-time = "2025-09-19T09:49:09.759Z" }, - { url = "https://files.pythonhosted.org/packages/1e/3b/55e64befa1e7bfea963cf4b787b2cea1011362c4193f5477047532ce127e/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a", size = 3256994, upload-time = "2025-09-19T09:48:56.701Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/fbfecf42f67d9b7b80fde4aabb2b3110a97fac6585c9470b5bff103a80cb/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7", size = 3153141, upload-time = "2025-09-19T09:48:59.749Z" }, - { url = "https://files.pythonhosted.org/packages/17/a9/b38f4e74e0817af8f8ef925507c63c6ae8171e3c4cb2d5d4624bf58fca69/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21", size = 3508049, upload-time = "2025-09-19T09:49:05.868Z" }, - { url = "https://files.pythonhosted.org/packages/d2/48/dd2b3dac46bb9134a88e35d72e1aa4869579eacc1a27238f1577270773ff/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214", size = 3710730, upload-time = "2025-09-19T09:49:01.832Z" }, - { url = "https://files.pythonhosted.org/packages/93/0e/ccabc8d16ae4ba84a55d41345207c1e2ea88784651a5a487547d80851398/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f", size = 3412560, upload-time = "2025-09-19T09:49:03.867Z" }, - { url = "https://files.pythonhosted.org/packages/d0/c6/dc3a0db5a6766416c32c034286d7c2d406da1f498e4de04ab1b8959edd00/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4", size = 3250221, upload-time = "2025-09-19T09:49:07.664Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a6/2c8486eef79671601ff57b093889a345dd3d576713ef047776015dc66de7/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879", size = 9345569, upload-time = "2025-09-19T09:49:14.214Z" }, - { url = "https://files.pythonhosted.org/packages/6b/16/32ce667f14c35537f5f605fe9bea3e415ea1b0a646389d2295ec348d5657/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446", size = 9271599, upload-time = "2025-09-19T09:49:16.639Z" }, - { url = "https://files.pythonhosted.org/packages/51/7c/a5f7898a3f6baa3fc2685c705e04c98c1094c523051c805cdd9306b8f87e/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a", size = 9533862, upload-time = "2025-09-19T09:49:19.146Z" }, - { url = "https://files.pythonhosted.org/packages/36/65/7e75caea90bc73c1dd8d40438adf1a7bc26af3b8d0a6705ea190462506e1/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390", size = 9681250, upload-time = "2025-09-19T09:49:21.501Z" }, - { url = "https://files.pythonhosted.org/packages/30/2c/959dddef581b46e6209da82df3b78471e96260e2bc463f89d23b1bf0e52a/tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82", size = 2472003, upload-time = "2025-09-19T09:49:27.089Z" }, - { url = "https://files.pythonhosted.org/packages/b3/46/e33a8c93907b631a99377ef4c5f817ab453d0b34f93529421f42ff559671/tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138", size = 2674684, upload-time = "2025-09-19T09:49:24.953Z" }, + { url = "https://files.pythonhosted.org/packages/bf/33/f4b2d94ada7ab297328fc671fed209368ddb82f965ec2224eb1892674c3a/tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73", size = 3069318 }, + { url = "https://files.pythonhosted.org/packages/1c/58/2aa8c874d02b974990e89ff95826a4852a8b2a273c7d1b4411cdd45a4565/tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc", size = 2926478 }, + { url = "https://files.pythonhosted.org/packages/1e/3b/55e64befa1e7bfea963cf4b787b2cea1011362c4193f5477047532ce127e/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a", size = 3256994 }, + { url = "https://files.pythonhosted.org/packages/71/0b/fbfecf42f67d9b7b80fde4aabb2b3110a97fac6585c9470b5bff103a80cb/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7", size = 3153141 }, + { url = "https://files.pythonhosted.org/packages/17/a9/b38f4e74e0817af8f8ef925507c63c6ae8171e3c4cb2d5d4624bf58fca69/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21", size = 3508049 }, + { url = "https://files.pythonhosted.org/packages/d2/48/dd2b3dac46bb9134a88e35d72e1aa4869579eacc1a27238f1577270773ff/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214", size = 3710730 }, + { url = "https://files.pythonhosted.org/packages/93/0e/ccabc8d16ae4ba84a55d41345207c1e2ea88784651a5a487547d80851398/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f", size = 3412560 }, + { url = "https://files.pythonhosted.org/packages/d0/c6/dc3a0db5a6766416c32c034286d7c2d406da1f498e4de04ab1b8959edd00/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4", size = 3250221 }, + { url = "https://files.pythonhosted.org/packages/d7/a6/2c8486eef79671601ff57b093889a345dd3d576713ef047776015dc66de7/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879", size = 9345569 }, + { url = "https://files.pythonhosted.org/packages/6b/16/32ce667f14c35537f5f605fe9bea3e415ea1b0a646389d2295ec348d5657/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446", size = 9271599 }, + { url = "https://files.pythonhosted.org/packages/51/7c/a5f7898a3f6baa3fc2685c705e04c98c1094c523051c805cdd9306b8f87e/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a", size = 9533862 }, + { url = "https://files.pythonhosted.org/packages/36/65/7e75caea90bc73c1dd8d40438adf1a7bc26af3b8d0a6705ea190462506e1/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390", size = 9681250 }, + { url = "https://files.pythonhosted.org/packages/30/2c/959dddef581b46e6209da82df3b78471e96260e2bc463f89d23b1bf0e52a/tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82", size = 2472003 }, + { url = "https://files.pythonhosted.org/packages/b3/46/e33a8c93907b631a99377ef4c5f817ab453d0b34f93529421f42ff559671/tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138", size = 2674684 }, ] [[package]] name = "tomli" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, - { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, - { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, - { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, - { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, - { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, - { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, - { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, - { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, - { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, - { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, - { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, - { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, - { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, - { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, - { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, - { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, - { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, - { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, - { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, - { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, - { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, - { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, - { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, - { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, - { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, - { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, - { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236 }, + { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084 }, + { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832 }, + { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052 }, + { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555 }, + { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128 }, + { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445 }, + { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165 }, + { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891 }, + { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796 }, + { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121 }, + { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070 }, + { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859 }, + { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296 }, + { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124 }, + { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698 }, + { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819 }, + { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766 }, + { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771 }, + { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586 }, + { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792 }, + { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909 }, + { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946 }, + { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705 }, + { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244 }, + { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637 }, + { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925 }, + { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045 }, + { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835 }, + { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109 }, + { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930 }, + { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964 }, + { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065 }, + { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088 }, + { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193 }, + { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488 }, + { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669 }, + { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709 }, + { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563 }, + { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756 }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408 }, ] [[package]] @@ -4612,53 +4596,53 @@ dependencies = [ { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681, upload-time = "2025-11-12T15:19:56.48Z" }, - { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036, upload-time = "2025-11-12T15:21:01.886Z" }, - { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861, upload-time = "2025-11-12T15:21:30.145Z" }, - { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222, upload-time = "2025-11-12T15:20:46.223Z" }, - { url = "https://files.pythonhosted.org/packages/15/db/c064112ac0089af3d2f7a2b5bfbabf4aa407a78b74f87889e524b91c5402/torch-2.9.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:62b3fd888277946918cba4478cf849303da5359f0fb4e3bfb86b0533ba2eaf8d", size = 104220430, upload-time = "2025-11-12T15:20:31.705Z" }, - { url = "https://files.pythonhosted.org/packages/56/be/76eaa36c9cd032d3b01b001e2c5a05943df75f26211f68fae79e62f87734/torch-2.9.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d033ff0ac3f5400df862a51bdde9bad83561f3739ea0046e68f5401ebfa67c1b", size = 899821446, upload-time = "2025-11-12T15:20:15.544Z" }, - { url = "https://files.pythonhosted.org/packages/47/cc/7a2949e38dfe3244c4df21f0e1c27bce8aedd6c604a587dd44fc21017cb4/torch-2.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:0d06b30a9207b7c3516a9e0102114024755a07045f0c1d2f2a56b1819ac06bcb", size = 110973074, upload-time = "2025-11-12T15:21:39.958Z" }, - { url = "https://files.pythonhosted.org/packages/1e/ce/7d251155a783fb2c1bb6837b2b7023c622a2070a0a72726ca1df47e7ea34/torch-2.9.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:52347912d868653e1528b47cafaf79b285b98be3f4f35d5955389b1b95224475", size = 74463887, upload-time = "2025-11-12T15:20:36.611Z" }, - { url = "https://files.pythonhosted.org/packages/0f/27/07c645c7673e73e53ded71705045d6cb5bae94c4b021b03aa8d03eee90ab/torch-2.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:da5f6f4d7f4940a173e5572791af238cb0b9e21b1aab592bd8b26da4c99f1cd6", size = 104126592, upload-time = "2025-11-12T15:20:41.62Z" }, - { url = "https://files.pythonhosted.org/packages/19/17/e377a460603132b00760511299fceba4102bd95db1a0ee788da21298ccff/torch-2.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:27331cd902fb4322252657f3902adf1c4f6acad9dcad81d8df3ae14c7c4f07c4", size = 899742281, upload-time = "2025-11-12T15:22:17.602Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1a/64f5769025db846a82567fa5b7d21dba4558a7234ee631712ee4771c436c/torch-2.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:81a285002d7b8cfd3fdf1b98aa8df138d41f1a8334fd9ea37511517cedf43083", size = 110940568, upload-time = "2025-11-12T15:21:18.689Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ab/07739fd776618e5882661d04c43f5b5586323e2f6a2d7d84aac20d8f20bd/torch-2.9.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:c0d25d1d8e531b8343bea0ed811d5d528958f1dcbd37e7245bc686273177ad7e", size = 74479191, upload-time = "2025-11-12T15:21:25.816Z" }, - { url = "https://files.pythonhosted.org/packages/20/60/8fc5e828d050bddfab469b3fe78e5ab9a7e53dda9c3bdc6a43d17ce99e63/torch-2.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c29455d2b910b98738131990394da3e50eea8291dfeb4b12de71ecf1fdeb21cb", size = 104135743, upload-time = "2025-11-12T15:21:34.936Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b7/6d3f80e6918213babddb2a37b46dbb14c15b14c5f473e347869a51f40e1f/torch-2.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:524de44cd13931208ba2c4bde9ec7741fd4ae6bfd06409a604fc32f6520c2bc9", size = 899749493, upload-time = "2025-11-12T15:24:36.356Z" }, - { url = "https://files.pythonhosted.org/packages/a6/47/c7843d69d6de8938c1cbb1eba426b1d48ddf375f101473d3e31a5fc52b74/torch-2.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:545844cc16b3f91e08ce3b40e9c2d77012dd33a48d505aed34b7740ed627a1b2", size = 110944162, upload-time = "2025-11-12T15:21:53.151Z" }, - { url = "https://files.pythonhosted.org/packages/28/0e/2a37247957e72c12151b33a01e4df651d9d155dd74d8cfcbfad15a79b44a/torch-2.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5be4bf7496f1e3ffb1dd44b672adb1ac3f081f204c5ca81eba6442f5f634df8e", size = 74830751, upload-time = "2025-11-12T15:21:43.792Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f7/7a18745edcd7b9ca2381aa03353647bca8aace91683c4975f19ac233809d/torch-2.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:30a3e170a84894f3652434b56d59a64a2c11366b0ed5776fab33c2439396bf9a", size = 104142929, upload-time = "2025-11-12T15:21:48.319Z" }, - { url = "https://files.pythonhosted.org/packages/f4/dd/f1c0d879f2863ef209e18823a988dc7a1bf40470750e3ebe927efdb9407f/torch-2.9.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8301a7b431e51764629208d0edaa4f9e4c33e6df0f2f90b90e261d623df6a4e2", size = 899748978, upload-time = "2025-11-12T15:23:04.568Z" }, - { url = "https://files.pythonhosted.org/packages/1f/9f/6986b83a53b4d043e36f3f898b798ab51f7f20fdf1a9b01a2720f445043d/torch-2.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2e1c42c0ae92bf803a4b2409fdfed85e30f9027a66887f5e7dcdbc014c7531db", size = 111176995, upload-time = "2025-11-12T15:22:01.618Z" }, - { url = "https://files.pythonhosted.org/packages/40/60/71c698b466dd01e65d0e9514b5405faae200c52a76901baf6906856f17e4/torch-2.9.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:2c14b3da5df416cf9cb5efab83aa3056f5b8cd8620b8fde81b4987ecab730587", size = 74480347, upload-time = "2025-11-12T15:21:57.648Z" }, - { url = "https://files.pythonhosted.org/packages/48/50/c4b5112546d0d13cc9eaa1c732b823d676a9f49ae8b6f97772f795874a03/torch-2.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1edee27a7c9897f4e0b7c14cfc2f3008c571921134522d5b9b5ec4ebbc69041a", size = 74433245, upload-time = "2025-11-12T15:22:39.027Z" }, - { url = "https://files.pythonhosted.org/packages/81/c9/2628f408f0518b3bae49c95f5af3728b6ab498c8624ab1e03a43dd53d650/torch-2.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:19d144d6b3e29921f1fc70503e9f2fc572cde6a5115c0c0de2f7ca8b1483e8b6", size = 104134804, upload-time = "2025-11-12T15:22:35.222Z" }, - { url = "https://files.pythonhosted.org/packages/28/fc/5bc91d6d831ae41bf6e9e6da6468f25330522e92347c9156eb3f1cb95956/torch-2.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:c432d04376f6d9767a9852ea0def7b47a7bbc8e7af3b16ac9cf9ce02b12851c9", size = 899747132, upload-time = "2025-11-12T15:23:36.068Z" }, - { url = "https://files.pythonhosted.org/packages/63/5d/e8d4e009e52b6b2cf1684bde2a6be157b96fb873732542fb2a9a99e85a83/torch-2.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:d187566a2cdc726fc80138c3cdb260970fab1c27e99f85452721f7759bbd554d", size = 110934845, upload-time = "2025-11-12T15:22:48.367Z" }, - { url = "https://files.pythonhosted.org/packages/bd/b2/2d15a52516b2ea3f414643b8de68fa4cb220d3877ac8b1028c83dc8ca1c4/torch-2.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cb10896a1f7fedaddbccc2017ce6ca9ecaaf990f0973bdfcf405439750118d2c", size = 74823558, upload-time = "2025-11-12T15:22:43.392Z" }, - { url = "https://files.pythonhosted.org/packages/86/5c/5b2e5d84f5b9850cd1e71af07524d8cbb74cba19379800f1f9f7c997fc70/torch-2.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0a2bd769944991c74acf0c4ef23603b9c777fdf7637f115605a4b2d8023110c7", size = 104145788, upload-time = "2025-11-12T15:23:52.109Z" }, - { url = "https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:07c8a9660bc9414c39cac530ac83b1fb1b679d7155824144a40a54f4a47bfa73", size = 899735500, upload-time = "2025-11-12T15:24:08.788Z" }, - { url = "https://files.pythonhosted.org/packages/db/2b/f7818f6ec88758dfd21da46b6cd46af9d1b3433e53ddbb19ad1e0da17f9b/torch-2.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c88d3299ddeb2b35dcc31753305612db485ab6f1823e37fb29451c8b2732b87e", size = 111163659, upload-time = "2025-11-12T15:23:20.009Z" }, + { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681 }, + { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036 }, + { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861 }, + { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222 }, + { url = "https://files.pythonhosted.org/packages/15/db/c064112ac0089af3d2f7a2b5bfbabf4aa407a78b74f87889e524b91c5402/torch-2.9.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:62b3fd888277946918cba4478cf849303da5359f0fb4e3bfb86b0533ba2eaf8d", size = 104220430 }, + { url = "https://files.pythonhosted.org/packages/56/be/76eaa36c9cd032d3b01b001e2c5a05943df75f26211f68fae79e62f87734/torch-2.9.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d033ff0ac3f5400df862a51bdde9bad83561f3739ea0046e68f5401ebfa67c1b", size = 899821446 }, + { url = "https://files.pythonhosted.org/packages/47/cc/7a2949e38dfe3244c4df21f0e1c27bce8aedd6c604a587dd44fc21017cb4/torch-2.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:0d06b30a9207b7c3516a9e0102114024755a07045f0c1d2f2a56b1819ac06bcb", size = 110973074 }, + { url = "https://files.pythonhosted.org/packages/1e/ce/7d251155a783fb2c1bb6837b2b7023c622a2070a0a72726ca1df47e7ea34/torch-2.9.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:52347912d868653e1528b47cafaf79b285b98be3f4f35d5955389b1b95224475", size = 74463887 }, + { url = "https://files.pythonhosted.org/packages/0f/27/07c645c7673e73e53ded71705045d6cb5bae94c4b021b03aa8d03eee90ab/torch-2.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:da5f6f4d7f4940a173e5572791af238cb0b9e21b1aab592bd8b26da4c99f1cd6", size = 104126592 }, + { url = "https://files.pythonhosted.org/packages/19/17/e377a460603132b00760511299fceba4102bd95db1a0ee788da21298ccff/torch-2.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:27331cd902fb4322252657f3902adf1c4f6acad9dcad81d8df3ae14c7c4f07c4", size = 899742281 }, + { url = "https://files.pythonhosted.org/packages/b1/1a/64f5769025db846a82567fa5b7d21dba4558a7234ee631712ee4771c436c/torch-2.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:81a285002d7b8cfd3fdf1b98aa8df138d41f1a8334fd9ea37511517cedf43083", size = 110940568 }, + { url = "https://files.pythonhosted.org/packages/6e/ab/07739fd776618e5882661d04c43f5b5586323e2f6a2d7d84aac20d8f20bd/torch-2.9.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:c0d25d1d8e531b8343bea0ed811d5d528958f1dcbd37e7245bc686273177ad7e", size = 74479191 }, + { url = "https://files.pythonhosted.org/packages/20/60/8fc5e828d050bddfab469b3fe78e5ab9a7e53dda9c3bdc6a43d17ce99e63/torch-2.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c29455d2b910b98738131990394da3e50eea8291dfeb4b12de71ecf1fdeb21cb", size = 104135743 }, + { url = "https://files.pythonhosted.org/packages/f2/b7/6d3f80e6918213babddb2a37b46dbb14c15b14c5f473e347869a51f40e1f/torch-2.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:524de44cd13931208ba2c4bde9ec7741fd4ae6bfd06409a604fc32f6520c2bc9", size = 899749493 }, + { url = "https://files.pythonhosted.org/packages/a6/47/c7843d69d6de8938c1cbb1eba426b1d48ddf375f101473d3e31a5fc52b74/torch-2.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:545844cc16b3f91e08ce3b40e9c2d77012dd33a48d505aed34b7740ed627a1b2", size = 110944162 }, + { url = "https://files.pythonhosted.org/packages/28/0e/2a37247957e72c12151b33a01e4df651d9d155dd74d8cfcbfad15a79b44a/torch-2.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5be4bf7496f1e3ffb1dd44b672adb1ac3f081f204c5ca81eba6442f5f634df8e", size = 74830751 }, + { url = "https://files.pythonhosted.org/packages/4b/f7/7a18745edcd7b9ca2381aa03353647bca8aace91683c4975f19ac233809d/torch-2.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:30a3e170a84894f3652434b56d59a64a2c11366b0ed5776fab33c2439396bf9a", size = 104142929 }, + { url = "https://files.pythonhosted.org/packages/f4/dd/f1c0d879f2863ef209e18823a988dc7a1bf40470750e3ebe927efdb9407f/torch-2.9.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8301a7b431e51764629208d0edaa4f9e4c33e6df0f2f90b90e261d623df6a4e2", size = 899748978 }, + { url = "https://files.pythonhosted.org/packages/1f/9f/6986b83a53b4d043e36f3f898b798ab51f7f20fdf1a9b01a2720f445043d/torch-2.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2e1c42c0ae92bf803a4b2409fdfed85e30f9027a66887f5e7dcdbc014c7531db", size = 111176995 }, + { url = "https://files.pythonhosted.org/packages/40/60/71c698b466dd01e65d0e9514b5405faae200c52a76901baf6906856f17e4/torch-2.9.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:2c14b3da5df416cf9cb5efab83aa3056f5b8cd8620b8fde81b4987ecab730587", size = 74480347 }, + { url = "https://files.pythonhosted.org/packages/48/50/c4b5112546d0d13cc9eaa1c732b823d676a9f49ae8b6f97772f795874a03/torch-2.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1edee27a7c9897f4e0b7c14cfc2f3008c571921134522d5b9b5ec4ebbc69041a", size = 74433245 }, + { url = "https://files.pythonhosted.org/packages/81/c9/2628f408f0518b3bae49c95f5af3728b6ab498c8624ab1e03a43dd53d650/torch-2.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:19d144d6b3e29921f1fc70503e9f2fc572cde6a5115c0c0de2f7ca8b1483e8b6", size = 104134804 }, + { url = "https://files.pythonhosted.org/packages/28/fc/5bc91d6d831ae41bf6e9e6da6468f25330522e92347c9156eb3f1cb95956/torch-2.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:c432d04376f6d9767a9852ea0def7b47a7bbc8e7af3b16ac9cf9ce02b12851c9", size = 899747132 }, + { url = "https://files.pythonhosted.org/packages/63/5d/e8d4e009e52b6b2cf1684bde2a6be157b96fb873732542fb2a9a99e85a83/torch-2.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:d187566a2cdc726fc80138c3cdb260970fab1c27e99f85452721f7759bbd554d", size = 110934845 }, + { url = "https://files.pythonhosted.org/packages/bd/b2/2d15a52516b2ea3f414643b8de68fa4cb220d3877ac8b1028c83dc8ca1c4/torch-2.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cb10896a1f7fedaddbccc2017ce6ca9ecaaf990f0973bdfcf405439750118d2c", size = 74823558 }, + { url = "https://files.pythonhosted.org/packages/86/5c/5b2e5d84f5b9850cd1e71af07524d8cbb74cba19379800f1f9f7c997fc70/torch-2.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0a2bd769944991c74acf0c4ef23603b9c777fdf7637f115605a4b2d8023110c7", size = 104145788 }, + { url = "https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:07c8a9660bc9414c39cac530ac83b1fb1b679d7155824144a40a54f4a47bfa73", size = 899735500 }, + { url = "https://files.pythonhosted.org/packages/db/2b/f7818f6ec88758dfd21da46b6cd46af9d1b3433e53ddbb19ad1e0da17f9b/torch-2.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c88d3299ddeb2b35dcc31753305612db485ab6f1823e37fb29451c8b2732b87e", size = 111163659 }, ] [[package]] name = "tornado" version = "6.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" } +sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" }, - { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" }, - { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" }, - { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" }, - { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" }, - { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" }, - { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" }, - { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" }, - { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" }, + { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563 }, + { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729 }, + { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295 }, + { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644 }, + { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878 }, + { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549 }, + { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973 }, + { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954 }, + { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023 }, + { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427 }, + { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456 }, ] [[package]] @@ -4668,18 +4652,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, ] [[package]] @@ -4699,9 +4683,9 @@ dependencies = [ { name = "tokenizers" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680, upload-time = "2025-11-25T15:51:30.139Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463, upload-time = "2025-11-25T15:51:26.493Z" }, + { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463 }, ] [[package]] @@ -4709,22 +4693,22 @@ name = "triton" version = "3.5.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692, upload-time = "2025-11-11T17:40:46.074Z" }, - { url = "https://files.pythonhosted.org/packages/b0/72/ec90c3519eaf168f22cb1757ad412f3a2add4782ad3a92861c9ad135d886/triton-3.5.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:61413522a48add32302353fdbaaf92daaaab06f6b5e3229940d21b5207f47579", size = 170425802, upload-time = "2025-11-11T17:40:53.209Z" }, - { url = "https://files.pythonhosted.org/packages/f2/50/9a8358d3ef58162c0a415d173cfb45b67de60176e1024f71fbc4d24c0b6d/triton-3.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d2c6b915a03888ab931a9fd3e55ba36785e1fe70cbea0b40c6ef93b20fc85232", size = 170470207, upload-time = "2025-11-11T17:41:00.253Z" }, - { url = "https://files.pythonhosted.org/packages/27/46/8c3bbb5b0a19313f50edcaa363b599e5a1a5ac9683ead82b9b80fe497c8d/triton-3.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3f4346b6ebbd4fad18773f5ba839114f4826037c9f2f34e0148894cd5dd3dba", size = 170470410, upload-time = "2025-11-11T17:41:06.319Z" }, - { url = "https://files.pythonhosted.org/packages/37/92/e97fcc6b2c27cdb87ce5ee063d77f8f26f19f06916aa680464c8104ef0f6/triton-3.5.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0b4d2c70127fca6a23e247f9348b8adde979d2e7a20391bfbabaac6aebc7e6a8", size = 170579924, upload-time = "2025-11-11T17:41:12.455Z" }, - { url = "https://files.pythonhosted.org/packages/a4/e6/c595c35e5c50c4bc56a7bac96493dad321e9e29b953b526bbbe20f9911d0/triton-3.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0637b1efb1db599a8e9dc960d53ab6e4637db7d4ab6630a0974705d77b14b60", size = 170480488, upload-time = "2025-11-11T17:41:18.222Z" }, - { url = "https://files.pythonhosted.org/packages/16/b5/b0d3d8b901b6a04ca38df5e24c27e53afb15b93624d7fd7d658c7cd9352a/triton-3.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bac7f7d959ad0f48c0e97d6643a1cc0fd5786fe61cb1f83b537c6b2d54776478", size = 170582192, upload-time = "2025-11-11T17:41:23.963Z" }, + { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692 }, + { url = "https://files.pythonhosted.org/packages/b0/72/ec90c3519eaf168f22cb1757ad412f3a2add4782ad3a92861c9ad135d886/triton-3.5.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:61413522a48add32302353fdbaaf92daaaab06f6b5e3229940d21b5207f47579", size = 170425802 }, + { url = "https://files.pythonhosted.org/packages/f2/50/9a8358d3ef58162c0a415d173cfb45b67de60176e1024f71fbc4d24c0b6d/triton-3.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d2c6b915a03888ab931a9fd3e55ba36785e1fe70cbea0b40c6ef93b20fc85232", size = 170470207 }, + { url = "https://files.pythonhosted.org/packages/27/46/8c3bbb5b0a19313f50edcaa363b599e5a1a5ac9683ead82b9b80fe497c8d/triton-3.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3f4346b6ebbd4fad18773f5ba839114f4826037c9f2f34e0148894cd5dd3dba", size = 170470410 }, + { url = "https://files.pythonhosted.org/packages/37/92/e97fcc6b2c27cdb87ce5ee063d77f8f26f19f06916aa680464c8104ef0f6/triton-3.5.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0b4d2c70127fca6a23e247f9348b8adde979d2e7a20391bfbabaac6aebc7e6a8", size = 170579924 }, + { url = "https://files.pythonhosted.org/packages/a4/e6/c595c35e5c50c4bc56a7bac96493dad321e9e29b953b526bbbe20f9911d0/triton-3.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0637b1efb1db599a8e9dc960d53ab6e4637db7d4ab6630a0974705d77b14b60", size = 170480488 }, + { url = "https://files.pythonhosted.org/packages/16/b5/b0d3d8b901b6a04ca38df5e24c27e53afb15b93624d7fd7d658c7cd9352a/triton-3.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bac7f7d959ad0f48c0e97d6643a1cc0fd5786fe61cb1f83b537c6b2d54776478", size = 170582192 }, ] [[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 } 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 }, ] [[package]] @@ -4735,9 +4719,9 @@ dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825 } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827 }, ] [[package]] @@ -4747,199 +4731,199 @@ 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 } 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 }, ] [[package]] name = "tzdata" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 }, ] [[package]] name = "uri-template" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140 }, ] [[package]] name = "urllib3" version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795 }, ] [[package]] name = "wcwidth" version = "0.2.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286 }, ] [[package]] name = "webcolors" version = "25.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905 }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, ] [[package]] name = "websocket-client" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, ] [[package]] name = "widgetsnbextension" version = "4.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503 }, ] [[package]] name = "xxhash" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, - { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, - { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, - { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, - { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, - { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, - { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, - { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, - { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, - { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, - { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, - { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, - { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, - { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, - { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, - { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, - { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, - { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, - { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, - { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, - { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, - { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, - { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, - { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, - { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, - { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, - { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" }, - { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" }, - { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" }, - { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" }, - { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" }, - { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" }, - { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" }, - { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" }, - { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" }, - { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" }, - { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" }, - { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738, upload-time = "2025-10-02T14:34:55.839Z" }, - { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821, upload-time = "2025-10-02T14:34:57.219Z" }, - { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127, upload-time = "2025-10-02T14:34:59.21Z" }, - { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975, upload-time = "2025-10-02T14:35:00.816Z" }, - { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241, upload-time = "2025-10-02T14:35:02.207Z" }, - { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471, upload-time = "2025-10-02T14:35:03.61Z" }, - { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936, upload-time = "2025-10-02T14:35:05.013Z" }, - { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440, upload-time = "2025-10-02T14:35:06.239Z" }, - { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990, upload-time = "2025-10-02T14:35:07.735Z" }, - { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689, upload-time = "2025-10-02T14:35:09.438Z" }, - { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068, upload-time = "2025-10-02T14:35:11.162Z" }, - { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495, upload-time = "2025-10-02T14:35:12.971Z" }, - { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620, upload-time = "2025-10-02T14:35:14.129Z" }, - { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542, upload-time = "2025-10-02T14:35:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880, upload-time = "2025-10-02T14:35:16.315Z" }, - { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956, upload-time = "2025-10-02T14:35:17.413Z" }, - { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072, upload-time = "2025-10-02T14:35:18.844Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409, upload-time = "2025-10-02T14:35:20.31Z" }, - { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736, upload-time = "2025-10-02T14:35:21.616Z" }, - { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833, upload-time = "2025-10-02T14:35:23.32Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348, upload-time = "2025-10-02T14:35:25.111Z" }, - { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070, upload-time = "2025-10-02T14:35:26.586Z" }, - { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907, upload-time = "2025-10-02T14:35:28.087Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839, upload-time = "2025-10-02T14:35:29.857Z" }, - { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304, upload-time = "2025-10-02T14:35:31.222Z" }, - { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930, upload-time = "2025-10-02T14:35:32.517Z" }, - { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787, upload-time = "2025-10-02T14:35:33.827Z" }, - { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, - { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, - { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, - { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, - { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, - { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, - { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, - { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, - { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, - { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, - { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, - { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, - { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, - { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, - { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, - { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, - { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, - { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, - { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, - { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, - { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, - { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, - { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, - { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, - { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, - { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, - { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, - { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, - { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845 }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807 }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786 }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830 }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606 }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872 }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217 }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139 }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669 }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018 }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058 }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628 }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577 }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487 }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863 }, + { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844 }, + { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809 }, + { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665 }, + { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550 }, + { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384 }, + { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749 }, + { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880 }, + { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912 }, + { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654 }, + { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867 }, + { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012 }, + { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409 }, + { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574 }, + { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481 }, + { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861 }, + { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744 }, + { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816 }, + { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035 }, + { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914 }, + { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163 }, + { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411 }, + { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883 }, + { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392 }, + { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898 }, + { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655 }, + { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001 }, + { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431 }, + { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617 }, + { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534 }, + { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876 }, + { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738 }, + { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821 }, + { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127 }, + { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975 }, + { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241 }, + { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471 }, + { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936 }, + { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440 }, + { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990 }, + { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689 }, + { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068 }, + { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495 }, + { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620 }, + { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542 }, + { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880 }, + { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956 }, + { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072 }, + { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409 }, + { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736 }, + { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833 }, + { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348 }, + { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070 }, + { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907 }, + { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839 }, + { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304 }, + { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930 }, + { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787 }, + { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916 }, + { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799 }, + { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044 }, + { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754 }, + { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846 }, + { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343 }, + { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074 }, + { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388 }, + { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614 }, + { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024 }, + { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541 }, + { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305 }, + { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848 }, + { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142 }, + { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547 }, + { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214 }, + { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290 }, + { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795 }, + { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955 }, + { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072 }, + { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579 }, + { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854 }, + { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965 }, + { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484 }, + { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162 }, + { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007 }, + { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956 }, + { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401 }, + { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083 }, + { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913 }, + { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586 }, + { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526 }, + { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898 }, + { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662 }, + { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056 }, + { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251 }, + { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481 }, + { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565 }, ] [[package]] @@ -4951,209 +4935,209 @@ 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/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, - { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, - { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, - { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, - { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, - { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, - { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, - { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, - { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, - { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, - { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, - { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, - { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, - { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, - { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, - { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, - { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, - { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, - { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, - { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, - { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, - { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, - { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, - { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, - { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, - { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, - { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, - { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, - { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, - { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, - { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, - { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, - { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, - { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, - { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, - { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, - { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, - { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, - { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, - { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, - { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, - { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, - { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, - { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, - { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, - { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, - { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, - { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517 }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495 }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400 }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545 }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598 }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893 }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240 }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965 }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026 }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637 }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082 }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811 }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223 }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118 }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852 }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012 }, + { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607 }, + { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027 }, + { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963 }, + { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406 }, + { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581 }, + { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924 }, + { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890 }, + { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819 }, + { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601 }, + { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072 }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311 }, + { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094 }, + { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944 }, + { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804 }, + { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858 }, + { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637 }, + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000 }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338 }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909 }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940 }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825 }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705 }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518 }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267 }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797 }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535 }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324 }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803 }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220 }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589 }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213 }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555 }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965 }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943 }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715 }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990 }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292 }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056 }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292 }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171 }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, ] [[package]] name = "zstandard" version = "0.25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/7a/28efd1d371f1acd037ac64ed1c5e2b41514a6cc937dd6ab6a13ab9f0702f/zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd", size = 795256, upload-time = "2025-09-14T22:15:56.415Z" }, - { url = "https://files.pythonhosted.org/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7", size = 640565, upload-time = "2025-09-14T22:15:58.177Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1b/4fdb2c12eb58f31f28c4d28e8dc36611dd7205df8452e63f52fb6261d13e/zstandard-0.25.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:ab85470ab54c2cb96e176f40342d9ed41e58ca5733be6a893b730e7af9c40550", size = 5345306, upload-time = "2025-09-14T22:16:00.165Z" }, - { url = "https://files.pythonhosted.org/packages/73/28/a44bdece01bca027b079f0e00be3b6bd89a4df180071da59a3dd7381665b/zstandard-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e05ab82ea7753354bb054b92e2f288afb750e6b439ff6ca78af52939ebbc476d", size = 5055561, upload-time = "2025-09-14T22:16:02.22Z" }, - { url = "https://files.pythonhosted.org/packages/e9/74/68341185a4f32b274e0fc3410d5ad0750497e1acc20bd0f5b5f64ce17785/zstandard-0.25.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:78228d8a6a1c177a96b94f7e2e8d012c55f9c760761980da16ae7546a15a8e9b", size = 5402214, upload-time = "2025-09-14T22:16:04.109Z" }, - { url = "https://files.pythonhosted.org/packages/8b/67/f92e64e748fd6aaffe01e2b75a083c0c4fd27abe1c8747fee4555fcee7dd/zstandard-0.25.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b6bd67528ee8b5c5f10255735abc21aa106931f0dbaf297c7be0c886353c3d0", size = 5449703, upload-time = "2025-09-14T22:16:06.312Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e5/6d36f92a197c3c17729a2125e29c169f460538a7d939a27eaaa6dcfcba8e/zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4b6d83057e713ff235a12e73916b6d356e3084fd3d14ced499d84240f3eecee0", size = 5556583, upload-time = "2025-09-14T22:16:08.457Z" }, - { url = "https://files.pythonhosted.org/packages/d7/83/41939e60d8d7ebfe2b747be022d0806953799140a702b90ffe214d557638/zstandard-0.25.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9174f4ed06f790a6869b41cba05b43eeb9a35f8993c4422ab853b705e8112bbd", size = 5045332, upload-time = "2025-09-14T22:16:10.444Z" }, - { url = "https://files.pythonhosted.org/packages/b3/87/d3ee185e3d1aa0133399893697ae91f221fda79deb61adbe998a7235c43f/zstandard-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25f8f3cd45087d089aef5ba3848cd9efe3ad41163d3400862fb42f81a3a46701", size = 5572283, upload-time = "2025-09-14T22:16:12.128Z" }, - { url = "https://files.pythonhosted.org/packages/0a/1d/58635ae6104df96671076ac7d4ae7816838ce7debd94aecf83e30b7121b0/zstandard-0.25.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3756b3e9da9b83da1796f8809dd57cb024f838b9eeafde28f3cb472012797ac1", size = 4959754, upload-time = "2025-09-14T22:16:14.225Z" }, - { url = "https://files.pythonhosted.org/packages/75/d6/57e9cb0a9983e9a229dd8fd2e6e96593ef2aa82a3907188436f22b111ccd/zstandard-0.25.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81dad8d145d8fd981b2962b686b2241d3a1ea07733e76a2f15435dfb7fb60150", size = 5266477, upload-time = "2025-09-14T22:16:16.343Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a9/ee891e5edf33a6ebce0a028726f0bbd8567effe20fe3d5808c42323e8542/zstandard-0.25.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a5a419712cf88862a45a23def0ae063686db3d324cec7edbe40509d1a79a0aab", size = 5440914, upload-time = "2025-09-14T22:16:18.453Z" }, - { url = "https://files.pythonhosted.org/packages/58/08/a8522c28c08031a9521f27abc6f78dbdee7312a7463dd2cfc658b813323b/zstandard-0.25.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e7360eae90809efd19b886e59a09dad07da4ca9ba096752e61a2e03c8aca188e", size = 5819847, upload-time = "2025-09-14T22:16:20.559Z" }, - { url = "https://files.pythonhosted.org/packages/6f/11/4c91411805c3f7b6f31c60e78ce347ca48f6f16d552fc659af6ec3b73202/zstandard-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:75ffc32a569fb049499e63ce68c743155477610532da1eb38e7f24bf7cd29e74", size = 5363131, upload-time = "2025-09-14T22:16:22.206Z" }, - { url = "https://files.pythonhosted.org/packages/ef/d6/8c4bd38a3b24c4c7676a7a3d8de85d6ee7a983602a734b9f9cdefb04a5d6/zstandard-0.25.0-cp310-cp310-win32.whl", hash = "sha256:106281ae350e494f4ac8a80470e66d1fe27e497052c8d9c3b95dc4cf1ade81aa", size = 436469, upload-time = "2025-09-14T22:16:25.002Z" }, - { url = "https://files.pythonhosted.org/packages/93/90/96d50ad417a8ace5f841b3228e93d1bb13e6ad356737f42e2dde30d8bd68/zstandard-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea9d54cc3d8064260114a0bbf3479fc4a98b21dffc89b3459edd506b69262f6e", size = 506100, upload-time = "2025-09-14T22:16:23.569Z" }, - { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, - { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, - { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, - { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, - { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, - { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, - { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, - { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, - { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, - { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, - { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, - { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, - { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, - { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, - { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, - { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, - { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, - { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, - { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, - { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, - { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, - { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, - { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, - { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, - { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, - { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, - { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, - { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, - { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, - { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, - { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, - { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, - { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, - { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, - { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, - { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, - { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, - { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, - { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, - { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, - { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, - { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, - { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, - { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, - { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, - { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, - { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, - { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, - { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, - { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, - { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, - { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, - { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, - { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, - { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/7a/28efd1d371f1acd037ac64ed1c5e2b41514a6cc937dd6ab6a13ab9f0702f/zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd", size = 795256 }, + { url = "https://files.pythonhosted.org/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7", size = 640565 }, + { url = "https://files.pythonhosted.org/packages/9d/1b/4fdb2c12eb58f31f28c4d28e8dc36611dd7205df8452e63f52fb6261d13e/zstandard-0.25.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:ab85470ab54c2cb96e176f40342d9ed41e58ca5733be6a893b730e7af9c40550", size = 5345306 }, + { url = "https://files.pythonhosted.org/packages/73/28/a44bdece01bca027b079f0e00be3b6bd89a4df180071da59a3dd7381665b/zstandard-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e05ab82ea7753354bb054b92e2f288afb750e6b439ff6ca78af52939ebbc476d", size = 5055561 }, + { url = "https://files.pythonhosted.org/packages/e9/74/68341185a4f32b274e0fc3410d5ad0750497e1acc20bd0f5b5f64ce17785/zstandard-0.25.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:78228d8a6a1c177a96b94f7e2e8d012c55f9c760761980da16ae7546a15a8e9b", size = 5402214 }, + { url = "https://files.pythonhosted.org/packages/8b/67/f92e64e748fd6aaffe01e2b75a083c0c4fd27abe1c8747fee4555fcee7dd/zstandard-0.25.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b6bd67528ee8b5c5f10255735abc21aa106931f0dbaf297c7be0c886353c3d0", size = 5449703 }, + { url = "https://files.pythonhosted.org/packages/fd/e5/6d36f92a197c3c17729a2125e29c169f460538a7d939a27eaaa6dcfcba8e/zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4b6d83057e713ff235a12e73916b6d356e3084fd3d14ced499d84240f3eecee0", size = 5556583 }, + { url = "https://files.pythonhosted.org/packages/d7/83/41939e60d8d7ebfe2b747be022d0806953799140a702b90ffe214d557638/zstandard-0.25.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9174f4ed06f790a6869b41cba05b43eeb9a35f8993c4422ab853b705e8112bbd", size = 5045332 }, + { url = "https://files.pythonhosted.org/packages/b3/87/d3ee185e3d1aa0133399893697ae91f221fda79deb61adbe998a7235c43f/zstandard-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25f8f3cd45087d089aef5ba3848cd9efe3ad41163d3400862fb42f81a3a46701", size = 5572283 }, + { url = "https://files.pythonhosted.org/packages/0a/1d/58635ae6104df96671076ac7d4ae7816838ce7debd94aecf83e30b7121b0/zstandard-0.25.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3756b3e9da9b83da1796f8809dd57cb024f838b9eeafde28f3cb472012797ac1", size = 4959754 }, + { url = "https://files.pythonhosted.org/packages/75/d6/57e9cb0a9983e9a229dd8fd2e6e96593ef2aa82a3907188436f22b111ccd/zstandard-0.25.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81dad8d145d8fd981b2962b686b2241d3a1ea07733e76a2f15435dfb7fb60150", size = 5266477 }, + { url = "https://files.pythonhosted.org/packages/d1/a9/ee891e5edf33a6ebce0a028726f0bbd8567effe20fe3d5808c42323e8542/zstandard-0.25.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a5a419712cf88862a45a23def0ae063686db3d324cec7edbe40509d1a79a0aab", size = 5440914 }, + { url = "https://files.pythonhosted.org/packages/58/08/a8522c28c08031a9521f27abc6f78dbdee7312a7463dd2cfc658b813323b/zstandard-0.25.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e7360eae90809efd19b886e59a09dad07da4ca9ba096752e61a2e03c8aca188e", size = 5819847 }, + { url = "https://files.pythonhosted.org/packages/6f/11/4c91411805c3f7b6f31c60e78ce347ca48f6f16d552fc659af6ec3b73202/zstandard-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:75ffc32a569fb049499e63ce68c743155477610532da1eb38e7f24bf7cd29e74", size = 5363131 }, + { url = "https://files.pythonhosted.org/packages/ef/d6/8c4bd38a3b24c4c7676a7a3d8de85d6ee7a983602a734b9f9cdefb04a5d6/zstandard-0.25.0-cp310-cp310-win32.whl", hash = "sha256:106281ae350e494f4ac8a80470e66d1fe27e497052c8d9c3b95dc4cf1ade81aa", size = 436469 }, + { url = "https://files.pythonhosted.org/packages/93/90/96d50ad417a8ace5f841b3228e93d1bb13e6ad356737f42e2dde30d8bd68/zstandard-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea9d54cc3d8064260114a0bbf3479fc4a98b21dffc89b3459edd506b69262f6e", size = 506100 }, + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254 }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559 }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020 }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126 }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390 }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914 }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635 }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277 }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377 }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493 }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018 }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672 }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753 }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047 }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484 }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183 }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533 }, + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738 }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436 }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019 }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012 }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148 }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652 }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993 }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806 }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659 }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933 }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008 }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517 }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292 }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237 }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922 }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276 }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679 }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735 }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440 }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070 }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001 }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120 }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230 }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173 }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736 }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368 }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022 }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889 }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952 }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054 }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113 }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936 }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232 }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671 }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887 }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658 }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849 }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095 }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751 }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818 }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402 }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108 }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248 }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330 }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123 }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591 }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513 }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118 }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940 }, ] diff --git a/workshop/README.md b/workshop/README.md deleted file mode 100644 index c2f57d1..0000000 --- a/workshop/README.md +++ /dev/null @@ -1,253 +0,0 @@ -# Context Engineering Workshop - -![Redis](https://redis.io/wp-content/uploads/2024/04/Logotype.svg?auto=webp&quality=85,75&width=120) - -## 🎯 Workshop Overview - -This condensed workshop covers the essential concepts of context engineering for AI agents. You'll learn how to build intelligent agents that remember, retrieve, and reason with context. - -**What You'll Build:** A course advisor agent that can: -- Search courses using semantic RAG -- Remember student preferences across sessions -- Make transparent reasoning decisions -- Achieve 91% token reduction through context engineering - -## 🧠 Workshop Philosophy - -This workshop follows a deliberate learning progression: - -1. **Foundations First** — Understand the "why" (context types, constraints) before the "how" -2. **Data Engineering Before RAG** — Learn to prepare data properly before implementing retrieval -3. **Chunking is a Design Choice** — For structured data like course catalogs, "don't chunk" is often best -4. **Progressive Disclosure** — The key pattern: summaries for all, details for top matches -5. **Build Up to Agents** — Each module adds capabilities until you have a full agent - -## ⏱️ Schedule - -| Module | Time | Notebook | Lines | Key Concepts | -|--------|------|----------|-------|--------------| -| **1. Introduction** | 45 min | `01_introduction_to_context_engineering.ipynb` | ~600 | Four context types, context failures, token budgeting | -| **2. RAG Essentials** | 60 min | `02_rag_essentials.ipynb` | ~1,000 | Vector embeddings, semantic search, HierarchicalCourseManager | -| **3. Data Engineering** | 75 min | `03_data_engineering.ipynb` | ~960 | Data pipeline, chunking strategies, real PDF examples | -| **4. Memory Systems** | 90 min | `04_memory_systems.ipynb` | ~2,000 | Working memory, long-term memory, memory-enhanced RAG | - -**Total:** ~4.5 hours | ~4,560 lines of comprehensive content - -## 🔧 Prerequisites - -### Required Software -- Python 3.11+ -- Docker (for Redis and Agent Memory Server) -- Jupyter Lab or VS Code with Jupyter extension - -### API Keys -- OpenAI API key (for embeddings and LLM) - -### Services Required -- **Redis** (port 6379) - Required for all modules -- **Agent Memory Server** (port 8088) - Required for Module 4 (Memory Systems) - - Must be started with `OPENAI_API_KEY` environment variable for long-term memory features - -## 🚀 Quick Setup - -### 1. Clone and Install - -```bash -# Navigate to workshop directory -cd workshop - -# Install the package (from repository root) -cd .. -pip install -e . -cd workshop -``` - -### 2. Environment Variables - -Create a `.env` file in the repository root: - -```bash -# Copy the example file -cp .env.example .env - -# Edit and add your OpenAI API key -``` - -Your `.env` file should contain: - -```bash -# Required -OPENAI_API_KEY=sk-your-key-here - -# Optional (defaults provided) -REDIS_URL=redis://localhost:6379 -AGENT_MEMORY_SERVER_URL=http://localhost:8088 -REDIS_INDEX_NAME=course_catalog -``` - -### 3. Start Services - -```bash -# From the repository root, start all services -docker-compose up -d -``` - -### 4. Verify Setup - -```bash -# Check Redis -docker exec redis redis-cli ping -# Expected: PONG - -# Check Agent Memory Server -curl http://localhost:8088/v1/health -# Expected: {"now":} -``` - -## 📚 Notebooks Overview - -### Module 1: Introduction to Context Engineering (45 min) - -**The "Why" of Context Engineering** *(Source: Redis Training)* - -- **The Problem**: The "clerk behind glass" narrative — why AI agents fail without context -- **Four Context Types**: System, User, Conversation, Retrieved (with Olivia Jansen example) -- **Live Code**: Build complete context and call OpenAI API -- **Token Analysis**: Measure token usage across context types with `estimate_tokens()` and `analyze_context_usage()` -- **Strategy Comparison**: Compare minimal vs. with_user vs. with_retrieval approaches side-by-side -- **Token Economics**: Understanding context window limits and budgeting -- **Context Failures**: Poisoning, Distraction, Confusion, Clash -- **Context Rot**: Why longer context ≠ better context -- **Best Practices**: 5 essential practices for production context engineering - -### Module 2: RAG Essentials (60 min) - ~1,000 lines - -**Understanding Retrieval-Augmented Generation** *(Comprehensive content from Section 2)* - -- **Vector Embeddings**: How semantic search captures meaning (with live similarity matrix demo) -- **RAG Pipeline**: Query → Embed → Search → Retrieve → Assemble → Generate -- **HierarchicalCourseManager**: Two-tier retrieval system - - Tier 1: Vector index of course summaries (for search) - - Tier 2: Hash storage of full course details (for deep dives) -- **HierarchicalContextAssembler**: Progressive disclosure pattern - - `assemble_summary_only_context()` - Lightweight overview - - `assemble_hierarchical_context()` - Full details for top matches - - `assemble_with_budget()` - Token-aware assembly -- **Hands-on**: Build course search with Redis Vector, compare search strategies - -### Module 3: Data Engineering for Context (75 min) - ~960 lines - -**Preparing Data for RAG** *(Comprehensive content from Section 2)* - -- **Data Pipeline**: Extract → Clean → Transform → Optimize → Store -- **Three Engineering Approaches**: - - RAG (Semantic Search) - Dynamic retrieval - - Structured Views (Pre-Computed) - Static summaries - - Hybrid - Best of both worlds -- **Chunking Strategies** (with LangChain): - - Document-Based (Structure-Aware) - - Fixed-Size (Token-Based with RecursiveCharacterTextSplitter) - - Semantic (Meaning-Based with SemanticChunker) - - When NOT to chunk: Structured records like courses -- **Real-World Examples**: - - Uses actual arXiv research paper (arxiv_2504_02268.pdf) - - Multimodal content handling: tables, formulas, figures - - Working code for PDF extraction and chunking -- **Production Pipelines**: Request-Time, Batch, Event-Driven architectures -- **Quality Metrics**: Relevance, Completeness, Efficiency, Accuracy - -### Module 4: Memory Systems (90 min) - ~2,000 lines - -**Adding Persistence to Your Agent** *(Comprehensive content from Section 3)* - -- **The Grounding Problem**: Why agents need memory for reference resolution -- **Working Memory**: Session-based conversation continuity - - Multi-turn conversation demos (Turn 1, 2, 3) - - Pronoun resolution ("it", "the first one", "those prerequisites") -- **Long-term Memory**: Cross-session knowledge persistence - - Semantic memories (facts) vs Episodic memories (events) - - Topics and filtering - - Cross-session persistence verification -- **Memory-Enhanced RAG**: All four context types working together - - System + User + Conversation + Retrieved -- **Agent Memory Server**: Automatic compression and semantic extraction -- **Hands-on**: Complete memory-enhanced course advisor - -## 🏃 Executing the Notebooks - -All workshop notebooks have been tested and execute successfully. To run them: - -```bash -# From the repository root -cd workshop - -# Execute a specific notebook -jupyter execute 02_rag_essentials.ipynb --inplace - -# Or run all notebooks -for nb in 02_rag_essentials.ipynb 03_data_engineering.ipynb 04_memory_systems.ipynb; do - jupyter execute $nb --inplace -done -``` - -**Note for Module 4 (Memory Systems):** -The Agent Memory Server must be running with the `OPENAI_API_KEY` environment variable set: - -```bash -# Restart Agent Memory Server with API key (from repository root) -source .env -docker stop agent-memory-server 2>/dev/null -docker rm agent-memory-server 2>/dev/null -docker run -d --name agent-memory-server \ - -p 8088:8000 \ - -e REDIS_URL=redis://host.docker.internal:6379 \ - -e OPENAI_API_KEY=$OPENAI_API_KEY \ - -e LOG_LEVEL=INFO \ - ghcr.io/redis/agent-memory-server:0.12.3 \ - agent-memory api --host 0.0.0.0 --port 8000 --no-worker -``` - -## 🗂️ Data - -This workshop uses **hierarchical course data** for progressive disclosure: - -- **CourseSummary**: Lightweight overview (~60 tokens each) -- **CourseDetails**: Full syllabus and assignments (~200+ tokens each) - -Data location: `src/redis_context_course/data/hierarchical/hierarchical_courses.json` - -## 🔧 Technical Notes - -### HierarchicalCourseManager vs CourseManager - -All workshop modules use `HierarchicalCourseManager` for consistency: - -- **HierarchicalCourseManager**: Two-tier retrieval (summaries + details) - - `search_summaries()` - Search course summaries - - `fetch_details()` - Get full course details - - `hierarchical_search()` - Combined search with progressive disclosure -- **CourseManager**: Basic single-tier retrieval (used in source notebooks) - -### File Paths - -Workshop notebooks use relative paths from the `workshop/` directory: -- `../reference-agent` - Reference agent code -- `../src/redis_context_course` - Core library - -## 📖 Related Resources - -### Full Course (15-20 hours) -- `notebooks/` - Complete 11-notebook curriculum -- `progressive_agents/` - 6-stage agent progression - -### Reference Implementation -- `src/redis_context_course/` - Production-ready code - -### Documentation -- [Redis Vector Search](https://redis.io/docs/stack/search/reference/vectors/) -- [Agent Memory Server](https://github.com/redis/agent-memory-server) - ---- - -**Ready to start?** Open `01_introduction_to_context_engineering.ipynb` and let's build some context-aware agents! 🚀 -