diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml
index b4984bdf9..299e831e9 100644
--- a/.github/actions/setup-environment/action.yml
+++ b/.github/actions/setup-environment/action.yml
@@ -26,5 +26,5 @@ runs:
- name: Install codecov
shell: bash
run: |
- uv tool install codecov-cli@10.0.1 --python 3.10
+ uv tool install codecov-cli@10.0.1
uv tool update-shell
diff --git a/.gitignore b/.gitignore
index 54c7b88c0..2c38ccae0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@ supabase/config.toml
**/scripts/*.md
**/scripts/Personal/*
**/infrastructure/aws_infra/.terraform/*
+pyrightconfig.json
Edwards Scratchpad.ipynb
# Allowing .env files to exist in repository, but not allowing updates
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7f8f20c68..eeea3f677 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -80,27 +80,13 @@ repos:
rev: 39.169.3
hooks:
- id: renovate-config-validator
+
- repo: https://github.com/astral-sh/uv-pre-commit
rev: "0.5.31"
hooks:
- id: uv-sync
args: ["--frozen", "--all-packages", "--all-extras"]
- - repo: "local"
- hooks:
- # Disabled as part of LFS removal.
- # - id: disallowed-words-check
- # name: Check for disallowed words
- # entry: scripts/disallowed-words-check.sh
- # language: script
- # files: '' # Check all files
- - id: generate-runner-imports
- name: Generate Runner Imports
- entry: bash -c "uv run --frozen python -m codegen.gscli.cli generate runner-imports src/codegen/shared/compilation/function_imports.py"
- language: system
- pass_filenames: false
- always_run: true
-
- repo: https://github.com/hukkin/mdformat
rev: 0.7.22 # Use the ref you want to point at
hooks:
diff --git a/architecture/2. parsing/B. AST Construction.md b/architecture/2. parsing/B. AST Construction.md
index c6484aaba..06a1cd48c 100644
--- a/architecture/2. parsing/B. AST Construction.md
+++ b/architecture/2. parsing/B. AST Construction.md
@@ -74,4 +74,4 @@ Statements have another layer of complexity. They are essentially pattern based
## Next Step
-After the AST is constructed, the system moves on to [Import Resolution](../3.%20imports-exports/A.%20Imports.md) to analyze module dependencies and resolve symbols across files.
+After the AST is constructed, the system moves on to [Directory Parsing](./C.%20Directory%20Parsing.md) to build a hierarchical representation of the codebase's directory structure.
diff --git a/architecture/2. parsing/C. Directory Parsing.md b/architecture/2. parsing/C. Directory Parsing.md
new file mode 100644
index 000000000..f25de2e29
--- /dev/null
+++ b/architecture/2. parsing/C. Directory Parsing.md
@@ -0,0 +1,50 @@
+# Directory Parsing
+
+The Directory Parsing system is responsible for creating and maintaining a hierarchical representation of the codebase's directory structure in memory. Directories do not hold references to the file itself, but instead holds the names to the files and does a dynamic lookup when needed.
+
+In addition to providing a more cohesive API for listing directory files, the Directory API is also used for [TSConfig](../3.%20imports-exports/C.%20TSConfig.md)-based (Import Resolution)[../3.%20imports-exports/A.%20Imports.md].
+
+## Core Components
+
+The Directory Tree is constructed during the initial build_graph step in codebase_context.py, and is recreated from scratch on every re-sync. More details are below:
+
+## Directory Tree Construction
+
+The directory tree is built through the following process:
+
+1. The `build_directory_tree` method in `CodebaseContext` is called during graph initialization or when the codebase structure changes.
+1. The method iterates through all files in the repository, creating directory objects for each directory path encountered.
+1. For each file, it adds the file to its parent directory using the `_add_file` method.
+1. Directories are created recursively as needed using the `get_directory` method with create_on_missing=True\`.
+
+## Directory Representation
+
+The `Directory` class provides a rich interface for working with directories:
+
+- **Hierarchy Navigation**: Access parent directories and subdirectories
+- **File Access**: Retrieve files by name or extension
+- **Symbol Access**: Find symbols (classes, functions, etc.) within files in the directory
+- **Directory Operations**: Rename, remove, or update directories
+
+Each `Directory` instance maintains:
+
+- A reference to its parent directory
+- Lists of files and subdirectories
+- Methods to recursively traverse the directory tree
+
+## File Representation
+
+Files are represented by the `File` class and its subclasses:
+
+- `File`: Base class for all files, supporting basic operations like reading and writing content
+- `SourceFile`: Specialized class for source code files that can be parsed into an AST
+
+Files maintain references to:
+
+- Their parent directory
+- Their content (loaded dynamically to preserve the source of truth)
+- For source files, the parsed AST and symbols
+
+## Next Step
+
+After the directory structure is parsed, the system can perform [Import Resolution](../3.%20imports-exports/A.%20Imports.md) to analyze module dependencies and resolve symbols across files.
diff --git a/architecture/3. imports-exports/A. Imports.md b/architecture/3. imports-exports/A. Imports.md
index 09d70d902..cca5951ab 100644
--- a/architecture/3. imports-exports/A. Imports.md
+++ b/architecture/3. imports-exports/A. Imports.md
@@ -1,7 +1,60 @@
# Import Resolution
-TODO
+Import resolution follows AST construction in the code analysis pipeline. It identifies dependencies between modules and builds a graph of relationships across the codebase.
+
+> NOTE: This is an actively evolving part of Codegen SDK, so some details here may be imcomplete, outdated, or incorrect.
+
+## Purpose
+
+The import resolution system serves these purposes:
+
+1. **Dependency Tracking**: Maps relationships between files by resolving import statements.
+1. **Symbol Resolution**: Connects imported symbols to their definitions.
+1. **Module Graph Construction**: Builds a directed graph of module dependencies.
+1. **(WIP) Cross-Language Support**: Provides implementations for different programming languages.
+
+## Core Components
+
+### ImportResolution Class
+
+The `ImportResolution` class represents the outcome of resolving an import statement. It contains:
+
+- The source file containing the imported symbol
+- The specific symbol being imported (if applicable)
+- Whether the import references an entire file/module
+
+### Import Base Class
+
+The `Import` class is the foundation for language-specific import implementations. It:
+
+- Stores metadata about the import (module path, symbol name, alias)
+- Provides the abstract `resolve_import()` method
+- Adds symbol resolution edges to the codebase graph
+
+### Language-Specific Implementations
+
+#### Python Import Resolution
+
+The `PyImport` class extends the base `Import` class with Python-specific logic:
+
+- Handles relative imports
+- Supports module imports, named imports, and wildcard imports
+- Resolves imports using configurable resolution paths and `sys.path`
+- Handles special cases like `__init__.py` files
+
+#### TypeScript Import Resolution
+
+The `TSImport` class implements TypeScript-specific resolution:
+
+- Supports named imports, default imports, and namespace imports
+- Handles type imports and dynamic imports
+- Resolves imports using TSConfig path mappings
+- Supports file extension resolution
+
+## Implementation
+
+After file and directory parse, we loop through all import nodes and perform `add_symbol_resolution_edge`. This then invokes the language-specific `resolve_import` method that converts the import statement into a resolvable `ImportResolution` object (or None if the import cannot be resolved). This import symbol and the `ImportResolution` object are then used to add a symbol resolution edge to the graph, where it can then be used in future steps to resolve symbols.
## Next Step
-After import resolution, the system analyzes [Export Analysis](./B.%20Exports.md) and handles [TSConfig Support](./C.%20TSConfig.md) for TypeScript projects. This is followed by comprehensive [Type Analysis](../4.%20type-analysis/A.%20Type%20Analysis.md).
+After import resolution, the system analyzes [Export Analysis](./B.%20Exports.md) and handles [TSConfig Support](./C.%20TSConfig.md) for TypeScript projects. This is followed by [Type Analysis](../4.%20type-analysis/A.%20Type%20Analysis.md).
diff --git a/architecture/3. imports-exports/B. Exports.md b/architecture/3. imports-exports/B. Exports.md
index 9da67fcb4..0e42c98c4 100644
--- a/architecture/3. imports-exports/B. Exports.md
+++ b/architecture/3. imports-exports/B. Exports.md
@@ -1,6 +1,74 @@
# Export Analysis
-TODO
+Some languages contain additional metadata on "exported" symbols, specifying which symbols are made available to other modules. Export analysis follows import resolution in the code analysis pipeline. It identifies and processes exported symbols from modules, enabling the system to track what each module makes available to others.
+
+## Core Components
+
+### Export Base Class
+
+The `Export` class serves as the foundation for language-specific export implementations. It:
+
+- Stores metadata about the export (symbol name, is default, etc.)
+- Tracks the relationship between the export and its declared symbol
+- Adds export edges to the codebase graph
+
+### TypeScript Export Implementation
+
+The `TSExport` class implements TypeScript-specific export handling:
+
+- Supports various export styles (named exports, default exports, re-exports)
+- Handles export declarations with and without values
+- Processes wildcard exports (`export * from 'module'`)
+- Manages export statements with multiple exports
+
+#### Export Types and Symbol Resolution
+
+The TypeScript implementation handles several types of exports:
+
+1. **Declaration Exports**
+
+ - Function declarations (including generators)
+ - Class declarations
+ - Interface declarations
+ - Type alias declarations
+ - Enum declarations
+ - Namespace declarations
+ - Variable/constant declarations
+
+1. **Value Exports**
+
+ - Object literals with property exports
+ - Arrow functions and function expressions
+ - Classes and class expressions
+ - Assignment expressions
+ - Primitive values and expressions
+
+1. **Special Export Forms**
+
+ - Wildcard exports (`export * from 'module'`)
+ - Named re-exports (`export { name as alias } from 'module'`)
+ - Default exports with various value types
+
+#### Symbol Tracking and Dependencies
+
+The export system:
+
+- Maintains relationships between exported symbols and their declarations
+- Validates export names match their declared symbols
+- Tracks dependencies through the codebase graph
+- Handles complex scenarios like:
+ - Shorthand property exports in objects
+ - Nested function and class declarations
+ - Re-exports from other modules
+
+#### Integration with Type System
+
+Exports are tightly integrated with the type system:
+
+- Exported type declarations are properly tracked
+- Symbol resolution considers both value and type exports
+- Re-exports preserve type information
+- Export edges in the codebase graph maintain type relationships
## Next Step
diff --git a/architecture/3. imports-exports/C. TSConfig.md b/architecture/3. imports-exports/C. TSConfig.md
index e9c77ae0c..b2362a7c8 100644
--- a/architecture/3. imports-exports/C. TSConfig.md
+++ b/architecture/3. imports-exports/C. TSConfig.md
@@ -1,6 +1,80 @@
# TSConfig Support
-TODO
+TSConfig support is a critical component for TypeScript projects in the import resolution system. It processes TypeScript configuration files (tsconfig.json) to correctly resolve module paths and dependencies.
+
+## Purpose
+
+The TSConfig support system serves these purposes:
+
+1. **Path Mapping**: Resolves custom module path aliases defined in the tsconfig.json file.
+1. **Base URL Resolution**: Handles non-relative module imports using the baseUrl configuration.
+1. **Project References**: Manages dependencies between TypeScript projects using the references field.
+1. **Directory Structure**: Respects rootDir and outDir settings for maintaining proper directory structures.
+
+## Core Components
+
+### TSConfig Class
+
+The `TSConfig` class represents a parsed TypeScript configuration file. It:
+
+- Parses and stores the configuration settings from tsconfig.json
+- Handles inheritance through the "extends" field
+- Provides methods for translating between import paths and absolute file paths
+- Caches computed values for performance optimization
+
+## Configuration Processing
+
+### Configuration Inheritance
+
+TSConfig files can extend other configuration files through the "extends" field:
+
+1. Base configurations are loaded and parsed first
+1. Child configurations inherit and can override settings from their parent
+1. Path mappings, base URLs, and other settings are merged appropriately
+
+### Path Mapping Resolution
+
+The system processes the "paths" field in tsconfig.json to create a mapping between import aliases and file paths:
+
+1. Path patterns are normalized (removing wildcards, trailing slashes)
+1. Relative paths are converted to absolute paths
+1. Mappings are stored for efficient lookup during import resolution
+
+### Project References
+
+The "references" field defines dependencies between TypeScript projects:
+
+1. Referenced projects are identified and loaded
+1. Their configurations are analyzed to determine import paths
+1. Import resolution can cross project boundaries using these references
+
+## Import Resolution Process
+
+### Path Translation
+
+When resolving an import path in TypeScript:
+
+1. Check if the path matches any path alias in the tsconfig.json
+1. If a match is found, translate the path according to the mapping
+1. Apply baseUrl resolution for non-relative imports
+1. Handle project references for cross-project imports
+
+### Optimization Techniques
+
+The system employs several optimizations:
+
+1. Caching computed values to avoid redundant processing
+1. Early path checking for common patterns (e.g., paths starting with "@" or "~")
+1. Hierarchical resolution that respects the configuration inheritance chain
+
+## Integration with Import Resolution
+
+The TSConfig support integrates with the broader import resolution system:
+
+1. Each TypeScript file is associated with its nearest tsconfig.json
+1. Import statements are processed using the file's associated configuration
+1. Path mappings are applied during the module resolution process
+1. Project references are considered when resolving imports across project boundaries
## Next Step
diff --git a/architecture/5. performing-edits/A. Edit Operations.md b/architecture/5. performing-edits/A. Edit Operations.md
deleted file mode 100644
index 850b8e103..000000000
--- a/architecture/5. performing-edits/A. Edit Operations.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Edit Operations
-
-TODO
-
-## Next Step
-
-After preparing edits, they are managed by the [Transaction Manager](./B.%20Transaction%20Manager.md) to ensure consistency and atomicity.
diff --git a/architecture/5. performing-edits/A. Transactions.md b/architecture/5. performing-edits/A. Transactions.md
new file mode 100644
index 000000000..c27c7e65f
--- /dev/null
+++ b/architecture/5. performing-edits/A. Transactions.md
@@ -0,0 +1,54 @@
+# Transactions
+
+Transactions represent atomic changes to files in the codebase. Each transaction defines a specific modification that can be queued, validated, and executed.
+
+## Transaction Types
+
+The transaction system is built around a base `Transaction` class with specialized subclasses:
+
+### Content Transactions
+
+- **RemoveTransaction**: Removes content between specified byte positions
+- **InsertTransaction**: Inserts new content at a specified byte position
+- **EditTransaction**: Replaces content between specified byte positions
+
+### File Transactions
+
+- **FileAddTransaction**: Creates a new file
+- **FileRenameTransaction**: Renames an existing file
+- **FileRemoveTransaction**: Deletes a file
+
+## Transaction Priority
+
+Transactions are executed in a specific order defined by the `TransactionPriority` enum:
+
+1. **Remove** (highest priority)
+1. **Edit**
+1. **Insert**
+1. **FileAdd**
+1. **FileRename**
+1. **FileRemove**
+
+This ordering ensures that content is removed before editing or inserting, and that all content operations happen before file operations.
+
+## Key Concepts
+
+### Byte-Level Operations
+
+All content transactions operate at the byte level rather than on lines or characters. This provides precise control over modifications and allows transactions to work with any file type, regardless of encoding or line ending conventions.
+
+### Content Generation
+
+Transactions support both static content (direct strings) and dynamic content (generated at execution time). This flexibility allows for complex transformations where the new content depends on the state of the codebase at execution time.
+
+Most content transactions use static content, but dynamic content is supported for rare cases where the new content depends on the state of other transactions. One common example is handling whitespace during add and remove transactions.
+
+### File Operations
+
+File transactions are used to create, rename, and delete files.
+
+> NOTE: It is important to note that most file transactions such as `FileAddTransaction` are no-ops (AKA skiping Transaction Manager) and instead applied immediately once the `create_file` API is called. This allows for created files to be immediately available for edit and use. The reason file operations are still added to Transaction Manager is to help with optimizing graph re-parse and diff generation. (Keeping track of which files exist and don't exist anymore).
+
+## Next Step
+
+After understanding the transaction system, they are managed by the [Transaction Manager](./B.%20Transaction%20Manager.md) to ensure consistency and atomicity.
diff --git a/architecture/5. performing-edits/B. Transaction Manager.md b/architecture/5. performing-edits/B. Transaction Manager.md
index a41d91270..4ed78a750 100644
--- a/architecture/5. performing-edits/B. Transaction Manager.md
+++ b/architecture/5. performing-edits/B. Transaction Manager.md
@@ -1,6 +1,92 @@
# Transaction Manager
-TODO
+The Transaction Manager coordinates the execution of transactions across multiple files, handling conflict resolution, and enforcing resource limits.
+
+## High-level Concept
+
+Since all node operations are on byte positions of the original file, multiple operations that change the total byte length of the file will result in offset errors and broken code.
+
+Give this example over here:
+
+```
+Original: FooBar
+Operations: Remove "Foo" (bytes 0-3), Insert "Hello" (bytes 0-5)
+ Remove "Bar" (bytes 3-6), Insert "World" (bytes 3-7)
+```
+
+If these operations were applied in order, the result would be:
+
+```
+Result: FooBar
+Operation: Remove "Foo" (bytes 0-3), Insert "Hello" (bytes 0-5)
+Result: HelloBar
+Operation: Remove "Bar" (bytes 3-6), Insert "World" (bytes 3-7)
+Result: HelWorldar
+```
+
+Resulting in an invalid output.
+
+⭐ The key with TransactionManager is that it queues up all transactions in a given Codemod run, the applies all of the ***backwards*** from the last byte range to the first. Given the same example as above but applied backwards:
+
+```
+Result: FooBar
+Operation: Remove "Bar" (bytes 3-6), Insert "World" (bytes 3-7)
+Result: FooWorld
+Operation: Remove "Foo" (bytes 0-3), Insert "Hello" (bytes 0-5)
+Result: HelloWorld
+```
+
+TransactionManager also performs some additional operations such detecting conflicts and coordinating (some basic) conflict resolutions. Overall, the core responsibilities are as follows:
+
+1. **Transaction Queueing**: Maintains a queue of pending transactions organized by file
+1. **Conflict Resolution**: Detects and resolves conflicts between transactions
+1. **Transaction Execution**: Applies transactions in the correct order
+1. **Resource Management**: Enforces limits on transaction count and execution time
+1. **Change Tracking**: Generates diffs for applied changes
+
+## Sorting Transactions
+
+Before execution, transactions are sorted based on (in this priority):
+
+1. Position in the file (higher byte positions first)
+1. Transaction type (following the priority order)
+1. User-defined priority
+1. Creation order
+
+This sorting ensures that transactions are applied in a deterministic order that minimizes conflicts. Larger byte ranges are always edited first, removals happen before insertions, and older transactions are applied before newer ones.
+
+## Conflict Resolution
+
+### Conflict Types
+
+The manager identifies several types of conflicts:
+
+1. **Overlapping Transactions**: Multiple transactions affecting the same byte range
+1. **Contained Transactions**: One transaction completely contained within another
+1. **Adjacent Transactions**: Transactions affecting adjacent byte ranges
+
+In it's current implementation, TransactionManager only handles Contained Transactions that are trivially sovable. (If a remove transaction completely overlaps with another remove transaction, only the larger one will be kept)
+
+## Resource Management
+
+The Transaction Manager enforces two types of limits:
+
+1. **Transaction Count**: Optional maximum number of transactions
+1. **Execution Time**: Optional time limit for transaction processing
+
+These limits prevent excessive resource usage and allow for early termination of long-running operations.
+
+## Commit Process
+
+The commit process applies queued transactions to the codebase:
+
+1. Transactions are sorted according to priority rules
+1. Files are processed one by one
+1. For each file, transactions are executed in order
+1. Diffs are collected for each modified file
+1. The queue is cleared after successful commit
+
+The diff's are later used during resyc to efficiently update the codebase graph as changes occur. See [Incremental Computation](../6.%20incremental-computation/A.%20Overview.md) for more details.
## Next Step
diff --git a/architecture/external/dependency-manager.md b/architecture/external/dependency-manager.md
index 071a10526..ed8e42a3d 100644
--- a/architecture/external/dependency-manager.md
+++ b/architecture/external/dependency-manager.md
@@ -1,6 +1,99 @@
# Dependency Manager
-TODO
+> WARNING: Dependency manager is an experimental feature designed for Codegen Cloud! The current implementation WILL delete any existing `node_modules` folder!
+
+## Motivation
+
+A future goal of Codegen is to support resolving symbols directly from dependencies, instead of falling back to `ExternalModule`s. (In fact, some experimental Codegen features such as [Type Engine](./type-engine.md) already parse and use 3rd party dependencies from `node_modules`)
+
+This requires us to pull and install dependencies from a repository's `package.json`. However, simply installing dependencies from `package.json` is not enough, as many projects require internal dependencies that use custom NPM registries. Others require custom post-install scripts that may not run on our codemod environments.
+
+Dependency Manager is an experimental solution to this problem. It creates a shadow tree of `package.json` files that includes all core dependencies and settings from the repository's original `package.json` without any custom registries or potentially problematic settings.
+
+> NOTE: Currently, this is only implemented for TypeScript projects.
+
+## Implementation
+
+Given this example codebase structure:
+
+```
+repo/
+├── package.json
+├── node_modules/
+├── src/
+│ ├── frontend/
+│ │ └── package.json
+│ └── backend/
+│ └── package.json
+└── tests/
+ └── package.json
+```
+
+Dependency Manager first deletes any existing `node_modules` folder in the user's repository. After this step, Dependency Manager initializes itself to use the correct version of NPM, Yarn, or PNPM for the user's repository.
+
+Dependency Manager then creates a "shadow copy" of the repository's original `package.json` file. This shadow copy is used to later revert any changes made by Codegen before running codemods. With these steps, the codebase structure now looks like this:
+
+```
+repo/
+├── package.json
+├── package.json.gs_internal.bak
+├── src/
+│ ├── frontend/
+│ │ └── package.json
+│ │ └── package.json.gs_internal.bak
+│ └── backend/
+│ └── package.json
+│ └── package.json.gs_internal.bak
+└── tests/
+ └── package.json
+ └── package.json.gs_internal.bak
+```
+
+Next, Dependency Manager iterates through all the `package.json` files and creates a "clean" version of each file. This "clean" version only includes a subset of information from the original, including:
+
+- Name
+- Version
+- Package Manager Details
+- Workspaces
+
+Most importantly, this step iterates through `dependencies` and `devDependencies` of each `package.json` file and validates them against the npm registry. If a package is not found, it is added to a list of invalid dependencies and removed from the `package.json` file.
+
+After this step, the codebase structure now looks like this:
+
+```
+repo/
+├── package.json (modified)
+├── package.json.gs_internal.bak
+├── src/
+│ ├── frontend/
+│ │ └── package.json (modified)
+│ │ └── package.json.gs_internal.bak
+│ └── backend/
+│ └── package.json (modified)
+│ └── package.json.gs_internal.bak
+└── tests/
+ └── package.json (modified)
+ └── package.json.gs_internal.bak
+```
+
+After the shadow and cleaning steps, Dependency Manager proceeds to install the user's dependencies through NPM, Yarn, or PNPM, depending on the detected installer type. Finally, Dependency Manager restores the original `package.json` files and removes the shadow copies.
+
+The final codebase structure looks like this:
+
+```
+repo/
+├── package.json
+├── node_modules/
+├── src/
+│ ├── frontend/
+│ │ └── package.json
+│ └── backend/
+│ └── package.json
+└── tests/
+ └── package.json
+```
+
+If all goes well, Dependency Manager will have successfully installed the user's dependencies and prepared the codebase for codemods.
## Next Step
diff --git a/architecture/external/type-engine.md b/architecture/external/type-engine.md
index 54313a82b..42b96f643 100644
--- a/architecture/external/type-engine.md
+++ b/architecture/external/type-engine.md
@@ -1,6 +1,24 @@
# Type Engine
-TODO
+Type Engine is an experimental feature of Codegen that leverages the [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API) to provide deeper insight into a user's codebase (such as resolving return types).
+
+> NOTE: Currently, this is only implemented for TypeScript projects.
+
+There are currently two experimental implementations of TypeScript's Type Engine: an external process-based implementation and a V8-based implementation.
+
+## Implementation (External Process)
+
+During codebase parsing, the Type Engine spawns a type inference subprocess (defined in `src/codegen/sdk/typescript/external/typescript_analyzer/run_full.ts`) that concurrently parses the codebase with the TypeScript API to resolve return types. The final analyzer output is placed in `/tmp/typescript-analysis.json` and is read in by Codegen to resolve return types.
+
+## Implementation (V8)
+
+The V8-based implementation is much more flexible and powerful in comparison but is currently not as stable. It uses the [PyMiniRacer](https://github.com/sqreen/py_mini_racer) package to spawn a V8-based JavaScript engine that can parse the codebase with the TypeScript API to resolve return types.
+
+The entirety of `src/codegen/sdk/typescript/external/typescript_analyzer` is compiled down using [Rollup.js](https://rollupjs.org/) into a single `index.js` file. A couple of patches are applied to the engine source to remove `require` and `export` statements, which are not supported by MiniRacer.
+
+Then, the entire `index.js` file is loaded into the MiniRacer context. To work around file read limitations with V8, an in-memory shadow filesystem is created that mimics the user's repository's filesystem. These are defined in `fsi.ts` (`FileSystemInterface`) and `fs_proxy.ts` (`ProxyFileSystem`). The TypeScript Compiler then uses the custom `ProxyFileSystem.readFile` function instead of the traditional `fs.readFile`.
+
+Once the analyzer is initialized and the codebase is parsed, the entire TypeScript Compiler API is available in the MiniRacer context. The analyzer can then be used to resolve return types for any function in the codebase or to parse the codebase and generate a full type analysis.
## Next Step
diff --git a/codegen-examples/examples/github_checks/README.md b/codegen-examples/examples/github_checks/README.md
new file mode 100644
index 000000000..605532669
--- /dev/null
+++ b/codegen-examples/examples/github_checks/README.md
@@ -0,0 +1,110 @@
+# Github Checks
+
+This application is a GitHub integration that analyzes import cycles in codebases. It automatically runs when a pull request is labeled and checks for potentially problematic import patterns in the modified codebase.
+
+## Features
+
+- Analyzes import relationships in codebases
+- Detects circular import dependencies
+- Identifies problematic cycles with mixed static and dynamic imports
+- Automatically comments on pull requests with detailed analysis
+
+## How It Works
+
+1. The app creates a directed graph representing import relationships in the codebase
+
+ ```python
+ for imp in codebase.imports:
+ if imp.from_file and imp.to_file:
+ G.add_edge(
+ imp.to_file.filepath,
+ imp.from_file.filepath,
+ color="red" if getattr(imp, "is_dynamic", False) else "black",
+ label="dynamic" if getattr(imp, "is_dynamic", False) else "static",
+ is_dynamic=getattr(imp, "is_dynamic", False),
+ )
+ ```
+
+1. It identifies strongly connected components (cycles) in the import graph
+
+ ```python
+ cycles = [scc for scc in nx.strongly_connected_components(G) if len(scc) > 1]
+ ```
+
+1. It specifically flags cycles that contain both static and dynamic imports
+
+ ```python
+ dynamic_count = sum(1 for e in edges.values() if e["color"] == "red")
+ static_count = sum(1 for e in edges.values() if e["color"] == "black")
+
+ if dynamic_count > 0 and static_count > 0:
+ mixed_imports[(from_file, to_file)] = {
+ "dynamic": dynamic_count,
+ "static": static_count,
+ "edges": edges,
+ }
+ ```
+
+1. Results are posted as a comment on the pull request
+
+ ```python
+ message = ["### Import Cycle Analysis - GitHub Check\n"]
+
+ if problematic_loops:
+ message.append("\n### ⚠️ Potentially Problematic Import Cycles")
+ message.append("Cycles with mixed static and dynamic imports, which might recquire attention.")
+ for i, cycle in enumerate(problematic_loops, 1):
+ message.append(f"\n#### Problematic Cycle {i}")
+ for (from_file, to_file), imports in cycle["mixed_imports"].items():
+ message.append(f"\nFrom: `{from_file}`")
+ message.append(f"To: `{to_file}`")
+ message.append(f"- Static imports: {imports['static']}")
+ message.append(f"- Dynamic imports: {imports['dynamic']}")
+ else:
+ message.append("\nNo problematic import cycles found! 🎉")
+ ```
+
+## Setup
+
+1. Ensure you have the following dependencies:
+
+ - Python 3.13
+ - Modal
+ - Codegen
+ - NetworkX
+ - python-dotenv
+
+1. Set up your environment variables in a `.env` file
+
+ - `GITHUB_TOKEN`: Your GitHub token, configured with `repo` and `workflow` scopes.
+
+1. Deploy the app using Modal:
+
+ ```bash
+ modal deploy app.py
+ ```
+
+ - After deployment, configure your GitHub App's webhook URL in its developer settings to point to your Modal endpoint with the endpoint `/github/events`
+ - The app will analyze imports via the Modal deployment whenever a pull request receives a `Codegen` label
+
+## Technical Details
+
+The application uses Codegen to parse the codebase and a combination of NetworkX and Codegen to analyze the import relationships. The app is structured as a Modal App with a FastAPI server.
+The analysis runs when a pull request is labeled (`pull_request:labeled` event).
+
+## Output Format
+
+The analysis results are posted as a markdown-formatted comment on the pull request, including:
+
+- Summary statistics
+- Detailed cycle information
+- Warning indicators for problematic import patterns
+
+## Learn More
+
+- [Codegen Documentation](https://docs.codegen.com)
+- [Detecting Import Loops](https://docs.codegen.com/blog/fixing-import-loops)
+
+## Contributing
+
+Feel free to submit issues and enhancement requests!
diff --git a/codegen-examples/examples/github_checks/app.py b/codegen-examples/examples/github_checks/app.py
new file mode 100644
index 000000000..8166e5d31
--- /dev/null
+++ b/codegen-examples/examples/github_checks/app.py
@@ -0,0 +1,154 @@
+import logging
+
+import modal
+from codegen import CodegenApp, Codebase
+from codegen.extensions.github.types.events.pull_request import PullRequestLabeledEvent
+from codegen.extensions.tools.github.create_pr_comment import create_pr_comment
+from dotenv import load_dotenv
+import networkx as nx
+
+load_dotenv()
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+cg = CodegenApp(name="codegen-github-checks")
+
+
+def create_graph_from_codebase(repo_path):
+ """Create a directed graph representing import relationships in a codebase."""
+ codebase = Codebase.from_repo(repo_path)
+ G = nx.MultiDiGraph()
+
+ for imp in codebase.imports:
+ if imp.from_file and imp.to_file:
+ G.add_edge(
+ imp.to_file.filepath,
+ imp.from_file.filepath,
+ color="red" if getattr(imp, "is_dynamic", False) else "black",
+ label="dynamic" if getattr(imp, "is_dynamic", False) else "static",
+ is_dynamic=getattr(imp, "is_dynamic", False),
+ )
+ return G
+
+
+def convert_all_calls_to_kwargs(codebase):
+ for file in codebase.files:
+ for function_call in file.function_calls:
+ function_call.convert_args_to_kwargs()
+
+ print("All function calls have been converted to kwargs")
+
+
+def find_import_cycles(G):
+ """Identify strongly connected components (cycles) in the import graph."""
+ cycles = [scc for scc in nx.strongly_connected_components(G) if len(scc) > 1]
+ print(f"🔄 Found {len(cycles)} import cycles.")
+
+ for i, cycle in enumerate(cycles, 1):
+ print(f"\nCycle #{i}: Size {len(cycle)} files")
+ print(f"Total number of imports in cycle: {G.subgraph(cycle).number_of_edges()}")
+
+ print("\nFiles in this cycle:")
+ for file in cycle:
+ print(f" - {file}")
+
+ return cycles
+
+
+def find_problematic_import_loops(G, cycles):
+ """Identify cycles with both static and dynamic imports between files."""
+ problematic_cycles = []
+
+ for i, scc in enumerate(cycles):
+ if i == 2:
+ continue
+
+ mixed_imports = {}
+ for from_file in scc:
+ for to_file in scc:
+ if G.has_edge(from_file, to_file):
+ edges = G.get_edge_data(from_file, to_file)
+ dynamic_count = sum(1 for e in edges.values() if e["color"] == "red")
+ static_count = sum(1 for e in edges.values() if e["color"] == "black")
+
+ if dynamic_count > 0 and static_count > 0:
+ mixed_imports[(from_file, to_file)] = {
+ "dynamic": dynamic_count,
+ "static": static_count,
+ "edges": edges,
+ }
+
+ if mixed_imports:
+ problematic_cycles.append({"files": scc, "mixed_imports": mixed_imports, "index": i})
+
+ print(f"Found {len(problematic_cycles)} cycles with potentially problematic imports.")
+
+ for i, cycle in enumerate(problematic_cycles):
+ print(f"\n⚠️ Problematic Cycle #{i + 1} (Index {cycle['index']}): Size {len(cycle['files'])} files")
+ print("\nFiles in cycle:")
+ for file in cycle["files"]:
+ print(f" - {file}")
+ print("\nMixed imports:")
+ for (from_file, to_file), imports in cycle["mixed_imports"].items():
+ print(f"\n From: {from_file}")
+ print(f" To: {to_file}")
+ print(f" Static imports: {imports['static']}")
+ print(f" Dynamic imports: {imports['dynamic']}")
+
+ return problematic_cycles
+
+
+@cg.github.event("pull_request:labeled")
+def handle_pr(event: PullRequestLabeledEvent):
+ codebase = Codebase.from_repo(event.repository.get("full_name"), commit=event.pull_request.head.sha)
+
+ G = create_graph_from_codebase(event.repository.get("full_name"))
+ cycles = find_import_cycles(G)
+ problematic_loops = find_problematic_import_loops(G, cycles)
+
+ # Build comment message
+ message = ["### Import Cycle Analysis - GitHub Check\n"]
+
+ if problematic_loops:
+ message.append("\n### ⚠️ Potentially Problematic Import Cycles")
+ message.append("Cycles with mixed static and dynamic imports, which might recquire attention.")
+ for i, cycle in enumerate(problematic_loops, 1):
+ message.append(f"\n#### Problematic Cycle {i}")
+ for (from_file, to_file), imports in cycle["mixed_imports"].items():
+ message.append(f"\nFrom: `{from_file}`")
+ message.append(f"To: `{to_file}`")
+ message.append(f"- Static imports: {imports['static']}")
+ message.append(f"- Dynamic imports: {imports['dynamic']}")
+ else:
+ message.append("\nNo problematic import cycles found! 🎉")
+
+ create_pr_comment(
+ codebase,
+ event.pull_request.number,
+ "\n".join(message),
+ )
+
+ return {
+ "message": "PR event handled",
+ "num_files": len(codebase.files),
+ "num_functions": len(codebase.functions),
+ }
+
+
+base_image = (
+ modal.Image.debian_slim(python_version="3.13")
+ .apt_install("git")
+ .pip_install(
+ "codegen",
+ )
+)
+
+app = modal.App("codegen-import-cycles-github-check")
+
+
+@app.function(image=base_image, secrets=[modal.Secret.from_dotenv()])
+@modal.asgi_app()
+def fastapi_app():
+ print("Starting codegen fastapi app")
+ return cg.app
diff --git a/codegen-examples/examples/langchain_agent/run.py b/codegen-examples/examples/langchain_agent/run.py
index 0d4d4f837..5c6891889 100644
--- a/codegen-examples/examples/langchain_agent/run.py
+++ b/codegen-examples/examples/langchain_agent/run.py
@@ -20,7 +20,7 @@
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph.graph import CompiledGraph
-from langgraph.prebuilt import create_react_agent
+from codegen.extensions.langchain.graph import create_react_agent
from langchain_core.messages import SystemMessage
@@ -70,7 +70,7 @@ def create_codebase_agent(
memory = MemorySaver() if memory else None
- return create_react_agent(model=llm, tools=tools, prompt=system_message, checkpointer=memory, debug=debug)
+ return create_react_agent(model=llm, tools=tools, system_message=system_message, checkpointer=memory, debug=debug)
if __name__ == "__main__":
diff --git a/codegen-examples/examples/sqlalchemy_soft_delete/README.md b/codegen-examples/examples/sqlalchemy_soft_delete/README.md
index b8c9a22db..52087e2e0 100644
--- a/codegen-examples/examples/sqlalchemy_soft_delete/README.md
+++ b/codegen-examples/examples/sqlalchemy_soft_delete/README.md
@@ -130,6 +130,10 @@ To run in no-graph mode:
codebase = Codebase(str(repo_path), language="python", config=CodebaseConfig(disable_graph=True))
```
+
+To learn more about no-graph mode, see the [Advanced Settings](/introduction/advanced-settings) page.
+
+
## Running the Conversion
```bash
diff --git a/codegen-examples/examples/swebench_agent_run/README.md b/codegen-examples/examples/swebench_agent_run/README.md
index c6dc48676..277578f16 100644
--- a/codegen-examples/examples/swebench_agent_run/README.md
+++ b/codegen-examples/examples/swebench_agent_run/README.md
@@ -27,7 +27,8 @@
Options:
--use-existing-preds TEXT The run ID of the existing predictions to
use.
- --dataset [lite|full|verified] The dataset to use.
+ --dataset [lite|full|verified|lite_small|lite_medium|lite_large]
+ The dataset to use.
--length INTEGER The number of examples to process.
--instance-id TEXT The instance ID of the example to process.
--repo TEXT The repo to use.
diff --git a/codegen-examples/examples/swebench_agent_run/constants.py b/codegen-examples/examples/swebench_agent_run/constants.py
new file mode 100644
index 000000000..138669e96
--- /dev/null
+++ b/codegen-examples/examples/swebench_agent_run/constants.py
@@ -0,0 +1,12 @@
+from codegen.extensions.swebench.enums import SWEBenchDataset
+from codegen.extensions.swebench.enums import SWEBenchLiteSubset
+
+
+DATASET_DICT = {
+ "lite": SWEBenchDataset.LITE,
+ "full": SWEBenchDataset.FULL,
+ "verified": SWEBenchDataset.VERIFIED,
+ "lite_small": SWEBenchLiteSubset.LITE_SMALL,
+ "lite_medium": SWEBenchLiteSubset.LITE_MEDIUM,
+ "lite_large": SWEBenchLiteSubset.LITE_LARGE,
+}
diff --git a/codegen-examples/examples/swebench_agent_run/entry_point.py b/codegen-examples/examples/swebench_agent_run/entry_point.py
index 411b09d3b..a364aaa19 100644
--- a/codegen-examples/examples/swebench_agent_run/entry_point.py
+++ b/codegen-examples/examples/swebench_agent_run/entry_point.py
@@ -13,7 +13,7 @@
app = modal.App(name="swebench-agent-run", image=image, secrets=[modal.Secret.from_dotenv()])
-@app.function(timeout=10 * 60)
-async def run_agent_modal(entry: SweBenchExample):
+@app.function(timeout=43200)
+async def run_agent_modal(entry: SweBenchExample, run_id: str, model: str):
"""Modal function to process a single example from the SWE-bench dataset."""
- return run_agent_on_entry(entry)
+ return run_agent_on_entry(entry, run_id=run_id, model=model)
diff --git a/codegen-examples/examples/swebench_agent_run/local_run.ipynb b/codegen-examples/examples/swebench_agent_run/local_run.ipynb
index 1f27f470c..0b212fa40 100644
--- a/codegen-examples/examples/swebench_agent_run/local_run.ipynb
+++ b/codegen-examples/examples/swebench_agent_run/local_run.ipynb
@@ -7,7 +7,14 @@
"outputs": [],
"source": [
"%load_ext autoreload\n",
- "%autoreload 2"
+ "%autoreload 2\n",
+ "\n",
+ "from dotenv import load_dotenv # type: ignore\n",
+ "\n",
+ "load_dotenv()\n",
+ "\n",
+ "from codegen.extensions.swebench.utils import SWEBenchDataset, get_swe_bench_examples # noqa: E402\n",
+ "from run_eval import run_eval # noqa: E402"
]
},
{
@@ -16,9 +23,7 @@
"metadata": {},
"outputs": [],
"source": [
- "from codegen.sdk.core.codebase import Codebase\n",
- "from codegen.extensions.swebench.utils import SWEBenchDataset, get_swe_bench_examples\n",
- "from run_eval import run_eval"
+ "examples = get_swe_bench_examples(dataset=SWEBenchDataset.LITE, split=\"test\", offset=0, length=10)"
]
},
{
@@ -27,43 +32,8 @@
"metadata": {},
"outputs": [],
"source": [
- "examples = get_swe_bench_examples(dataset=SWEBenchDataset.LITE, split=\"test\", offset=0, length=1)"
+ "await run_eval(use_existing_preds=None, dataset=\"lite\", length=20, repo=\"django/django\", num_workers=10, model=\"claude-3-7-sonnet-latest\")"
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "codebase = Codebase.from_repo(examples[0].repo, commit=examples[0].base_commit, tmp_dir=f\"/tmp/{examples[0].instance_id}\")\n",
- "# this will allow us to reuse the codebase for multiple examples\n",
- "codebases = {examples[0].instance_id: codebase}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "await run_eval(use_existing_preds=None, dataset=\"lite\", length=None, instance_id=examples[0].instance_id, local=True, codebases=codebases)\n",
- "codebases[examples[0].instance_id].reset()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {
@@ -82,7 +52,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.13.1"
+ "version": "3.13.0"
}
},
"nbformat": 4,
diff --git a/codegen-examples/examples/swebench_agent_run/run_eval.py b/codegen-examples/examples/swebench_agent_run/run_eval.py
index b39cede6f..b1567f8f6 100644
--- a/codegen-examples/examples/swebench_agent_run/run_eval.py
+++ b/codegen-examples/examples/swebench_agent_run/run_eval.py
@@ -5,9 +5,11 @@
import uuid
import modal
import click
-from datetime import datetime
+import time
+from codegen.extensions.swebench.enums import SWEBenchDataset, SWEBenchLiteSubset
+from constants import DATASET_DICT
from codegen.extensions.swebench.harness import run_agent_on_entry
-from codegen.extensions.swebench.utils import SWEBenchDataset, SweBenchExample, get_swe_bench_examples
+from codegen.extensions.swebench.utils import SweBenchExample, get_swe_bench_examples
from codegen.extensions.swebench.report import generate_report
from codegen.sdk.core.codebase import Codebase
@@ -17,102 +19,234 @@
run_agent_modal = modal.Function.from_name(app_name="swebench-agent-run", name="run_agent_modal")
-async def process_batch_modal(examples: list[SweBenchExample], batch_size=10):
- """Process a batch of examples concurrently.
+async def process_batch_modal(examples: list[SweBenchExample], run_id: str, model: str, num_workers=5, min_workers=1, max_retries=3):
+ """Process a batch of examples concurrently using a queue system with incremental worker scaling.
Args:
examples: List of SweBenchExample objects to process
- batch_size: Number of examples to process concurrently.
- Default is 50 which provides good parallelization
- while staying well within Modal's limits.
+ num_workers: Initial number of examples to process concurrently
+ min_workers: Minimum number of concurrent workers to maintain
+ max_retries: Maximum number of retries for failed requests
"""
- results = []
+ results = {}
+ queue = asyncio.Queue()
+
+ # Shared state for worker management
+ state = {
+ "active_workers": num_workers,
+ "success_streak": 0,
+ "last_scaling_time": time.time(),
+ "scaling_cooldown": 0, # seconds between scaling operations
+ "worker_tasks": [],
+ "running": True,
+ }
- # Process examples in batches
- for i in range(0, len(examples), batch_size):
- batch = examples[i : i + batch_size]
+ # Use a lock to protect shared state during adjustments
+ state_lock = asyncio.Lock()
+
+ # Initialize the queue with (example, attempt) tuples
+ for example in examples:
+ await queue.put((example, 0)) # 0 represents first attempt
+
+ async def scale_down_worker(task_to_cancel=None):
+ """Remove a single worker when rate limiting is detected"""
+ async with state_lock:
+ # Only scale if cooldown period has passed and we're above min_workers
+ current_time = time.time()
+ if current_time - state["last_scaling_time"] < state["scaling_cooldown"] or state["active_workers"] <= min_workers:
+ return False
+
+ # Reset success streak when scaling down
+ state["success_streak"] = 0
+ state["last_scaling_time"] = current_time
+
+ # If a specific task was provided, cancel it
+ if task_to_cancel and task_to_cancel in state["worker_tasks"]:
+ print(f"Rate limiting detected! Removing 1 worker, going from {state['active_workers']} to {state['active_workers'] - 1}")
+ state["worker_tasks"].remove(task_to_cancel)
+ task_to_cancel.cancel()
+ state["active_workers"] -= 1
+ return True
+
+ # Otherwise, cancel the most recently added worker
+ elif state["worker_tasks"]:
+ print(f"Rate limiting detected! Removing 1 worker, going from {state['active_workers']} to {state['active_workers'] - 1}")
+ task = state["worker_tasks"].pop()
+ task.cancel()
+ state["active_workers"] -= 1
+ return True
+
+ return False
+
+ async def scale_up_worker():
+ """Add a single worker when operations have been consistently successful"""
+ async with state_lock:
+ # Only scale if cooldown period has passed and we're below num_workers
+ current_time = time.time()
+ if current_time - state["last_scaling_time"] < state["scaling_cooldown"] or state["active_workers"] >= num_workers:
+ return False
+
+ # Add a worker after a streak of successful operations
+ if state["success_streak"] >= 5:
+ print(f"Operations succeeding! Adding 1 worker, going from {state['active_workers']} to {state['active_workers'] + 1}")
+
+ # Create new worker
+ if state["running"]:
+ new_task = asyncio.create_task(worker())
+ state["worker_tasks"].append(new_task)
+ state["active_workers"] += 1
+ state["success_streak"] = 0
+ state["last_scaling_time"] = current_time
+ return True
+
+ return False
+
+ async def is_rate_limit_error(error):
+ """Determine if an error is due to rate limiting"""
+ # Check for common rate limit error patterns
+ if isinstance(error, modal.exception.Error):
+ error_msg = str(error).lower()
+ rate_limit_indicators = ["rate limit", "too many requests", "429", "throttle", "quota exceeded", "capacity", "limit exceeded"]
+ return any(indicator in error_msg for indicator in rate_limit_indicators)
+ return False
+
+ async def process_example(example, attempt, current_task):
+ try:
+ result = await run_agent_modal.remote.aio(example, run_id=run_id, model=model)
- # Create tasks for this batch
- batch_tasks = [run_agent_modal.remote.aio(example) for example in batch]
+ if result is None:
+ print(f"Warning: Null result for {example.instance_id}")
+ return {"status": "error", "instance_id": example.instance_id, "error_info": {"error_type": "NullResult", "error_message": "Process returned None"}}
- # Wait for all tasks in this batch to complete
- print(f"Processing batch {i // batch_size + 1}/{len(examples) // batch_size + 1} (examples {i + 1}-{min(i + batch_size, len(examples))})")
+ # Increment success streak and potentially scale up
+ async with state_lock:
+ state["success_streak"] += 1
- try:
- batch_results = await asyncio.gather(*batch_tasks, return_exceptions=True)
-
- # Store results
- for example, result in zip(batch, batch_results):
- error_info = None
-
- if isinstance(result, Exception):
- error_type = type(result).__name__
- error_info = {
- "error_type": error_type,
- "error_message": str(result),
- "traceback": traceback.format_exception(type(result), result, result.__traceback__),
- }
-
- if isinstance(result, modal.exception.Error):
- error_info["modal_error_code"] = getattr(result, "code", None)
- error_info["modal_error_details"] = getattr(result, "details", None)
-
- print(f"Error processing {example.instance_id}:")
- print(f"Type: {error_type}")
- print(f"Message: {str(result)}")
- print("Traceback:")
- print("".join(error_info["traceback"]))
-
- results.append({"instance_id": example.instance_id, "status": "error", "error_info": error_info})
- else:
- if result is None:
- print(f"Warning: Null result for {example.instance_id}")
- results.append({"instance_id": example.instance_id, "status": "error", "error_info": {"error_type": "NullResult", "error_message": "Process returned None"}})
- else:
- results.append(result)
+ if state["success_streak"] % 5 == 0: # Check after every 5 successes
+ await scale_up_worker()
+
+ return result
except Exception as e:
- print("Batch processing error:")
- print(f"Type: {type(e).__name__}")
+ error_type = type(e).__name__
+ error_info = {
+ "error_type": error_type,
+ "error_message": str(e),
+ "traceback": traceback.format_exception(type(e), e, e.__traceback__),
+ }
+
+ if isinstance(e, modal.exception.Error):
+ error_info["modal_error_code"] = getattr(e, "code", None)
+ error_info["modal_error_details"] = getattr(e, "details", None)
+
+ print(f"Error processing {example.instance_id} (attempt {attempt + 1}):")
+ print(f"Type: {error_type}")
print(f"Message: {str(e)}")
- traceback.print_exc()
-
- # Mark all examples in the batch as failed
- for example in batch:
- results.append(
- {
- "instance_id": example.instance_id,
- "status": "error",
- "error_info": {"error_type": type(e).__name__, "error_message": str(e), "traceback": traceback.format_exc(), "batch_failure": True},
- }
- )
- return results
+ # Check if this is a rate limit error
+ if await is_rate_limit_error(e):
+ print(f"Rate limit detected on task for {example.instance_id}")
+
+ # Scale down by removing this specific worker
+ scaled_down = await scale_down_worker(current_task)
+
+ # If we're removing this worker, we need to requeue the task for another worker
+ if scaled_down:
+ # Requeue this example with the same attempt count (not incrementing)
+ await queue.put((example, attempt))
+ return None
+
+ # Otherwise add a small delay before retrying
+ await asyncio.sleep(2 * (attempt + 1)) # Exponential backoff
+
+ if attempt < max_retries:
+ await queue.put((example, attempt + 1))
+ return None
+ return {"status": "error", "instance_id": example.instance_id, "error_info": error_info}
-def process_batch_local(examples: list[SweBenchExample], batch_size=10, codebases: dict[str, Codebase] = {}):
+ async def worker():
+ # Store this task reference to allow targeted cancellation
+ current_task = asyncio.current_task()
+
+ while state["running"]:
+ try:
+ # Use a timeout to allow worker to check if it should exit
+ try:
+ example, attempt = await asyncio.wait_for(queue.get(), timeout=1.0)
+ except asyncio.TimeoutError:
+ continue
+
+ if example.instance_id in results:
+ queue.task_done()
+ continue
+ print(f"Processing example {example.instance_id}")
+ process_result = await process_example(example, attempt, current_task)
+
+ # If we're still processing this task (not requeued due to rate limiting)
+ if process_result is not None:
+ results[example.instance_id] = {"instance_id": example.instance_id, **process_result}
+ print(f"Processed example {example.instance_id}")
+ queue.task_done()
+
+ # If None is returned, the task was requeued due to rate limiting
+ # and this worker is being shut down, so exit the loop
+ else:
+ print(f"Task for {example.instance_id} has been requeued")
+ queue.task_done()
+ if current_task not in state["worker_tasks"]:
+ break
+
+ except asyncio.CancelledError:
+ # Handle graceful cancellation
+ print("Worker task cancelled")
+ break
+ except Exception as e:
+ print(f"Worker error: {str(e)}")
+ traceback.print_exc()
+ queue.task_done()
+
+ # Start initial workers
+ state["worker_tasks"] = [asyncio.create_task(worker()) for _ in range(num_workers)]
+
+ # Wait for queue to be fully processed
+ await queue.join()
+
+ # Mark as not running and cancel remaining workers
+ state["running"] = False
+ for w in state["worker_tasks"]:
+ w.cancel()
+
+ # Wait for all workers to be cancelled
+ await asyncio.gather(*state["worker_tasks"], return_exceptions=True)
+
+ # Return results in the same order as input examples
+ return [results.get(example.instance_id, {"instance_id": example.instance_id, "status": "missing"}) for example in examples]
+
+
+def process_batch_local(examples: list[SweBenchExample], model: str, num_workers=5, codebases: dict[str, Codebase] = {}, run_id: str | None = None):
"""Process a batch of examples synchronously.
Args:
examples: List of SweBenchExample objects to process
- batch_size: Number of examples to process in each batch.
+ num_workers: Number of examples to process in each batch.
Default is 10 to avoid overwhelming the system.
"""
results = []
# Process examples in batches
- for i in range(0, len(examples), batch_size):
- batch = examples[i : i + batch_size]
- print(f"Processing batch {i // batch_size + 1}/{len(examples) // batch_size + 1} (examples {i + 1}-{min(i + batch_size, len(examples))})")
+ for i in range(0, len(examples), num_workers):
+ batch = examples[i : i + num_workers]
+ print(f"Processing batch {i // num_workers + 1}/{len(examples) // num_workers + 1} (examples {i + 1}-{min(i + num_workers, len(examples))})")
# Process each example in the batch
for example in batch:
try:
# Run the agent locally instead of using modal
if codebases and example.instance_id in codebases:
- result = run_agent_on_entry(example, codebase=codebases[example.instance_id])
+ result = run_agent_on_entry(example, model=model, codebase=codebases[example.instance_id], run_id=run_id)
else:
- result = run_agent_on_entry(example)
+ result = run_agent_on_entry(example, model=model, run_id=run_id)
results.append(result)
except Exception as e:
@@ -134,35 +268,40 @@ def process_batch_local(examples: list[SweBenchExample], batch_size=10, codebase
return results
-async def run_eval(use_existing_preds: str | None, dataset: str, length: int, instance_id: str | None = None, local: bool = False, codebases: dict[str, Codebase] = {}, repo: str | None = None):
+async def run_eval(
+ dataset: str,
+ use_existing_preds: str | None = None,
+ length: int | None = None,
+ instance_id: str | None = None,
+ local: bool = False,
+ codebases: dict[str, Codebase] = {},
+ repo: str | None = None,
+ num_workers: int = 2,
+ model: str = "claude-3-7-sonnet-latest",
+):
run_id = use_existing_preds or str(uuid.uuid4())
print(f"Run ID: {run_id}")
predictions_dir = PREDS_DNAME / f"results_{run_id}"
- dataset_dict = {
- "lite": SWEBenchDataset.LITE,
- "full": SWEBenchDataset.FULL,
- "verified": SWEBenchDataset.VERIFIED,
- }
- dataset_enum = dataset_dict[dataset]
- print(repo)
+
+ dataset_enum = DATASET_DICT[dataset]
examples = get_swe_bench_examples(dataset=dataset_enum, length=length, instance_id=instance_id, repo=repo)
- print(f"Examples:\n{'\n'.join([f'{e.instance_id} - {e.repo} - {e.base_commit}' for e in examples])}")
try:
if use_existing_preds is None:
+ print(f"Repo: {repo}")
+ print(f"Examples:\n{'\n'.join([f'{e.instance_id} - {e.repo} - {e.base_commit}' for e in examples])}")
print(f"Processing {len(examples)} examples...")
-
# Create output directory if it doesn't exist
predictions_dir.mkdir(exist_ok=True, parents=True)
# Create a timestamp for this run
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+ timestamp = time.strftime("%Y-%m-%d %H:%M %Z", time.localtime(time.time()))
# Process all examples in parallel batches
if local:
- results = process_batch_local(examples, codebases=codebases)
+ results = process_batch_local(examples, model=model, codebases=codebases, run_id=run_id)
else:
- results = await process_batch_modal(examples)
+ results = await process_batch_modal(examples, model=model, run_id=run_id, num_workers=num_workers)
# Save individual results
for result in results:
@@ -203,6 +342,8 @@ async def run_eval(use_existing_preds: str | None, dataset: str, length: int, in
for error_type, count in summary["error_types"].items():
print(f" {error_type}: {count}")
+ if isinstance(dataset_enum, SWEBenchLiteSubset):
+ dataset_enum = SWEBenchDataset.LITE
# Generate Report on Modal
generate_report(predictions_dir, LOG_DIR, dataset_enum, run_id)
except Exception:
@@ -212,15 +353,20 @@ async def run_eval(use_existing_preds: str | None, dataset: str, length: int, in
@click.command()
+@click.option("--dataset", help="The dataset to use.", type=click.Choice(["lite", "full", "verified", "lite_small", "lite_medium", "lite_large"]), default="lite")
@click.option("--use-existing-preds", help="The run ID of the existing predictions to use.", type=str, default=None)
-@click.option("--dataset", help="The dataset to use.", type=click.Choice(["lite", "full", "verified"]), default="lite")
-@click.option("--length", help="The number of examples to process.", type=int, default=10)
+@click.option("--length", help="The number of examples to process.", type=int, default=None)
@click.option("--instance-id", help="The instance ID of the example to process.", type=str, default=None)
@click.option("--local", help="Run the evaluation locally.", is_flag=True, default=False)
@click.option("--repo", help="The repo to use.", type=str, default=None)
-def run_eval_command(use_existing_preds, dataset, length, instance_id, local, repo):
+@click.option(
+ "--num-workers", help="The number of workers to use. This is the number of examples that will be processed concurrently. A large number may lead to rate limiting issues.", type=int, default=5
+)
+@click.option("--model", help="The model to use.", type=str, default="claude-3-7-sonnet-latest")
+def run_eval_command(dataset, use_existing_preds, length, instance_id, local, repo, num_workers, model):
print(f"Repo: {repo}")
- asyncio.run(run_eval(use_existing_preds=use_existing_preds, dataset=dataset, length=length, instance_id=instance_id, codebases=None, local=local, repo=repo))
+ print(f"Model: {model}")
+ asyncio.run(run_eval(dataset=dataset, use_existing_preds=use_existing_preds, length=length, instance_id=instance_id, local=local, repo=repo, num_workers=num_workers, model=model))
if __name__ == "__main__":
diff --git a/codegen-examples/uv.lock b/codegen-examples/uv.lock
index d34fae7ac..268c77f50 100644
--- a/codegen-examples/uv.lock
+++ b/codegen-examples/uv.lock
@@ -14,11 +14,11 @@ members = [
[[package]]
name = "aiohappyeyeballs"
-version = "2.4.6"
+version = "2.5.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/08/07/508f9ebba367fc3370162e53a3cfd12f5652ad79f0e0bfdf9f9847c6f159/aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0", size = 21726 }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/0c/458958007041f4b4de2d307e6b75d9e7554dad0baf26fe7a48b741aac126/aiohappyeyeballs-2.5.0.tar.gz", hash = "sha256:18fde6204a76deeabc97c48bdd01d5801cfda5d6b9c8bbeb1aaaee9d648ca191", size = 22494 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/44/4c/03fb05f56551828ec67ceb3665e5dc51638042d204983a03b0a1541475b6/aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1", size = 14543 },
+ { url = "https://files.pythonhosted.org/packages/1b/9a/e4886864ce06e1579bd428208127fbdc0d62049c751e4e9e3b509c0059dc/aiohappyeyeballs-2.5.0-py3-none-any.whl", hash = "sha256:0850b580748c7071db98bffff6d4c94028d0d3035acc20fd721a0ce7e8cac35d", size = 15128 },
]
[[package]]
@@ -82,15 +82,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 },
]
-[[package]]
-name = "alabaster"
-version = "1.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 },
-]
-
[[package]]
name = "annotated-types"
version = "0.7.0"
@@ -143,11 +134,11 @@ wheels = [
[[package]]
name = "argcomplete"
-version = "3.5.3"
+version = "3.6.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/0c/be/6c23d80cb966fb8f83fb1ebfb988351ae6b0554d0c3a613ee4531c026597/argcomplete-3.5.3.tar.gz", hash = "sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392", size = 72999 }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/be/29abccb5d9f61a92886a2fba2ac22bf74326b5c4f55d36d0a56094630589/argcomplete-3.6.0.tar.gz", hash = "sha256:2e4e42ec0ba2fff54b0d244d0b1623e86057673e57bafe72dda59c64bd5dee8b", size = 73135 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/c4/08/2a4db06ec3d203124c967fc89295e85a202e5cbbcdc08fd6a64b65217d1e/argcomplete-3.5.3-py3-none-any.whl", hash = "sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61", size = 43569 },
+ { url = "https://files.pythonhosted.org/packages/08/94/e786d91ccc3a1fc664c20332825b73da20928eb067cdc984b821948a1acc/argcomplete-3.6.0-py3-none-any.whl", hash = "sha256:4e3e4e10beb20e06444dbac0ac8dda650cb6349caeefe980208d3c548708bedd", size = 43769 },
]
[[package]]
@@ -407,7 +398,7 @@ wheels = [
[[package]]
name = "codegen"
-version = "0.43.2"
+version = "0.48.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "astor" },
@@ -431,6 +422,7 @@ dependencies = [
{ name = "langchain-anthropic" },
{ name = "langchain-core" },
{ name = "langchain-openai" },
+ { name = "langchain-xai" },
{ name = "langgraph" },
{ name = "langgraph-prebuilt" },
{ name = "langsmith" },
@@ -484,14 +476,14 @@ dependencies = [
{ name = "xmltodict" },
]
wheels = [
- { url = "https://files.pythonhosted.org/packages/eb/e1/ff1a5bc1c5e4e030e176eb37c3e480395a38e0ce613cc7c9af0ccb378f15/codegen-0.43.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:936004461a5bf014ae887e200a235ad7731d54057a7ba148c3224b5a6f1a8b96", size = 1146690 },
- { url = "https://files.pythonhosted.org/packages/4c/4e/d4f7043fadd416dc5b0d9ec9a11aa86d0d11d4d9f130e9c862b756cf481a/codegen-0.43.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:36533914fbb78e16708c280320e2fa65bfff404dc3b7fb276b4f02a899f1b793", size = 1137829 },
- { url = "https://files.pythonhosted.org/packages/3a/04/0436ff5617313570523663bbad46d11f1827b7cfcc70c1a896ebb60a7256/codegen-0.43.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_34_aarch64.whl", hash = "sha256:ccc83c2542b2843a75fd12327621639afdc9b009338231bc83bea14d44656c7f", size = 2142117 },
- { url = "https://files.pythonhosted.org/packages/51/ed/24a7e6a3c44264849256e784d0a3ffe30e83407ee3b3d24dbaae20d43c97/codegen-0.43.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_34_x86_64.whl", hash = "sha256:1010714abf56c9e252647c1a961a438e65fcb5f65169493d4c4fda0da36bd0cd", size = 2191390 },
- { url = "https://files.pythonhosted.org/packages/15/cd/63808926dbfb46b48786242c7680fdfd69357a848ca08fbb2c88b6d93b47/codegen-0.43.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:388bc76c57c93ccede4af4cec535083135079990f960719309ce331b8bb154b3", size = 1142110 },
- { url = "https://files.pythonhosted.org/packages/3b/8a/72fff90bdc517143fc0a17b31cd09360705a7549cdf299f4230f67b9d88c/codegen-0.43.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:24ae5b7f540e6e9ff55ade1171e3d1e718312bcc2589650436407059f334ffe0", size = 1133994 },
- { url = "https://files.pythonhosted.org/packages/9c/6e/7b9bcd9385ec35db07c08e234bacaac445cab9fdf0801535f1343d55f9a2/codegen-0.43.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_34_aarch64.whl", hash = "sha256:aaccab5b2063bf74c6c2125fb5a4ff65fd6792c24876c60f3f79ef16c82263b5", size = 2134861 },
- { url = "https://files.pythonhosted.org/packages/e9/36/e991085e3e7a1c369a2d1deb75fc7e9dba855dcbccdd437ef404cd40fd8a/codegen-0.43.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_34_x86_64.whl", hash = "sha256:1f2aa88e0e2ecae0883798656e38ce300cbeabc20dced33a1fbfca8271ac068f", size = 2181238 },
+ { url = "https://files.pythonhosted.org/packages/b8/a1/2e79373ece8044ff60975dd0f64c7782059e75767b5551541bfe03e8235c/codegen-0.48.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:92379780a883a87a18d2016eac6fba94fd6ea1e6ae8d5a4f2bf2bea619798421", size = 1158326 },
+ { url = "https://files.pythonhosted.org/packages/bc/15/79f6870fa73f4d31726b6a2ad04261c6f5a4ff64fa5acc59425222cc621c/codegen-0.48.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0de392531421fc8bd7ea49efe9d7f2e6b621d26dcb108be409511edcb5ad0a", size = 1149461 },
+ { url = "https://files.pythonhosted.org/packages/b8/5c/f8e35680b1b4d2f6bed47f87ed1ecd7221f292c480e6136550fb1ea286b2/codegen-0.48.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_34_aarch64.whl", hash = "sha256:433de2e2619df3ae2674c5e6b0e67d9e167353e7cc0509eb52e214af93a77349", size = 2153759 },
+ { url = "https://files.pythonhosted.org/packages/c0/94/3aaad37d7686850cf9e63d6cb4410144ac54a0d1d33c1f9f0cb51832c99f/codegen-0.48.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_34_x86_64.whl", hash = "sha256:a69764e76a0bee45851416da955a9f69919323490e3328c45a59360b59381d7f", size = 2203035 },
+ { url = "https://files.pythonhosted.org/packages/78/a3/eb1f4c0f07d1732b887ee75c4077f966546d976cb4bed6446625e5502d94/codegen-0.48.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:faf7768cab6e2ebb990cce9ef37272b98fe12a8fcad5435c080656911d6bb5f9", size = 1153747 },
+ { url = "https://files.pythonhosted.org/packages/e9/0a/63a808ebe700c01f63618efb68749321f0d5d81394461f1e697666081a1c/codegen-0.48.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3a32bf053e699ca380752d7440cac01e6f50f2558451b503dfac3f2f3db42ac8", size = 1145635 },
+ { url = "https://files.pythonhosted.org/packages/f4/98/9f835f7cd40564eef0b65b12a6b063d2ce305ee5e1416a28466b5a75b062/codegen-0.48.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_34_aarch64.whl", hash = "sha256:c8d0d5eb92573c81c0fa8309c11fe1c840da7aaf730200c42f31dd59dafcb7ee", size = 2146504 },
+ { url = "https://files.pythonhosted.org/packages/a5/5a/7b48ed2441d401b844793bd1b8c3c2f86066944166d24a1cb3208885a145/codegen-0.48.5-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_34_x86_64.whl", hash = "sha256:2d4dce804a3de5b92e32dd60c8623184381a8f2f856cc625ddffca2f152792cb", size = 2192882 },
]
[[package]]
@@ -663,19 +655,19 @@ wheels = [
[[package]]
name = "debugpy"
-version = "1.8.12"
+version = "1.8.13"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/68/25/c74e337134edf55c4dfc9af579eccb45af2393c40960e2795a94351e8140/debugpy-1.8.12.tar.gz", hash = "sha256:646530b04f45c830ceae8e491ca1c9320a2d2f0efea3141487c82130aba70dce", size = 1641122 }
+sdist = { url = "https://files.pythonhosted.org/packages/51/d4/f35f539e11c9344652f362c22413ec5078f677ac71229dc9b4f6f85ccaa3/debugpy-1.8.13.tar.gz", hash = "sha256:837e7bef95bdefba426ae38b9a94821ebdc5bea55627879cd48165c90b9e50ce", size = 1641193 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ba/e6/0f876ecfe5831ebe4762b19214364753c8bc2b357d28c5d739a1e88325c7/debugpy-1.8.12-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:7e94b643b19e8feb5215fa508aee531387494bf668b2eca27fa769ea11d9f498", size = 2500846 },
- { url = "https://files.pythonhosted.org/packages/19/64/33f41653a701f3cd2cbff8b41ebaad59885b3428b5afd0d93d16012ecf17/debugpy-1.8.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:086b32e233e89a2740c1615c2f775c34ae951508b28b308681dbbb87bba97d06", size = 4222181 },
- { url = "https://files.pythonhosted.org/packages/32/a6/02646cfe50bfacc9b71321c47dc19a46e35f4e0aceea227b6d205e900e34/debugpy-1.8.12-cp312-cp312-win32.whl", hash = "sha256:2ae5df899732a6051b49ea2632a9ea67f929604fd2b036613a9f12bc3163b92d", size = 5227017 },
- { url = "https://files.pythonhosted.org/packages/da/a6/10056431b5c47103474312cf4a2ec1001f73e0b63b1216706d5fef2531eb/debugpy-1.8.12-cp312-cp312-win_amd64.whl", hash = "sha256:39dfbb6fa09f12fae32639e3286112fc35ae976114f1f3d37375f3130a820969", size = 5267555 },
- { url = "https://files.pythonhosted.org/packages/cf/4d/7c3896619a8791effd5d8c31f0834471fc8f8fb3047ec4f5fc69dd1393dd/debugpy-1.8.12-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:696d8ae4dff4cbd06bf6b10d671e088b66669f110c7c4e18a44c43cf75ce966f", size = 2485246 },
- { url = "https://files.pythonhosted.org/packages/99/46/bc6dcfd7eb8cc969a5716d858e32485eb40c72c6a8dc88d1e3a4d5e95813/debugpy-1.8.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:898fba72b81a654e74412a67c7e0a81e89723cfe2a3ea6fcd3feaa3395138ca9", size = 4218616 },
- { url = "https://files.pythonhosted.org/packages/03/dd/d7fcdf0381a9b8094da1f6a1c9f19fed493a4f8576a2682349b3a8b20ec7/debugpy-1.8.12-cp313-cp313-win32.whl", hash = "sha256:22a11c493c70413a01ed03f01c3c3a2fc4478fc6ee186e340487b2edcd6f4180", size = 5226540 },
- { url = "https://files.pythonhosted.org/packages/25/bd/ecb98f5b5fc7ea0bfbb3c355bc1dd57c198a28780beadd1e19915bf7b4d9/debugpy-1.8.12-cp313-cp313-win_amd64.whl", hash = "sha256:fdb3c6d342825ea10b90e43d7f20f01535a72b3a1997850c0c3cefa5c27a4a2c", size = 5267134 },
- { url = "https://files.pythonhosted.org/packages/38/c4/5120ad36405c3008f451f94b8f92ef1805b1e516f6ff870f331ccb3c4cc0/debugpy-1.8.12-py2.py3-none-any.whl", hash = "sha256:274b6a2040349b5c9864e475284bce5bb062e63dce368a394b8cc865ae3b00c6", size = 5229490 },
+ { url = "https://files.pythonhosted.org/packages/79/ad/dff929b6b5403feaab0af0e5bb460fd723f9c62538b718a9af819b8fff20/debugpy-1.8.13-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1", size = 2501004 },
+ { url = "https://files.pythonhosted.org/packages/d6/4f/b7d42e6679f0bb525888c278b0c0d2b6dff26ed42795230bb46eaae4f9b3/debugpy-1.8.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522", size = 4222346 },
+ { url = "https://files.pythonhosted.org/packages/ec/18/d9b3e88e85d41f68f77235112adc31012a784e45a3fcdbb039777d570a0f/debugpy-1.8.13-cp312-cp312-win32.whl", hash = "sha256:3872ce5453b17837ef47fb9f3edc25085ff998ce63543f45ba7af41e7f7d370f", size = 5226639 },
+ { url = "https://files.pythonhosted.org/packages/c9/f7/0df18a4f530ed3cc06f0060f548efe9e3316102101e311739d906f5650be/debugpy-1.8.13-cp312-cp312-win_amd64.whl", hash = "sha256:63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea", size = 5268735 },
+ { url = "https://files.pythonhosted.org/packages/b1/db/ae7cd645c1826aae557cebccbc448f0cc9a818d364efb88f8d80e7a03f41/debugpy-1.8.13-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:31abc9618be4edad0b3e3a85277bc9ab51a2d9f708ead0d99ffb5bb750e18503", size = 2485416 },
+ { url = "https://files.pythonhosted.org/packages/ec/ed/db4b10ff3b5bb30fe41d9e86444a08bb6448e4d8265e7768450b8408dd36/debugpy-1.8.13-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0bd87557f97bced5513a74088af0b84982b6ccb2e254b9312e29e8a5c4270eb", size = 4218784 },
+ { url = "https://files.pythonhosted.org/packages/82/82/ed81852a8d94086f51664d032d83c7f87cd2b087c6ea70dabec7c1ba813d/debugpy-1.8.13-cp313-cp313-win32.whl", hash = "sha256:5268ae7fdca75f526d04465931cb0bd24577477ff50e8bb03dab90983f4ebd02", size = 5226270 },
+ { url = "https://files.pythonhosted.org/packages/15/63/aa92fb341a78ec40f1c414ec7a7885c2ee17032eee00d12cee0cdc502af4/debugpy-1.8.13-cp313-cp313-win_amd64.whl", hash = "sha256:79ce4ed40966c4c1631d0131606b055a5a2f8e430e3f7bf8fd3744b09943e8e8", size = 5268621 },
+ { url = "https://files.pythonhosted.org/packages/37/4f/0b65410a08b6452bfd3f7ed6f3610f1a31fb127f46836e82d31797065dcb/debugpy-1.8.13-py2.py3-none-any.whl", hash = "sha256:d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f", size = 5229306 },
]
[[package]]
@@ -798,15 +790,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637", size = 36533 },
]
-[[package]]
-name = "docutils"
-version = "0.21.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 },
-]
-
[[package]]
name = "dotty-dict"
version = "1.3.1"
@@ -1166,7 +1149,7 @@ wheels = [
[[package]]
name = "huggingface-hub"
-version = "0.29.1"
+version = "0.29.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "filelock" },
@@ -1177,9 +1160,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/22/37/797d6476f13e5ef6af5fc48a5d641d32b39c37e166ccf40c3714c5854a85/huggingface_hub-0.29.1.tar.gz", hash = "sha256:9524eae42077b8ff4fc459ceb7a514eca1c1232b775276b009709fe2a084f250", size = 389776 }
+sdist = { url = "https://files.pythonhosted.org/packages/58/b2/f8b3c9842a794e8203448725aefa02d7c9e0da42d5f22f4ed806057cc36e/huggingface_hub-0.29.2.tar.gz", hash = "sha256:590b29c0dcbd0ee4b7b023714dc1ad8563fe4a68a91463438b74e980d28afaf3", size = 389816 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ae/05/75b90de9093de0aadafc868bb2fa7c57651fd8f45384adf39bd77f63980d/huggingface_hub-0.29.1-py3-none-any.whl", hash = "sha256:352f69caf16566c7b6de84b54a822f6238e17ddd8ae3da4f8f2272aea5b198d5", size = 468049 },
+ { url = "https://files.pythonhosted.org/packages/13/5f/088ff08dc41808fcd99d9972b9bcfa7e3a35e30e8b0a3155b57938f1611c/huggingface_hub-0.29.2-py3-none-any.whl", hash = "sha256:c56f20fca09ef19da84dcde2b76379ecdaddf390b083f59f166715584953307d", size = 468087 },
]
[[package]]
@@ -1202,11 +1185,11 @@ wheels = [
[[package]]
name = "identify"
-version = "2.6.8"
+version = "2.6.9"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f9/fa/5eb460539e6f5252a7c5a931b53426e49258cde17e3d50685031c300a8fd/identify-2.6.8.tar.gz", hash = "sha256:61491417ea2c0c5c670484fd8abbb34de34cdae1e5f39a73ee65e48e4bb663fc", size = 99249 }
+sdist = { url = "https://files.pythonhosted.org/packages/9b/98/a71ab060daec766acc30fb47dfca219d03de34a70d616a79a38c6066c5bf/identify-2.6.9.tar.gz", hash = "sha256:d40dfe3142a1421d8518e3d3985ef5ac42890683e32306ad614a29490abeb6bf", size = 99249 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/78/8c/4bfcab2d8286473b8d83ea742716f4b79290172e75f91142bc1534b05b9a/identify-2.6.8-py2.py3-none-any.whl", hash = "sha256:83657f0f766a3c8d0eaea16d4ef42494b39b34629a4b3192a9d020d349b3e255", size = 99109 },
+ { url = "https://files.pythonhosted.org/packages/07/ce/0845144ed1f0e25db5e7a79c2354c1da4b5ce392b8966449d5db8dca18f1/identify-2.6.9-py2.py3-none-any.whl", hash = "sha256:c98b4322da415a8e5a70ff6e51fbc2d2932c015532d77e9f8537b4ba7813b150", size = 99101 },
]
[[package]]
@@ -1218,15 +1201,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
]
-[[package]]
-name = "imagesize"
-version = "1.4.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 },
-]
-
[[package]]
name = "importlib-resources"
version = "6.5.2"
@@ -1280,7 +1254,7 @@ wheels = [
[[package]]
name = "ipython"
-version = "9.0.0"
+version = "9.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
@@ -1294,9 +1268,9 @@ dependencies = [
{ name = "stack-data" },
{ name = "traitlets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/de/39/264894738a202ddaf6abae39b3f84671ddee23fd292dbb3e10039e70300c/ipython-9.0.0.tar.gz", hash = "sha256:9368d65b3d4a471e9a698fed3ea486bbf6737e45111e915279c971b77f974397", size = 4364165 }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/ce/012a0f40ca58a966f87a6e894d6828e2817657cbdf522b02a5d3a87d92ce/ipython-9.0.2.tar.gz", hash = "sha256:ec7b479e3e5656bf4f58c652c120494df1820f4f28f522fb7ca09e213c2aab52", size = 4366102 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/85/a1/894e4c0b6ac994045c6edeb2b6fdf69c59f20fcd2e348a42f4e40889181c/ipython-9.0.0-py3-none-any.whl", hash = "sha256:2cce23069b830a54a5b9d3d66ccd6433047c1503a7b9a3b34593c0b5c2c08477", size = 592040 },
+ { url = "https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl", hash = "sha256:143ef3ea6fb1e1bffb4c74b114051de653ffb7737a3f7ab1670e657ca6ae8c44", size = 600524 },
]
[[package]]
@@ -1346,14 +1320,14 @@ wheels = [
[[package]]
name = "jinja2"
-version = "3.1.5"
+version = "3.1.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 }
+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/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 },
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 },
]
[[package]]
@@ -1617,23 +1591,20 @@ wheels = [
[[package]]
name = "langchain"
-version = "0.3.19"
+version = "0.3.20"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "aiohttp" },
{ name = "langchain-core" },
{ name = "langchain-text-splitters" },
{ name = "langsmith" },
- { name = "numpy" },
{ name = "pydantic" },
{ name = "pyyaml" },
{ name = "requests" },
{ name = "sqlalchemy" },
- { name = "tenacity" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/a2/cf/a064ef27d5f3154491c85783590a25d7ae22340cddedf9bf47496044e4eb/langchain-0.3.19.tar.gz", hash = "sha256:b96f8a445f01d15d522129ffe77cc89c8468dbd65830d153a676de8f6b899e7b", size = 10224228 }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/b0/5121cdd19cf99e684043f4eae528c893f56bd25e7711d4de89f27832a5f3/langchain-0.3.20.tar.gz", hash = "sha256:edcc3241703e1f6557ef5a5c35cd56f9ccc25ff12e38b4829c66d94971737a93", size = 10225276 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/18/7d/0f4cc3317634195381f87c5d90268f29b9a31fda62aa7a7f36a1c27b06f3/langchain-0.3.19-py3-none-any.whl", hash = "sha256:1e16d97db9106640b7de4c69f8f5ed22eeda56b45b9241279e83f111640eff16", size = 1010630 },
+ { url = "https://files.pythonhosted.org/packages/b5/d4/afe8174838bdd3baba5d6a19e9f3af4c54c5db1ab4d66ef0b650c6157919/langchain-0.3.20-py3-none-any.whl", hash = "sha256:273287f8e61ffdf7e811cf8799e6a71e9381325b8625fd6618900faba79cfdd0", size = 1011577 },
]
[package.optional-dependencies]
@@ -1643,21 +1614,21 @@ openai = [
[[package]]
name = "langchain-anthropic"
-version = "0.3.8"
+version = "0.3.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anthropic" },
{ name = "langchain-core" },
{ name = "pydantic" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/63/2f/6ec88725da9cbb1c2b1295f6903faa2fa87fda07c87f8f0dfdec85f687dc/langchain_anthropic-0.3.8.tar.gz", hash = "sha256:1932977b8105744739ffdcb39861b041b73ae93846d0896a775fcea9a29e4b2b", size = 40585 }
+sdist = { url = "https://files.pythonhosted.org/packages/be/0a/7ccb79c41575b04266fc4def50f41d0a4689361421d82a14350d9d5e783e/langchain_anthropic-0.3.9.tar.gz", hash = "sha256:e8012d7986ad1d8412df6914c56f3c0d2797f231766a03bb1ad22cc7023e6e1d", size = 42205 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f2/b1/9f3f1b94c8770b2745c6cb950ef0f3299c2178ed3f9d73d61ccf3215390c/langchain_anthropic-0.3.8-py3-none-any.whl", hash = "sha256:05a70f51500d3c4e0f3e463730e193a25b6244e06b3bda3d7b2ec21d83d081ae", size = 23266 },
+ { url = "https://files.pythonhosted.org/packages/b9/27/258565b4a487fca7db363ea95765e6f1f00c23baa83dc4ec19a009213658/langchain_anthropic-0.3.9-py3-none-any.whl", hash = "sha256:adbbfaf3ce9798d46fb43d6fc01105630238f375dc6043d35d0aafab61fdbb71", size = 24414 },
]
[[package]]
name = "langchain-core"
-version = "0.3.40"
+version = "0.3.43"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jsonpatch" },
@@ -1668,23 +1639,23 @@ dependencies = [
{ name = "tenacity" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/4f/6b/7c3f5fa60639b885d8dbc932c37f0b0584ac5151ac6bdcd00b67b591e5e9/langchain_core-0.3.40.tar.gz", hash = "sha256:893a238b38491967c804662c1ec7c3e6ebaf223d1125331249c3cf3862ff2746", size = 528341 }
+sdist = { url = "https://files.pythonhosted.org/packages/8e/18/26255368f56d2749709fc2884c521d64471f32118ce09dfc677e0596be20/langchain_core-0.3.43.tar.gz", hash = "sha256:bec60f4f5665b536434ff747b8f23375a812e82cfa529f519b54cc1e7a94a875", size = 529403 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b7/01/b52e43f63261b5aae016cbe170bb5d8e8899770530075d11c1e45a07b97b/langchain_core-0.3.40-py3-none-any.whl", hash = "sha256:9f31358741f10a13db8531e8288b8a5ae91904018c5c2e6f739d6645a98fca03", size = 414346 },
+ { url = "https://files.pythonhosted.org/packages/20/0e/ddf9f5dc46b178df5c101666bb3bc7fc526d68cd81cdd60cbe1b6b438b30/langchain_core-0.3.43-py3-none-any.whl", hash = "sha256:caa6bc1f4c6ab71d3c2e400f8b62e1cd6dc5ac2c37e03f12f3e2c60befd5b273", size = 415421 },
]
[[package]]
name = "langchain-openai"
-version = "0.3.7"
+version = "0.3.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
{ name = "openai" },
{ name = "tiktoken" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/8e/3c/08add067e46409d3e881933155f546edb08644e5e4e2360ff22c6a2104a8/langchain_openai-0.3.7.tar.gz", hash = "sha256:b8b51a3aaa1cc3bda060651ea41145f7728219e8a7150b5404fb1e8446de9cef", size = 256488 }
+sdist = { url = "https://files.pythonhosted.org/packages/2e/04/ae071af0b04d1c3a8040498714091afd21149f6f8ae1dbab584317d9dfd7/langchain_openai-0.3.8.tar.gz", hash = "sha256:4d73727eda8102d1d07a2ca036278fccab0bb5e0abf353cec9c3973eb72550ec", size = 256898 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/36/0e/816c5293eda67600d374bb8484a9adab873c9096489f6f91634581919f35/langchain_openai-0.3.7-py3-none-any.whl", hash = "sha256:0aefc7bdf8e7398d41e09c4313cace816df6438f2aa93d34f79523487310f0da", size = 55254 },
+ { url = "https://files.pythonhosted.org/packages/a5/43/9c6a1101bcd751d52a3328a06956f85122f9aaa31da1b15a8e0f99a70317/langchain_openai-0.3.8-py3-none-any.whl", hash = "sha256:9004dc8ef853aece0d8f0feca7753dc97f710fa3e53874c8db66466520436dbb", size = 55446 },
]
[[package]]
@@ -1699,9 +1670,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4c/f8/6b82af988e65af9697f6a2f25373fb173fd32d48b62772a8773c5184c870/langchain_text_splitters-0.3.6-py3-none-any.whl", hash = "sha256:e5d7b850f6c14259ea930be4a964a65fa95d9df7e1dbdd8bad8416db72292f4e", size = 31197 },
]
+[[package]]
+name = "langchain-xai"
+version = "0.2.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "langchain-core" },
+ { name = "langchain-openai" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a3/94/a633bf1b4bbf66e4516f4188adc1174480c465ae12fb98f06c3e23c98519/langchain_xai-0.2.1.tar.gz", hash = "sha256:143a6f52be7617b5e5c68ab10c9b7df90914f54a6b3098566ce22b5d8fd89da5", size = 7788 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/88/d8050e610fadabf97c1745d24f0987b3e53b72fca63c8038ab1e0c103da9/langchain_xai-0.2.1-py3-none-any.whl", hash = "sha256:87228125cb15131663979d627210fca47dcd6b9a28462e8b5fee47f73bbed9f4", size = 6263 },
+]
+
[[package]]
name = "langgraph"
-version = "0.3.2"
+version = "0.3.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
@@ -1709,53 +1695,53 @@ dependencies = [
{ name = "langgraph-prebuilt" },
{ name = "langgraph-sdk" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/82/21/83cc5f941da39ba31b8ff07e5e55b3112839f0bf332d52e6b405ad365ae5/langgraph-0.3.2.tar.gz", hash = "sha256:4712c11a9355e5d15126e15a166807a1d6275d72cf74fd2303609ffc2505e7a8", size = 113460 }
+sdist = { url = "https://files.pythonhosted.org/packages/4e/fa/b1ecc95a2464bc7dbe5e67fbd21096013829119899c33236090b98c75508/langgraph-0.3.5.tar.gz", hash = "sha256:7c0d8e61aa02578b41036c9f7a599ccba2562d269f66ef76bacbba47a99a7eca", size = 114020 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/33/1c/c50719e89442094bace035e632da7be161e5389974f2b805b75fef7aab8f/langgraph-0.3.2-py3-none-any.whl", hash = "sha256:1e17f85e225bf4fc5f0f70bce89d8bc5d1536b7993e39e2e47baa1b1a17a439c", size = 130875 },
+ { url = "https://files.pythonhosted.org/packages/a4/5f/1e1d9173b5c41eff54f88d9f4ee82c38eb4928120ab6a21a68a78d1c499e/langgraph-0.3.5-py3-none-any.whl", hash = "sha256:be313ec300633c857873ea3e44aece4dd7d0b11f131d385108b359d377a85bf7", size = 131527 },
]
[[package]]
name = "langgraph-checkpoint"
-version = "2.0.16"
+version = "2.0.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
{ name = "msgpack" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/01/66/5d4a2013a84c511be289bb4a5ef91cbaad28c091b6b366fdb79710a1458b/langgraph_checkpoint-2.0.16.tar.gz", hash = "sha256:49ba8cfa12b2aae845ccc3b1fbd1d7a8d3a6c4a2e387ab3a92fca40dd3d4baa5", size = 34206 }
+sdist = { url = "https://files.pythonhosted.org/packages/76/1d/27a178de8a40c0cd53671f6a7e9aa21967a17672fdc774e5c0ae6cc406a4/langgraph_checkpoint-2.0.18.tar.gz", hash = "sha256:2822eedd028b454b7bfebfb7e04347aed1b64db97dedb7eb68ef0fb42641606d", size = 34947 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7c/63/03bc3dd304ead45b53313cab8727329e1d139a2d220f2d030c72242c860e/langgraph_checkpoint-2.0.16-py3-none-any.whl", hash = "sha256:dfab51076a6eddb5f9e146cfe1b977e3dd6419168b2afa23ff3f4e47973bf06f", size = 38291 },
+ { url = "https://files.pythonhosted.org/packages/21/11/91062b03b22b9ce6474df7c3e056417a4c2b029f9cc71829dd6f62479dd0/langgraph_checkpoint-2.0.18-py3-none-any.whl", hash = "sha256:941de442e5a893a6cabb8c3845f03159301b85f63ff4e8f2b308f7dfd96a3f59", size = 39106 },
]
[[package]]
name = "langgraph-prebuilt"
-version = "0.1.1"
+version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
{ name = "langgraph-checkpoint" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/22/15/848593ccace12e4f8b80cc0b159b0ba1da17605e1eecbda5f37d891748a3/langgraph_prebuilt-0.1.1.tar.gz", hash = "sha256:420a748ff93842f2b1a345a0c1ca3939d2bc7a2d46c20e9a9a0d8f148152cc47", size = 23257 }
+sdist = { url = "https://files.pythonhosted.org/packages/99/68/e1e692dbaeb4e9159b60a585fbfc26fbf073b3bb061caa2ff3153f85121a/langgraph_prebuilt-0.1.2.tar.gz", hash = "sha256:cfa7e54006d45e8f3d034ee88fa1d457c381bf6a2a0de0e64c5d3a776659e6d0", size = 23310 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3c/62/a424fdb892f578fa88b2ff4df0bfdebdc8b89501dacb8ca3b480305cbfef/langgraph_prebuilt-0.1.1-py3-none-any.whl", hash = "sha256:148a9558a36ec7e83cc6512f3521425c862b0463251ae0242ade52a448c54e78", size = 24622 },
+ { url = "https://files.pythonhosted.org/packages/73/2c/2fd70d557b7343f766f79dc8184b391f3417fc85b34dd04439cdd12dc2e1/langgraph_prebuilt-0.1.2-py3-none-any.whl", hash = "sha256:32028c4c4370576748e6c2e075cab1e13b5e3f2c196a390d71cacfb455212311", size = 24684 },
]
[[package]]
name = "langgraph-sdk"
-version = "0.1.53"
+version = "0.1.55"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
{ name = "orjson" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/39/b2/a261cfbf91a4499396ba0993cf5601076301dd22883d3c0901e905253917/langgraph_sdk-0.1.53.tar.gz", hash = "sha256:12906ed965905fa27e0c28d9fa07dc6fd89e6895ff321ff049fdf3965d057cc4", size = 42369 }
+sdist = { url = "https://files.pythonhosted.org/packages/7a/6c/8286151a21124dc0189b57495541c2e3cace317056f60feb04076b438f82/langgraph_sdk-0.1.55.tar.gz", hash = "sha256:89a0240157a27822cc4edd1c9e72bc852e20f5c71165a4c9b91eeffa11fd6a6b", size = 42690 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fc/97/3492a07b454cc74bf49938e83f0a95c608a8bc5c3dda338091d3c66e3ec5/langgraph_sdk-0.1.53-py3-none-any.whl", hash = "sha256:4fab62caad73661ffe4c3ababedcd0d7bfaaba986bee4416b9c28948458a3af5", size = 45441 },
+ { url = "https://files.pythonhosted.org/packages/4e/64/4b75f4b57f0c8f39bdb43aa74b1d2edcdb604b5baa58465ccc54b8b906c5/langgraph_sdk-0.1.55-py3-none-any.whl", hash = "sha256:266e92a558eb738da1ef04c29fbfc2157cd3a977b80905d9509a2cb79331f8fc", size = 45785 },
]
[[package]]
name = "langsmith"
-version = "0.3.11"
+version = "0.3.13"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -1766,9 +1752,9 @@ dependencies = [
{ name = "requests-toolbelt" },
{ name = "zstandard" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ea/34/c4c0eddad03e00457cd6be1a88c288cd4419da8d368d8f519a29abe5392c/langsmith-0.3.11.tar.gz", hash = "sha256:ddf29d24352e99de79c9618aaf95679214324e146c5d3d9475a7ddd2870018b1", size = 323815 }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/18/14b2427d627bba44abc613dc78cbd395580310856774ce8c555bd58308dd/langsmith-0.3.13.tar.gz", hash = "sha256:14014058cff408772acb93344e03cb64174837292d5f1ae09b2c8c1d8df45e92", size = 326588 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ff/68/514ffa62860202a5a0a3acbf5c05017ef9df38d4437d2cb44a3cf93d617b/langsmith-0.3.11-py3-none-any.whl", hash = "sha256:0cca22737ef07d3b038a437c141deda37e00add56022582680188b681bec095e", size = 335265 },
+ { url = "https://files.pythonhosted.org/packages/e0/09/3f909694aa0b104a611444959227832206864d92703e191a0f4b2a27d55b/langsmith-0.3.13-py3-none-any.whl", hash = "sha256:73aaf52bbc293b9415fff4f6dad68df40658081eb26c9cb2c7bd1ff57cedd695", size = 339683 },
]
[[package]]
@@ -1830,15 +1816,14 @@ wheels = [
[[package]]
name = "lox"
-version = "0.12.0"
+version = "0.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pathos" },
- { name = "sphinx-rtd-theme" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0f/b5/2bfa8da2a1dd6647c3ea0b8d7ae366bbb36b49f9f3858a253199daacb860/lox-0.12.0.tar.gz", hash = "sha256:cc7d5f867afb4dc7c2bce7bd6e90f4665c6df492863f35ff63229300b7219977", size = 37579 }
+sdist = { url = "https://files.pythonhosted.org/packages/95/85/923891e93122afcd724241a2bca01331ac2b956cde021445f51cf223e642/lox-0.13.0.tar.gz", hash = "sha256:f27b17e01d8ae92eec5e6e782477e0fb78ab8ceccec0a64385e50f5b7211bb34", size = 37565 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/02/9a/cc790ca4b853821b76acb5944d32036590a789e5f3b9e4f10a8962bcfda5/lox-0.12.0-py2.py3-none-any.whl", hash = "sha256:ac0a392662f3a75cc9097655d26169d5e3564e2670431fd9884a7a09a09f6921", size = 25372 },
+ { url = "https://files.pythonhosted.org/packages/70/d5/eca08aa7cd286c2dacd0c39c1dd9828e537b000a1ca246af0bdafae56340/lox-0.13.0-py2.py3-none-any.whl", hash = "sha256:37e1a206b7ac932082e7bdc49c4c26f1b9be1a737010db5b6cff8c707714fe67", size = 25363 },
]
[[package]]
@@ -1975,7 +1960,7 @@ wheels = [
[[package]]
name = "modal"
-version = "0.73.78"
+version = "0.73.91"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -1993,9 +1978,9 @@ dependencies = [
{ name = "typing-extensions" },
{ name = "watchfiles" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f6/68/90f2ef2ad678faa7bfd750f4c2bc16c363b11970825779df86fffe939a1d/modal-0.73.78.tar.gz", hash = "sha256:dcb3535549e47ba519ed927635a424e4b73e45afa942b002d5cbc8d3f78479f0", size = 469597 }
+sdist = { url = "https://files.pythonhosted.org/packages/d0/b6/c44d67b8468f86e2cad6c6f61afdc4021c97adabcc826d465eb45bd1b139/modal-0.73.91.tar.gz", hash = "sha256:77d8c556f9be37298e042ea0ea1602f5de3261ef1e3c4135f63a6f758be9c06d", size = 469844 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/97/1f/08178134de7c7bcdb3b8777193ed008188c305edfa7f8e58a6f1bda4ce8b/modal-0.73.78-py3-none-any.whl", hash = "sha256:602edf2ec8877078d5a8d9a0956baf085d59f3431aa654b1302130e9fbde39f2", size = 535815 },
+ { url = "https://files.pythonhosted.org/packages/1b/a9/8bf787c9dde7e0ae5d5c33ba9a75e5b67aadd90fd6046441c88024f651c7/modal-0.73.91-py3-none-any.whl", hash = "sha256:5d47a250dc8af992934359ffe9ee7c0cb1a1b7a732f47651750a982ed6b9a214", size = 536057 },
]
[[package]]
@@ -2094,11 +2079,11 @@ wheels = [
[[package]]
name = "narwhals"
-version = "1.28.0"
+version = "1.29.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ba/65/cc4f1d02d418e587fc5b9b31f3cbb8db83f4b35f91d7b59adfa8d947f644/narwhals-1.28.0.tar.gz", hash = "sha256:a2213fa44a039f724278fb15609889319e7c240403413f2606cc856c8d8f708d", size = 252143 }
+sdist = { url = "https://files.pythonhosted.org/packages/a7/17/7d35094da0820ae941d8ce51842f253da36c6f95360ea0afabfc18bc02c6/narwhals-1.29.1.tar.gz", hash = "sha256:c408acf09e90c116f247cf34f24a3a89d147e3e235b1d3c708cfd1960baf320a", size = 251464 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/73/aa/eedf2ade0c16a60541ca7acd48665c62dc0d11e1e910467b6c7e6b1eda34/narwhals-1.28.0-py3-none-any.whl", hash = "sha256:45d909ad6240944d447b0dae38074c5a919830dff3868d57b05a5526c1f06fe4", size = 308950 },
+ { url = "https://files.pythonhosted.org/packages/f1/22/380df533b08a57bc9013bb5714f33c571e1447828d83213a66adaefc0a04/narwhals-1.29.1-py3-none-any.whl", hash = "sha256:2f68cfbb2562672c4dfa54f158ed8c2828e9920ef784981cd9114e419c444216", size = 308220 },
]
[[package]]
@@ -2247,7 +2232,7 @@ wheels = [
[[package]]
name = "openai"
-version = "1.65.2"
+version = "1.65.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
@@ -2259,9 +2244,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f6/03/0bbf201a7e44920d892db0445874c8111be4255cb9495379df18d6d36ea1/openai-1.65.2.tar.gz", hash = "sha256:729623efc3fd91c956f35dd387fa5c718edd528c4bed9f00b40ef290200fb2ce", size = 359185 }
+sdist = { url = "https://files.pythonhosted.org/packages/56/cf/e02fb2c5a834803e6f29f43fd3dfe010303282d1ea450a5b95e28608860a/openai-1.65.5.tar.gz", hash = "sha256:17d39096bbcaf6c86580244b493a59e16613460147f0ba5ab6e608cdb6628149", size = 359548 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/2c/3b/722ed868cb56f70264190ed479b38b3e46d14daa267d559a3fe3bd9061cf/openai-1.65.2-py3-none-any.whl", hash = "sha256:27d9fe8de876e31394c2553c4e6226378b6ed85e480f586ccfe25b7193fb1750", size = 473206 },
+ { url = "https://files.pythonhosted.org/packages/fc/8f/a178d73277bf2d838617fa20ba4ae6952e26074664aacb53ae4532a69588/openai-1.65.5-py3-none-any.whl", hash = "sha256:5948a504e7b4003d921cfab81273813793a31c25b1d7b605797c01757e0141f1", size = 474468 },
]
[[package]]
@@ -2952,11 +2937,11 @@ wheels = [
[[package]]
name = "python-json-logger"
-version = "3.2.1"
+version = "3.3.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e3/c4/358cd13daa1d912ef795010897a483ab2f0b41c9ea1b35235a8b2f7d15a7/python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008", size = 16287 }
+sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/4b/72/2f30cf26664fcfa0bd8ec5ee62ec90c03bd485e4a294d92aabc76c5203a5/python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090", size = 14924 },
+ { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163 },
]
[[package]]
@@ -3015,15 +3000,15 @@ wheels = [
[[package]]
name = "pywin32"
-version = "308"
+version = "309"
source = { registry = "https://pypi.org/simple" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 },
- { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 },
- { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 },
- { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 },
- { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 },
- { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 },
+ { url = "https://files.pythonhosted.org/packages/20/2c/b0240b14ff3dba7a8a7122dc9bbf7fbd21ed0e8b57c109633675b5d1761f/pywin32-309-cp312-cp312-win32.whl", hash = "sha256:de9acacced5fa82f557298b1fed5fef7bd49beee04190f68e1e4783fbdc19926", size = 8790648 },
+ { url = "https://files.pythonhosted.org/packages/dd/11/c36884c732e2b3397deee808b5dac1abbb170ec37f94c6606fcb04d1e9d7/pywin32-309-cp312-cp312-win_amd64.whl", hash = "sha256:6ff9eebb77ffc3d59812c68db33c0a7817e1337e3537859499bd27586330fc9e", size = 9497399 },
+ { url = "https://files.pythonhosted.org/packages/18/9f/79703972958f8ba3fd38bc9bf1165810bd75124982419b0cc433a2894d46/pywin32-309-cp312-cp312-win_arm64.whl", hash = "sha256:619f3e0a327b5418d833f44dc87859523635cf339f86071cc65a13c07be3110f", size = 8454122 },
+ { url = "https://files.pythonhosted.org/packages/6c/c3/51aca6887cc5e410aa4cdc55662cf8438212440c67335c3f141b02eb8d52/pywin32-309-cp313-cp313-win32.whl", hash = "sha256:008bffd4afd6de8ca46c6486085414cc898263a21a63c7f860d54c9d02b45c8d", size = 8789700 },
+ { url = "https://files.pythonhosted.org/packages/dd/66/330f265140fa814b4ed1bf16aea701f9d005f8f4ab57a54feb17f53afe7e/pywin32-309-cp313-cp313-win_amd64.whl", hash = "sha256:bd0724f58492db4cbfbeb1fcd606495205aa119370c0ddc4f70e5771a3ab768d", size = 9496714 },
+ { url = "https://files.pythonhosted.org/packages/2c/84/9a51e6949a03f25cd329ece54dbf0846d57fadd2e79046c3b8d140aaa132/pywin32-309-cp313-cp313-win_arm64.whl", hash = "sha256:8fd9669cfd41863b688a1bc9b1d4d2d76fd4ba2128be50a70b0ea66b8d37953b", size = 8453052 },
]
[[package]]
@@ -3273,16 +3258,16 @@ wheels = [
[[package]]
name = "rich-click"
-version = "1.8.6"
+version = "1.8.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "rich" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ea/e3/ff1c715b673ec9e01f4482d8d0edfd9adf891f3630d83e695b38337a3889/rich_click-1.8.6.tar.gz", hash = "sha256:8a2448fd80e3d4e16fcb3815bfbc19be9bae75c9bb6aedf637901e45f3555752", size = 38247 }
+sdist = { url = "https://files.pythonhosted.org/packages/a6/7a/4b78c5997f2a799a8c5c07f3b2145bbcda40115c4d35c76fbadd418a3c89/rich_click-1.8.8.tar.gz", hash = "sha256:547c618dea916620af05d4a6456da797fbde904c97901f44d2f32f89d85d6c84", size = 39066 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/09/c20b04b6c9cf273995753f226ca51656e00f8a37f1e723f8c713b93b2ad4/rich_click-1.8.6-py3-none-any.whl", hash = "sha256:55fb571bad7d3d69ac43ca45f05b44616fd019616161b1815ff053567b9a8e22", size = 35076 },
+ { url = "https://files.pythonhosted.org/packages/fa/69/963f0bf44a654f6465bdb66fb5a91051b0d7af9f742b5bd7202607165036/rich_click-1.8.8-py3-none-any.whl", hash = "sha256:205aabd5a98e64ab2c105dee9e368be27480ba004c7dfa2accd0ed44f9f1550e", size = 35747 },
]
[[package]]
@@ -3299,15 +3284,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/1b/1c2f43af46456050b27810a7a013af8a7e12bc545a0cdc00eb0df55eb769/rich_toolkit-0.13.2-py3-none-any.whl", hash = "sha256:f3f6c583e5283298a2f7dbd3c65aca18b7f818ad96174113ab5bec0b0e35ed61", size = 13566 },
]
-[[package]]
-name = "roman-numerals-py"
-version = "3.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742 },
-]
-
[[package]]
name = "rpds-py"
version = "0.23.1"
@@ -3400,11 +3376,11 @@ wheels = [
[[package]]
name = "setuptools"
-version = "75.8.2"
+version = "76.0.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", size = 1344083 }
+sdist = { url = "https://files.pythonhosted.org/packages/32/d2/7b171caf085ba0d40d8391f54e1c75a1cda9255f542becf84575cfd8a732/setuptools-76.0.0.tar.gz", hash = "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4", size = 1349387 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", size = 1229385 },
+ { url = "https://files.pythonhosted.org/packages/37/66/d2d7e6ad554f3a7c7297c3f8ef6e22643ad3d35ef5c63bf488bc89f32f31/setuptools-76.0.0-py3-none-any.whl", hash = "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6", size = 1236106 },
]
[[package]]
@@ -3477,15 +3453,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
]
-[[package]]
-name = "snowballstemmer"
-version = "2.2.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 },
-]
-
[[package]]
name = "soupsieve"
version = "2.6"
@@ -3495,114 +3462,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 },
]
-[[package]]
-name = "sphinx"
-version = "8.2.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "alabaster" },
- { name = "babel" },
- { name = "colorama", marker = "sys_platform == 'win32'" },
- { name = "docutils" },
- { name = "imagesize" },
- { name = "jinja2" },
- { name = "packaging" },
- { name = "pygments" },
- { name = "requests" },
- { name = "roman-numerals-py" },
- { name = "snowballstemmer" },
- { name = "sphinxcontrib-applehelp" },
- { name = "sphinxcontrib-devhelp" },
- { name = "sphinxcontrib-htmlhelp" },
- { name = "sphinxcontrib-jsmath" },
- { name = "sphinxcontrib-qthelp" },
- { name = "sphinxcontrib-serializinghtml" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741 },
-]
-
-[[package]]
-name = "sphinx-rtd-theme"
-version = "3.0.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "docutils" },
- { name = "sphinx" },
- { name = "sphinxcontrib-jquery" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561 },
-]
-
-[[package]]
-name = "sphinxcontrib-applehelp"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 },
-]
-
-[[package]]
-name = "sphinxcontrib-devhelp"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 },
-]
-
-[[package]]
-name = "sphinxcontrib-htmlhelp"
-version = "2.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 },
-]
-
-[[package]]
-name = "sphinxcontrib-jquery"
-version = "4.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "sphinx" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104 },
-]
-
-[[package]]
-name = "sphinxcontrib-jsmath"
-version = "1.0.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 },
-]
-
-[[package]]
-name = "sphinxcontrib-qthelp"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 },
-]
-
-[[package]]
-name = "sphinxcontrib-serializinghtml"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 },
-]
-
[[package]]
name = "sqlalchemy"
version = "2.0.38"
@@ -3661,14 +3520,14 @@ wheels = [
[[package]]
name = "starlette"
-version = "0.46.0"
+version = "0.46.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/44/b6/fb9a32e3c5d59b1e383c357534c63c2d3caa6f25bf3c59dd89d296ecbaec/starlette-0.46.0.tar.gz", hash = "sha256:b359e4567456b28d473d0193f34c0de0ed49710d75ef183a74a5ce0499324f50", size = 2575568 }
+sdist = { url = "https://files.pythonhosted.org/packages/04/1b/52b27f2e13ceedc79a908e29eac426a63465a1a01248e5f24aa36a62aeb3/starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230", size = 2580102 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/41/94/8af675a62e3c91c2dee47cf92e602cfac86e8767b1a1ac3caf1b327c2ab0/starlette-0.46.0-py3-none-any.whl", hash = "sha256:913f0798bd90ba90a9156383bcf1350a17d6259451d0d8ee27fc0cf2db609038", size = 71991 },
+ { url = "https://files.pythonhosted.org/packages/a0/4b/528ccf7a982216885a1ff4908e886b8fb5f19862d1962f56a3fce2435a70/starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227", size = 71995 },
]
[[package]]
@@ -3898,11 +3757,11 @@ wheels = [
[[package]]
name = "trove-classifiers"
-version = "2025.2.18.16"
+version = "2025.3.3.18"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/13/8e/15ba2980e2704edecc53d15506a5bfa6efb3b1cadc5e4df7dc277bc199f8/trove_classifiers-2025.2.18.16.tar.gz", hash = "sha256:b1ee2e1668589217d4edf506743e28b1834da128f8a122bad522c02d837006e1", size = 16271 }
+sdist = { url = "https://files.pythonhosted.org/packages/08/e9/eb59303bac7aca949c4a4b0fa03a9b270be165d303a84cf2733d35a840ce/trove_classifiers-2025.3.3.18.tar.gz", hash = "sha256:3ffcfa90a428adfde1a5d90e3aa1b87fe474c5dbdbf5ccbca74ed69ba83c5ca7", size = 16239 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e1/67/038a8c7f60ffd6037374649826dbaa221e4b17755016b71a581162a15ce1/trove_classifiers-2025.2.18.16-py3-none-any.whl", hash = "sha256:7f6dfae899f23f04b73bc09e0754d9219a6fc4d6cca6acd62f1850a87ea92262", size = 13616 },
+ { url = "https://files.pythonhosted.org/packages/ef/bf/44195f3d9c3c4fe4cccf1c261c80d50781b9e8a0a6febf084c09c66740ff/trove_classifiers-2025.3.3.18-py3-none-any.whl", hash = "sha256:215630da61cf8757c373f81b602fc1283ec5a691cf12c5f9f96f11d6ad5fc7f2", size = 13629 },
]
[[package]]
@@ -3940,11 +3799,14 @@ wheels = [
[[package]]
name = "types-setuptools"
-version = "75.8.2.20250301"
+version = "75.8.2.20250305"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f6/02/5f476d1a4f2bb23ba47c3aac6246cae1159d430937171e58860a9f1f47f8/types_setuptools-75.8.2.20250301.tar.gz", hash = "sha256:c900bceebfffc92a4abc3cfd4b3c39ead1a2298a73dae37e6bc09da7baf797a0", size = 48468 }
+dependencies = [
+ { name = "setuptools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4f/18/a996861f5225e7d533a8d8b6aa61bcc9183429a6b8bc93b850aa2e22974d/types_setuptools-75.8.2.20250305.tar.gz", hash = "sha256:a987269b49488f21961a1d99aa8d281b611625883def6392a93855b31544e405", size = 42609 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f3/d8/aba63d60951fbec2917a9d2c8673605a57fdbfc9134268802988c99c7a4c/types_setuptools-75.8.2.20250301-py3-none-any.whl", hash = "sha256:3cc3e751db9e84eddf1e6d4f8c46bef2c77e6c25b0cd096f729ffa57d3d6a83a", size = 71841 },
+ { url = "https://files.pythonhosted.org/packages/d9/5b/bb33f99239a6d54ed1d8220a088d96d2ccacac7abb317df0d68d2500f3be/types_setuptools-75.8.2.20250305-py3-none-any.whl", hash = "sha256:ba80953fd1f5f49e552285c024f75b5223096a38a5138a54d18ddd3fa8f6a2d4", size = 63727 },
]
[[package]]
@@ -4016,27 +3878,27 @@ wheels = [
[[package]]
name = "uv"
-version = "0.6.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/4e/31/8f354a0b1df7ef4cb42da118dfae046d49f2c57ae427eb948a48a236c37d/uv-0.6.3.tar.gz", hash = "sha256:73587a192f2ebb8a25431d01037fe19f713fa99ff3b9fdf6e7a121131c6c5649", size = 3081857 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bb/c2/5a4138f1c615c7702943ce94155349943b5813e51faa38b6876a2ab86033/uv-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:facfec798eaddd07615b3a52973e38f2c8862ceb1bc685a5091891cd6c0c2a21", size = 15524019 },
- { url = "https://files.pythonhosted.org/packages/02/1d/abf01aa5e02b0a066f77b69a4f2f771c2ccd5424cd553e218afb026c65b9/uv-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b261895497f3c55a8a8917db0a1daeba1a9988ba487b068198d6cc4e8c13e769", size = 15537243 },
- { url = "https://files.pythonhosted.org/packages/ea/ac/4c1d5e04868051874dce74333fbe98e1f61e40a1522a9258a998775f2fab/uv-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:08e3f71a39c76c5b9ab63f9341b433a4ab8a1cc4e29d34ce81bd3b6f5bd642d8", size = 14450283 },
- { url = "https://files.pythonhosted.org/packages/00/8b/6cdb9a8cb4a5579d8b22d632e98d01f7c3695066ce1a2e33036edba2413a/uv-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:ebd4d1012c5043fe507f1f4477e7a54ec81e939e2a6e0229f23abb242f1622f5", size = 14909401 },
- { url = "https://files.pythonhosted.org/packages/51/8e/4d8c31250c7440a4c3704e81dab39f7f75db046e8b23f5322c3e47549557/uv-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f63b659a5ccbbd8c0ca5200c83ada6d19e73c0f1cafb8f4d9a7ef32544beb06d", size = 15245520 },
- { url = "https://files.pythonhosted.org/packages/4b/29/52976b3f7a79e4293763823e59d4de3b77506a1b9d298df0285be4879026/uv-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c23948f242a6bcbd274fa18387a608a52b21a3dfed18d324641964e305c348e9", size = 15890146 },
- { url = "https://files.pythonhosted.org/packages/54/38/a3c37aaf02b890d908edfec32e7a9b86e0df819df6443837929e40ac8d7e/uv-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0445ce49229001cec0a0b1240c6135e2252a3b8017ae878b0559411688a3e12a", size = 16817703 },
- { url = "https://files.pythonhosted.org/packages/df/0b/cd75c692266eb1cdea6764f9fb14d88babfa8d8433c414ac18623777760d/uv-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95ab9e9194046f4fb50daec6293e471fc18b6e1d350dba4f5328d0f19f6ec183", size = 16509829 },
- { url = "https://files.pythonhosted.org/packages/1c/5c/35747d595bf13f5b495a29ec9bb6212fd2fad7d8c32324a7faaeb6a643d0/uv-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af417925d7af00be949ebcab1bf187540bea235e9454aa2193ffae5b7ecc75cf", size = 20477063 },
- { url = "https://files.pythonhosted.org/packages/23/c7/4ea3d3f23d24240c54deee0248766c320163eef8b0117310f0be168fe0f0/uv-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed2d4e3c6e041bc8b55f931a58d758220e46e828b983967fbb318a117d879351", size = 16190208 },
- { url = "https://files.pythonhosted.org/packages/83/f2/96d4981c3490fabc5ba787703951124969f5b6dc8e3166543e7534de2dea/uv-0.6.3-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:a936275590f3091b05c03ad3ce69e2f8a4c964e80ae44ce0cf13cc3b412352f1", size = 15145146 },
- { url = "https://files.pythonhosted.org/packages/2b/62/1be7fb8b97fd057460b733bbdf30e71e771dcfbfab27b7db552fa4e219e6/uv-0.6.3-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:e842e96b941832cd95cb2fce90c5626b33e477773f425005e9237f8fd9ef5696", size = 15245907 },
- { url = "https://files.pythonhosted.org/packages/e0/1b/5849046e11f8154567b235fc8097ebb6a0d6416b3ce317300d9b06470481/uv-0.6.3-py3-none-musllinux_1_1_i686.whl", hash = "sha256:cd51af332fb0f6362cc44e4cca22c2d12c31dd52352c6259cae0e3570ce79da4", size = 15504955 },
- { url = "https://files.pythonhosted.org/packages/ec/46/d4fa9bd06f84bb83e452f3f201b058cd13969cb979402ff000c2e4c77a1e/uv-0.6.3-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:328677a74c7d998b654e4bfd50ba4347d0f3deed85284dbd041004a184353806", size = 16317436 },
- { url = "https://files.pythonhosted.org/packages/0b/d9/f93e4522cf1de51ff1a985ead75df85523cd1b689128b1b033c9e31204b8/uv-0.6.3-py3-none-win32.whl", hash = "sha256:dc2d965481bba716a0cf9d0f81896a70c341a854f0e4273f1887f22e52e5c9fb", size = 15545377 },
- { url = "https://files.pythonhosted.org/packages/91/ea/27dd790ec0d1f8c4ced06e27a409522bd157ed295a1140b3fb6cac3cd39a/uv-0.6.3-py3-none-win_amd64.whl", hash = "sha256:8fc19471fd4cfde1b31a47c239591d7c6dc0a31213f206d3953c528f9f3b406c", size = 16860609 },
- { url = "https://files.pythonhosted.org/packages/97/0f/01e48493264d75cfac6c953809e11c8356c77fb6be32dfce831bcf481ab2/uv-0.6.3-py3-none-win_arm64.whl", hash = "sha256:94a9d59c05f22829388e51a62a9cfddef4000a112e1c561bb5bd5761d4d672f1", size = 15697009 },
+version = "0.6.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5f/3b/9a699194b132948b377272f06f2218d6453d440c8bae77275cd7d21e64dc/uv-0.6.5.tar.gz", hash = "sha256:70ad4cc5f2b636edbeeebb3aee0a7daa66b17457038088be870ac7adc5a9842d", size = 3093602 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/40/ac0b8050e145ae7dab029e8590046f9f96af4c6a36a4c4ee328a81e56062/uv-0.6.5-py3-none-linux_armv6l.whl", hash = "sha256:c5676fc7cdd088e2c3342593c1d2dc379bf86a83301af7b0dfe8d45801a50d85", size = 15517362 },
+ { url = "https://files.pythonhosted.org/packages/3c/f8/c0c2a2d5021904830d0d9fac4885819d731af2ed8e4ec11d80751420c646/uv-0.6.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6e82de1cb6a116f7736de9542430d78c210d152c80723db8beffc14e5b4e4b40", size = 15606625 },
+ { url = "https://files.pythonhosted.org/packages/c6/f7/1c5a44233ba80938b316eb67b6f3087a5cdc032882fbb86abfb7b8d14f3a/uv-0.6.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:442639a874f6bb6864279f099c97739287d7e244bc25d0f791345cc69f46c940", size = 14483413 },
+ { url = "https://files.pythonhosted.org/packages/c9/15/68beb9094e976c9403d8b79de76601f793250d0ecb84cb69d5940ba36729/uv-0.6.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:b5445a509f500bbf18faba4e7cf5cc9763617c335d58afaa5f3e5a6e388dd4ee", size = 14914536 },
+ { url = "https://files.pythonhosted.org/packages/1c/49/42d917ec3a6d79751d54862ac8d5170b1f509680bcad506d949f5d365aaa/uv-0.6.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c5683bccfc2b92cdc2f91e2904baa8ee2b5893b33ac8acac25e702ce7d3e5415", size = 15264210 },
+ { url = "https://files.pythonhosted.org/packages/ad/4c/446c039726dc6f04cd963f2a0813ec4e35c57d3566a9daf0272e2c5e311d/uv-0.6.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43847ef95d56c239de940339e5cfc2ade58249005e8ab97244fdb69fb9761572", size = 15974263 },
+ { url = "https://files.pythonhosted.org/packages/8b/c6/46f5334c73846bb9afd883ca9a1f41262d677a3ee0e3ff0063acef5a8a05/uv-0.6.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ef0b2f810d87aa9bbad15c3ab113e555871f14c9cd8ad2205338fb0358aaf52d", size = 16842142 },
+ { url = "https://files.pythonhosted.org/packages/a3/b4/b01cfa179b6e65aeb58eaf89bd3a6880082ec0fa391f93cc786db65ace03/uv-0.6.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b56fa88951fab3bc7164255d844de9ad048e6a04a95f1c2774637e06889efe6", size = 16539261 },
+ { url = "https://files.pythonhosted.org/packages/cb/cc/1e00721e749ecc4d2cf8d233a9f9585108afcd62e3da4a2784f15d1f3a65/uv-0.6.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f3b3f21b2385545f499f6cc21f44eac3bbb0f6cb98fbf9c6d3e58db186c8a41", size = 20699878 },
+ { url = "https://files.pythonhosted.org/packages/66/32/ad9944c9716360c82fb62516aca72bdeaedf7991483383f3a06734cb2cf4/uv-0.6.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15dae245979add192c4845947da1a9141f95c19403d1c0d75019182e6882e7d4", size = 16249288 },
+ { url = "https://files.pythonhosted.org/packages/80/7a/cad1a0382182b923f881ec9b592106abb0df55be42384bfbe3694fb5b243/uv-0.6.5-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:26a90e69d6438de2ec03ab452cc48d1cb375249c6b6980f4ed177f324a5ad8b3", size = 15156024 },
+ { url = "https://files.pythonhosted.org/packages/f5/f1/a9721cf48232ee4d0871c74dbc7ff5e2e90fb79aab4096c76f12eb3ba453/uv-0.6.5-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:776500595ff7cda1ffa5a76dd3ff9de3819f1e26c493938cbdc20c1ab766b2eb", size = 15213625 },
+ { url = "https://files.pythonhosted.org/packages/cc/a4/02a2e4eb1a09b87086c92ebeb9953dca427b54ec113be2e0445abc850b3c/uv-0.6.5-py3-none-musllinux_1_1_i686.whl", hash = "sha256:6210fe6ef6a0ae3dc618611fcc8ada4e620fea5172fb8a9c50d3a59b6915b023", size = 15558969 },
+ { url = "https://files.pythonhosted.org/packages/78/c1/5a3a0905a630a5b99b7b3cc1a400bcb65401e1a325bf43ced50e8bd007a2/uv-0.6.5-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d47b4adffcdbe30bd678c7670e63c671b8b34a667898501e588f2e7cbce34656", size = 16345448 },
+ { url = "https://files.pythonhosted.org/packages/36/80/721c0621f14071462bc8420b16c4cba3c9c066f5775eab7dc56d9b559c30/uv-0.6.5-py3-none-win32.whl", hash = "sha256:23aa8e8ca7795f54f6cf0f0fbd0aaf7b26bf4aae42f8c10643bcba6d42485a3f", size = 15657842 },
+ { url = "https://files.pythonhosted.org/packages/09/d1/751610f12b99ab6166887554cd98d376f22ffb6fdc69e57676735e781ccc/uv-0.6.5-py3-none-win_amd64.whl", hash = "sha256:5323e9219a519c6553111820a8c54588d426380404a208b23cf4c3265bc87ec6", size = 16958031 },
+ { url = "https://files.pythonhosted.org/packages/0d/63/0080e1618c936297001a3da462dd83f73391bacf7857ed7b327518d57f93/uv-0.6.5-py3-none-win_arm64.whl", hash = "sha256:a481254f63240023239ecec80cd690dec05875e248eb4b9d7f66957b017798b1", size = 15811982 },
]
[[package]]
@@ -4085,16 +3947,16 @@ wheels = [
[[package]]
name = "virtualenv"
-version = "20.29.2"
+version = "20.29.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
{ name = "filelock" },
{ name = "platformdirs" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f1/88/dacc875dd54a8acadb4bcbfd4e3e86df8be75527116c91d8f9784f5e9cab/virtualenv-20.29.2.tar.gz", hash = "sha256:fdaabebf6d03b5ba83ae0a02cfe96f48a716f4fae556461d180825866f75b728", size = 4320272 }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/9c/57d19fa093bcf5ac61a48087dd44d00655f85421d1aa9722f8befbf3f40a/virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac", size = 4320280 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/93/fa/849483d56773ae29740ae70043ad88e068f98a6401aa819b5d6bee604683/virtualenv-20.29.2-py3-none-any.whl", hash = "sha256:febddfc3d1ea571bdb1dc0f98d7b45d24def7428214d4fb73cc486c9568cce6a", size = 4301478 },
+ { url = "https://files.pythonhosted.org/packages/c2/eb/c6db6e3001d58c6a9e67c74bb7b4206767caa3ccc28c6b9eaf4c23fb4e34/virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170", size = 4301458 },
]
[[package]]
@@ -4171,33 +4033,33 @@ wheels = [
[[package]]
name = "websockets"
-version = "15.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/2e/7a/8bc4d15af7ff30f7ba34f9a172063bfcee9f5001d7cef04bee800a658f33/websockets-15.0.tar.gz", hash = "sha256:ca36151289a15b39d8d683fd8b7abbe26fc50be311066c5f8dcf3cb8cee107ab", size = 175574 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/22/1e/92c4547d7b2a93f848aedaf37e9054111bc00dc11bff4385ca3f80dbb412/websockets-15.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cccc18077acd34c8072578394ec79563664b1c205f7a86a62e94fafc7b59001f", size = 174709 },
- { url = "https://files.pythonhosted.org/packages/9f/37/eae4830a28061ba552516d84478686b637cd9e57d6a90b45ad69e89cb0af/websockets-15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4c22992e24f12de340ca5f824121a5b3e1a37ad4360b4e1aaf15e9d1c42582d", size = 172372 },
- { url = "https://files.pythonhosted.org/packages/46/2f/b409f8b8aa9328d5a47f7a301a43319d540d70cf036d1e6443675978a988/websockets-15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1206432cc6c644f6fc03374b264c5ff805d980311563202ed7fef91a38906276", size = 172607 },
- { url = "https://files.pythonhosted.org/packages/d6/81/d7e2e4542d4b4df849b0110df1b1f94f2647b71ab4b65d672090931ad2bb/websockets-15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d3cc75ef3e17490042c47e0523aee1bcc4eacd2482796107fd59dd1100a44bc", size = 182422 },
- { url = "https://files.pythonhosted.org/packages/b6/91/3b303160938d123eea97f58be363f7dbec76e8c59d587e07b5bc257dd584/websockets-15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b89504227a5311610e4be16071465885a0a3d6b0e82e305ef46d9b064ce5fb72", size = 181362 },
- { url = "https://files.pythonhosted.org/packages/f2/8b/df6807f1ca339c567aba9a7ab03bfdb9a833f625e8d2b4fc7529e4c701de/websockets-15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56e3efe356416bc67a8e093607315951d76910f03d2b3ad49c4ade9207bf710d", size = 181787 },
- { url = "https://files.pythonhosted.org/packages/21/37/e6d3d5ebb0ebcaf98ae84904205c9dcaf3e0fe93e65000b9f08631ed7309/websockets-15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f2205cdb444a42a7919690238fb5979a05439b9dbb73dd47c863d39640d85ab", size = 182058 },
- { url = "https://files.pythonhosted.org/packages/c9/df/6aca296f2be4c638ad20908bb3d7c94ce7afc8d9b4b2b0780d1fc59b359c/websockets-15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aea01f40995fa0945c020228ab919b8dfc93fc8a9f2d3d705ab5b793f32d9e99", size = 181434 },
- { url = "https://files.pythonhosted.org/packages/88/f1/75717a982bab39bbe63c83f9df0e7753e5c98bab907eb4fb5d97fe5c8c11/websockets-15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9f8e33747b1332db11cf7fcf4a9512bef9748cb5eb4d3f7fbc8c30d75dc6ffc", size = 181431 },
- { url = "https://files.pythonhosted.org/packages/e7/15/cee9e63ed9ac5bfc1a3ae8fc6c02c41745023c21eed622eef142d8fdd749/websockets-15.0-cp312-cp312-win32.whl", hash = "sha256:32e02a2d83f4954aa8c17e03fe8ec6962432c39aca4be7e8ee346b05a3476904", size = 175678 },
- { url = "https://files.pythonhosted.org/packages/4e/00/993974c60f40faabb725d4dbae8b072ef73b4c4454bd261d3b1d34ace41f/websockets-15.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc02b159b65c05f2ed9ec176b715b66918a674bd4daed48a9a7a590dd4be1aa", size = 176119 },
- { url = "https://files.pythonhosted.org/packages/12/23/be28dc1023707ac51768f848d28a946443041a348ee3a54abdf9f6283372/websockets-15.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d2244d8ab24374bed366f9ff206e2619345f9cd7fe79aad5225f53faac28b6b1", size = 174714 },
- { url = "https://files.pythonhosted.org/packages/8f/ff/02b5e9fbb078e7666bf3d25c18c69b499747a12f3e7f2776063ef3fb7061/websockets-15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3a302241fbe825a3e4fe07666a2ab513edfdc6d43ce24b79691b45115273b5e7", size = 172374 },
- { url = "https://files.pythonhosted.org/packages/8e/61/901c8d4698e0477eff4c3c664d53f898b601fa83af4ce81946650ec2a4cb/websockets-15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:10552fed076757a70ba2c18edcbc601c7637b30cdfe8c24b65171e824c7d6081", size = 172605 },
- { url = "https://files.pythonhosted.org/packages/d2/4b/dc47601a80dff317aecf8da7b4ab278d11d3494b2c373b493e4887561f90/websockets-15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c53f97032b87a406044a1c33d1e9290cc38b117a8062e8a8b285175d7e2f99c9", size = 182380 },
- { url = "https://files.pythonhosted.org/packages/83/f7/b155d2b38f05ed47a0b8de1c9ea245fcd7fc625d89f35a37eccba34b42de/websockets-15.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1caf951110ca757b8ad9c4974f5cac7b8413004d2f29707e4d03a65d54cedf2b", size = 181325 },
- { url = "https://files.pythonhosted.org/packages/d3/ff/040a20c01c294695cac0e361caf86f33347acc38f164f6d2be1d3e007d9f/websockets-15.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bf1ab71f9f23b0a1d52ec1682a3907e0c208c12fef9c3e99d2b80166b17905f", size = 181763 },
- { url = "https://files.pythonhosted.org/packages/cb/6a/af23e93678fda8341ac8775e85123425e45c608389d3514863c702896ea5/websockets-15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bfcd3acc1a81f106abac6afd42327d2cf1e77ec905ae11dc1d9142a006a496b6", size = 182097 },
- { url = "https://files.pythonhosted.org/packages/7e/3e/1069e159c30129dc03c01513b5830237e576f47cedb888777dd885cae583/websockets-15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8c5c8e1bac05ef3c23722e591ef4f688f528235e2480f157a9cfe0a19081375", size = 181485 },
- { url = "https://files.pythonhosted.org/packages/9a/a7/c91c47103f1cd941b576bbc452601e9e01f67d5c9be3e0a9abe726491ab5/websockets-15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:86bfb52a9cfbcc09aba2b71388b0a20ea5c52b6517c0b2e316222435a8cdab72", size = 181466 },
- { url = "https://files.pythonhosted.org/packages/16/32/a4ca6e3d56c24aac46b0cf5c03b841379f6409d07fc2044b244f90f54105/websockets-15.0-cp313-cp313-win32.whl", hash = "sha256:26ba70fed190708551c19a360f9d7eca8e8c0f615d19a574292b7229e0ae324c", size = 175673 },
- { url = "https://files.pythonhosted.org/packages/c0/31/25a417a23e985b61ffa5544f9facfe4a118cb64d664c886f1244a8baeca5/websockets-15.0-cp313-cp313-win_amd64.whl", hash = "sha256:ae721bcc8e69846af00b7a77a220614d9b2ec57d25017a6bbde3a99473e41ce8", size = 176115 },
- { url = "https://files.pythonhosted.org/packages/e8/b2/31eec524b53f01cd8343f10a8e429730c52c1849941d1f530f8253b6d934/websockets-15.0-py3-none-any.whl", hash = "sha256:51ffd53c53c4442415b613497a34ba0aa7b99ac07f1e4a62db5dcd640ae6c3c3", size = 169023 },
+version = "15.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437 },
+ { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096 },
+ { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332 },
+ { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152 },
+ { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096 },
+ { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523 },
+ { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790 },
+ { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165 },
+ { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160 },
+ { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395 },
+ { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841 },
+ { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440 },
+ { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098 },
+ { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329 },
+ { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111 },
+ { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054 },
+ { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496 },
+ { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829 },
+ { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217 },
+ { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195 },
+ { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393 },
+ { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837 },
+ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 },
]
[[package]]
diff --git a/docs/api-reference/core/Codebase.mdx b/docs/api-reference/core/Codebase.mdx
index bd47e4dd6..963ee95db 100644
--- a/docs/api-reference/core/Codebase.mdx
+++ b/docs/api-reference/core/Codebase.mdx
@@ -11,7 +11,7 @@ import {HorizontalDivider} from '/snippets/HorizontalDivider.mdx';
import {GithubLinkNote} from '/snippets/GithubLinkNote.mdx';
import {Attribute} from '/snippets/Attribute.mdx';
-
+
## Attributes
@@ -89,7 +89,7 @@ import {Attribute} from '/snippets/Attribute.mdx';
### ai
Generates a response from the AI based on the provided prompt, target, and context.
-
+
checkout
Checks out a git branch or commit and syncs the codebase graph to the new state.
-
+
commit
Commits all staged changes to the codebase graph and synchronizes the graph with the filesystem if specified.
-
+
create_directory
Creates a directory at the specified path.
-
+
create_file
Creates a new file in the codebase with specified content.
-
+
create_pr
Creates a pull request from the current branch to the repository's default branch.
-
+
create_pr_comment
Create a comment on a pull request
-
+
None } description=""/>
@@ -265,7 +265,7 @@ Create a comment on a pull request
### create_pr_review_comment
Create a review comment on a pull request.
-
+
None } description=""/>
@@ -273,7 +273,7 @@ Create a review comment on a pull request.
### files
A list property that returns all files in the codebase.
-
+
list[ SourceFile ] | list[ File ]> } description="A sorted list of source files in the codebase."/>
@@ -281,7 +281,7 @@ A list property that returns all files in the codebase.
### find_by_span
Finds editable objects that overlap with the given source code span.
-
+
from_files
Creates a Codebase instance from multiple files.
-
+
Codebase> } description="A Codebase instance initialized with the provided files"/>
@@ -306,7 +306,7 @@ Creates a Codebase instance from multiple files.
### from_repo
Fetches a codebase from GitHub and returns a Codebase instance.
-
+
from_string
Creates a Codebase instance from a string of code.
-
+
Codebase> } description="A Codebase instance initialized with the provided code Example: >>> # Python code >>> code = "def add(a, b): return a + b" >>> codebase = Codebase.from_string(code, language="python") >>> # TypeScript code >>> code = "function add(a: number, b: number): number { return a + b; }" >>> codebase = Codebase.from_string(code, language="typescript")"/>
@@ -367,7 +367,7 @@ Creates a Codebase instance from a string of code.
### get_class
Returns a class that matches the given name.
-
+
get_directory
Returns Directory by `dir_path`, or full path to the directory from codebase root.
-
+
get_file
Retrieves a file from the codebase by its filepath.
-
+
get_function
Retrieves a function from the codebase by its name.
-
+
get_modified_symbols_in_pr
Get all modified symbols in a pull request
-
+
tuple[str, dict[str, str], list[str]] } description=""/>
@@ -473,7 +473,7 @@ Get all modified symbols in a pull request
### get_relative_path
Calculates a relative path from one file to another, removing the extension from the target file.
-
+
get_symbol
Returns a Symbol by name from the codebase.
-
+
get_symbols
Retrieves all symbols in the codebase that match the given symbol name.
-
+
git_commit
Stages + commits all changes to the codebase and git.
-
+
has_directory
Returns a boolean indicating if a directory exists in the codebase.
-
+
has_file
Determines if a file exists in the codebase.
-
+
has_symbol
Returns whether a symbol exists in the codebase.
-
+
reset
Resets the codebase by
-
+
None } description=""/>
@@ -624,7 +624,7 @@ Resets the codebase by
### set_ai_key
Sets the OpenAI key for the current Codebase instance.
-
+
None } description=""/>
@@ -632,7 +632,7 @@ Sets the OpenAI key for the current Codebase instance.
### set_session_options
Sets the session options for the current codebase.
-
+
should_fix
Returns True if the flag should be fixed based on the current mode and active group.
-
+
visualize
Visualizes a NetworkX graph or Plotly figure.
-
+
+
### Inherits from
[PySymbol](/api-reference/python/PySymbol), [Assignment](/api-reference/core/Assignment), [Symbol](/api-reference/core/Symbol), [HasValue](/api-reference/core/HasValue), [Typeable](/api-reference/core/Typeable), [Usable](/api-reference/core/Usable), [Importable](/api-reference/core/Importable), [Editable](/api-reference/core/Editable), [Expression](/api-reference/core/Expression), [HasName](/api-reference/core/HasName)
@@ -291,7 +291,7 @@ Flags a Python symbol by adding a flag comment and returning a CodeFlag.
### from_named_expression
Creates a MultiExpression from a Python named expression.
-
+
remove
Deletes this assignment and its related extended nodes (e.g. decorators, comments).
-
+
+
+
+
+This modifies over 40 files and correctly removes old code, passes lint + tests, etc.
+
+What made this work?
+
+Devin operates like a state machine: write a codemod, run it through the linter, analyze failures, and refine. Each iteration adds handling for new edge cases until the codemod successfully transforms the entire codebase. This is the same cycle developers use for many large-scale refactors, just automated.
+
+```mermaid
+flowchart LR
+ style EditRun fill:#ff6b6b,stroke:#000,stroke-width:3px,color:#000,font-weight:bold,font-size:16px
+ style Linter fill:#4dabf7,stroke:#000,stroke-width:3px,color:#000,font-weight:bold,font-size:16px
+ style Success fill:#cc5de8,stroke:#000,stroke-width:3px,color:#000,font-weight:bold,font-size:16px
+
+ EditRun["Edit + Run
Codemod"] --> Linter["Run
Linter"]
+ Linter --"success?"--- Success["Success"]
+ Linter --"errors found"--- EditRun
+
+ linkStyle default stroke-width:2px
+ classDef edgeLabel fill:#e9ecef,color:#000,font-weight:bold
+ class success?,errors edgeLabel
+```
+
+The nice part about this approach is that we don't have to blindly trust the AI. There's no magic - it's just a program we can run and verify through linter/test output. The codemod is easy to review, and we can update it if we need to add exceptions or edge cases. Much better than trying to manually review hundreds of individual edits.
+
+## Try it yourself
+
+Want to experience this with your own Devin instance? Install the Codegen CLI in your Devin box:
+
+```bash
+uv tool install codegen --python 3.13
+```
+
+Then use the following prompt:
+
+
+ Download System Prompt
+
+
+Or try it with other platform-level modifications supported by Codegen:
+
+
+
+ Automatically convert Promise chains to async/await syntax across your codebase.
+
+
+ Move and organize code safely with automatic import and dependency handling.
+
+
+ Convert class components to hooks, standardize props, and organize components.
+
+
+ Automatically convert unittest test suites to modern pytest style.
+
+
+
+We'd love to hear how it works for you! Let us know in our [community](https://community.codegen.com) and share your experience developing codemods with Devin or other code assistants.
\ No newline at end of file
diff --git a/docs/blog/posts.mdx b/docs/blog/posts.mdx
index 2d1b27ed1..ad92465be 100644
--- a/docs/blog/posts.mdx
+++ b/docs/blog/posts.mdx
@@ -4,7 +4,21 @@ icon: "clock"
iconType: "solid"
---
-
+
+
+## Agents are Better with Codemods
+
+How AI agents like Devin can use codemods to safely make systematic changes across entire codebases, from deleting dead code to modernizing React components.
+
+
+
+
+
+
## Act via Code
diff --git a/docs/changelog/changelog.mdx b/docs/changelog/changelog.mdx
index 223a470cc..49e17df61 100644
--- a/docs/changelog/changelog.mdx
+++ b/docs/changelog/changelog.mdx
@@ -4,6 +4,92 @@ icon: "clock"
iconType: "solid"
---
+
+### [Fixes null body issue in pull request context.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.48.6)
+- Fix null body issue in pull request context
+
+
+
+### [Adds dataset subsets and improves CLI arguments.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.48.5)
+- Updated OpenAI dependency
+- Improved command line arguments
+- Added subsets of swe-bench lite dataset
+
+
+
+### [Fixes import issue and removes outdated Chat Agent.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.48.4)
+- Fix search tool import issue
+- Remove obsolete Chat Agent implementation
+
+
+
+### [Fixes git token issue and integrates xAI provider.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.48.3)
+- Fix issue with remote git repo token requirement
+- Integrate new xAI provider
+- Update and expand API documentation
+
+
+
+### [Fixes PR viewing issue returning 404 error.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.48.2)
+- Fix issue with viewing PR returning 404
+
+
+
+### [Fixes and documentation update with langsmith tagging.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.48.1)
+- Updated API reference
+- Fixed issue with Codebase.from_repo
+- Enabled model name tagging for langsmith traces
+
+
+
+### [adds view PR checks tool.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.48.0)
+- Add view PR checks tool
+
+
+
+### [Adds GitHub issues search tool and eval command update.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.47.0)
+- Adds a new tool for searching GitHub issues
+- Makes model a parameter for the run eval command
+
+
+
+### [Bug fixes and GitHub Webhook functionality improvements.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.46.1)
+- Fix invalid file handling bug
+- Improve GitHub Webhook functionality
+- Enhance testing and documentation updates
+
+
+
+### [Introduces a better search tool and dynamic scaling.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.46.0)
+- Fix issues with unpacking functionality
+- Implement dynamic scaling for asyncio requests
+- Introduce a better search tool
+- Enable evaluator to run on existing predictions
+
+
+
+### [Improved bug fixes with updated dependency.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.45.1)
+- Update dependency to improve bug fixes
+
+
+
+### [Improve performance and update documentation.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.45.0)
+- Add runner tooling feature
+- Speed up directory tree generation
+- Remove unnecessary tools from agent implementation
+- Update API reference and fix documentation links
+
+
+
+### [Fixes a Slack schema error.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.44.4)
+- Fix Slack schema error
+
+
+
+### [Fixes Slack event type handling for rich text.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.44.3)
+- Fix Slack event type handling for rich text
+
+
### [Fixes and improvements to event handling and codebase.](https://github.com/codegen-sh/codegen-sdk/releases/tag/v0.44.2)
- Fix Slack event handling with thread-ts addition
diff --git a/docs/images/devin-edits-codemod.png b/docs/images/devin-edits-codemod.png
new file mode 100644
index 000000000..3349b9589
Binary files /dev/null and b/docs/images/devin-edits-codemod.png differ
diff --git a/docs/introduction/advanced-settings.mdx b/docs/introduction/advanced-settings.mdx
new file mode 100644
index 000000000..e7297bd38
--- /dev/null
+++ b/docs/introduction/advanced-settings.mdx
@@ -0,0 +1,391 @@
+---
+title: "Advanced Settings"
+sidebarTitle: "Advanced Settings"
+icon: "memory"
+iconType: "solid"
+---
+
+Codegen's [Codebase](/api-reference/core/Codebase) constructor accepts a `CodebaseConfig` object which is used to configure more advanced behaviors of the graph construction process.
+
+These flags are helpful for debugging problematic repos, optimizing Codegen's performance, or testing unreleased or experimental (potentially backwards-breaking) features.
+
+
+**These are considered experimental features and may change in the future!**
+
+As such, they may have little to no testing or documentation. Many of these flags may also be unsupported in the future!
+
+If you need help, please visit our [community](/introduction/community).
+
+
+
+These configuration options are defined in [src/codegen/configs/models/codebase.py](https://github.com/codegen-sh/codegen/blob/develop/src/codegen/configs/models/codebase.py).
+
+
+# Usage
+
+You can customize the behavior of the graph construction process when initializing a [Codebase](/api-reference/core/Codebase) by passing a `CodebaseConfig` object with the desired configuration flags.
+
+```python
+from codegen import Codebase
+from codegen.configs import CodebaseConfig
+
+# Initialize a Codebase with custom configuration
+codebase = Codebase(
+ "",
+ config=CodebaseConfig(
+ flag1=...,
+ flag2=...,
+ ...
+ )
+)
+```
+
+# Table of Contents
+
+- [debug](#flag-debug)
+- [verify-graph](#flag-verify-graph)
+- [track-graph](#flag-track-graph)
+- [method-usages](#flag-method-usages)
+- [sync-enabled](#flag-sync-enabled)
+- [full-range-index](#flag-full-range-index)
+- [ignore-process-errors](#flag-ignore-process-errors)
+- [disable-graph](#flag-disable-graph)
+- [disable-file-parse](#flag-disable-file-parse)
+- [exp-lazy-graph](#flag-exp-lazy-graph)
+- [generics](#flag-generics)
+- [import-resolution-paths](#flag-import-resolution-paths)
+- [import-resolution-overrides](#flag-import-resolution-overrides)
+- [py-resolve-syspath](#flag-py-resolve-syspath)
+- [ts-dependency-manager](#flag-ts-dependency-manager)
+- [ts-language-engine](#flag-ts-language-engine)
+- [v8-ts-engine](#flag-v8-ts-engine)
+- [unpacking-assignment-partial-removal](#flag-unpacking-assignment-partial-removal)
+
+# Configuration Flags
+
+## Flag: `debug`
+> **Default: `False`**
+
+Enables verbose logging for debugging purposes. In its current form, it enables:
+- Verbose logging when adding nodes to the graph
+- Verbose logging during initial file parsing
+- Additional assertions on graph creation
+- Additional (costly) debug metrics on codebase construction
+- etc.
+
+
+This flag may be very noisy and significantly impact performance. It is generally not recommended to use.
+
+
+## Flag: `verify_graph`
+> **Default: `False`**
+
+Adds assertions for graph state during reset resync. Used to test and debug graph desyncs after a codebase reset.
+
+Runs `post_reset_validation` after a reset resync.
+
+
+This is an internal debug flag.
+
+
+## Flag: `track_graph`
+> **Default: `False`**
+
+Keeps a copy of the original graph before a resync. Used in conjunction with `verify_graph` to test and debug graph desyncs.
+
+Original graph is saved as `ctx.old_graph`.
+
+
+This is an internal debug flag.
+
+
+## Flag: `method_usages`
+> **Default: `True`**
+
+Enables and disables resolving method usages.
+
+**Example Codebase:**
+```python
+class Foo:
+ def bar():
+ ...
+
+obj = Foo()
+obj.bar() # Method Usage
+```
+
+**Codemod with `method_usages` on:**
+```python
+bar_func = codebase.get_class("Foo").get_method("bar")
+len(bar_func.usages) # 1
+bar_func.usages # [obj.bar()]
+```
+
+**Codemod with `method_usages` off:**
+```python
+bar_func = codebase.get_class("Foo").get_method("bar")
+len(bar_func.usages) # 0
+bar_func.usages # []
+```
+
+Method usage resolution could be disabled for a marginal performance boost. However, it is generally recommended to leave it enabled.
+
+## Flag: `sync_enabled`
+> **Default: `False`**
+
+Enables or disables graph sync during `codebase.commit`.
+
+
+Implementation-specific details on sync graph can be found [here](https://github.com/codegen-sh/codegen/blob/develop/architecture/6.%20incremental-computation/C.%20Graph%20Recomputation.md).
+
+
+This section won't go into the specific details of sync graph, but the general idea is that enabling sync graph will update the Codebase object to whatever new changes were made.
+
+**Example with `sync_enabled` on:**
+```python
+file = codebase.get_file(...)
+file.insert_after("foobar = 1")
+codebase.commit()
+
+foobar = codebase.get_symbol("foobar")
+assert foobar # foobar is available after commit / graph sync
+```
+
+**Example with `sync_enabled` disabled:**
+```python
+file = codebase.get_file(...)
+file.insert_after("foobar = 1")
+
+foobar = codebase.get_symbol("foobar", optional=True)
+assert not foobar # foobar is not available after commit
+```
+
+
+Enabling sync graph will have a performance impact on codebase commit, but will also unlock a bunch of operations that were previously not possible.
+
+
+## Flag: `full_range_index`
+> **Default: `False`**
+
+By default, Codebase maintains an internal range-to-node index for fast lookups. (i.e. `bytes 120 to 130 maps to node X`).
+For optimization purposes, this only applies to nodes defined and handled by `parser.py`.
+
+Enabling `full_range_index` will create an additional index that maps **all** tree-sitter ranges to nodes.
+This can be useful for debugging or when you need to build any applications that require a full range-to-node index (i.e. a codebase tree lookup).
+
+
+This flag **significantly** increases memory usage!
+
+
+## Flag: `ignore_process_errors`
+> **Default: `True`**
+
+Controls whether to ignore errors that occur during external process execution (such as dependency manager or language engine).
+
+Disabling `ignore_process_errors` would make Codegen fail on errors that would otherwise be logged then ignored.
+
+## Flag: `disable_graph`
+> **Default: `False`**
+
+Disables the graph construction process. Any operations that require the graph will no longer work. (In other words, this turns off import resolution and usage/dependency resolution)
+
+Functions that operate purely on AST such as getting and editing parameters or modifying function and class definitions will still work.
+
+
+For codemods that do not require the graph (aka only AST/Syntax-level changes), **disabling graph parse could yield a 30%-40% decrease in parse time and memory usage**!
+
+
+## Flag: `disable_file_parse`
+> **Default: `False`**
+
+Disables **ALL** parsing, including file and graph parsing. This essentially treats all codebases as the "UNSUPPORTED" language mode.
+
+Nearly all functions except for editing primitives like `codebase.get_file` and `file.edit` will no longer work.
+
+
+This flag is useful for any usages of Codegen that do **NOT** require any AST/CST/Graph parsing. (i.e. using Codegen purely as a file editing harness)
+
+If this is your use case, this **could decrease parse and memory usage by 95%.**
+
+
+## Flag: `exp_lazy_graph`
+> **Default: `False`**
+
+This experimental flag pushes the graph creation back until the graph is needed. This is an experimental feature and may have some unintended consequences.
+
+**Example Codemod:**
+```python
+from codegen import Codebase
+from codegen.configs import CodebaseConfig
+
+# Enable lazy graph parsing
+codebase = Codebase("", config=CodebaseConfig(exp_lazy_graph=True))
+
+# The codebase object will be created immediately with no parsing done
+# These all do not require graph parsing
+codebase.files
+codebase.directories
+codebase.get_file("...")
+
+# These do require graph parsing, and will create the graph only if called
+codebase.get_function("...")
+codebase.get_class("...")
+codebase.imports
+```
+
+
+This may have a very slight performance boost. Use at your own risk!
+
+
+## Flag: `generics`
+> **Default: `True`**
+
+Enables and disables generic type resolution.
+
+**Example Codebase:**
+```python
+class Point:
+ def scale(cls, n: int):
+ pass
+
+class List[T]():
+ def pop(self) -> T:
+ ...
+
+l: List[Point] = []
+l.pop().scale(1) # Generic Usage
+```
+
+**Codemod with `generics` on:**
+```python
+bar_func = codebase.get_class("Point").get_method("scale")
+len(bar_func.usages) # 1
+bar_func.usages # [l.pop().scale(1)]
+```
+
+**Codemod with `generics` off:**
+```python
+bar_func = codebase.get_class("Point").get_method("scale")
+len(bar_func.usages) # 0
+bar_func.usages # []
+```
+
+
+Generic resolution is still largely WIP and experimental, and may not work in all cases. In some rare circumstances, disabling generics may result in a significant performance boost.
+
+
+## Flag: `import_resolution_paths`
+> **Default: `[]`**
+
+Controls alternative paths to resolve imports from.
+
+**Example Codebase:**
+```python
+# a/b/c/src.py
+def update():
+ pass
+
+# consumer.py
+from c import src as operations
+
+operations.update()
+```
+
+**Codemod:**
+```python
+codebase.ctx.config.import_resolution_paths = ["a/b"]
+```
+
+## Flag: `import_resolution_overrides`
+> **Default: `{}`**
+
+Controls import path overrides during import resolution.
+
+**Example**
+`from a.b.c import d` with the override `a/b` -> `foo/bar` will internally resolve the import as `from foo.bar.c import d`.
+
+## Flag: `py_resolve_syspath`
+> **Default: `False`**
+
+Enables and disables resolution of imports from `sys.path`.
+
+## Flag: `ts_dependency_manager`
+> **Default: `False`**
+
+
+**This is an internal flag used for Codegen Cloud and should not be used externally!**
+
+This flag **WILL** nuke any existing `node_modules` folder!
+
+
+
+This flag also assumes many constants for Codegen Cloud. Very likely this will not work if run locally.
+
+Instead, just install `node_modules` as normal (either through `npm`, `pnpm`, or `yarn`) and skip this setting!
+
+
+Enables Codegen's internal dependency installer for TypeScript. This will modify `package.json` and install the bare minimum set of installable dependencies.
+
+
+More documentation on TypeScript dependency manager can be found [here](https://github.com/codegen-sh/codegen/blob/develop/architecture/external/dependency-manager.md)
+
+
+## Flag: `ts_language_engine`
+> **Default: `False`**
+
+
+This feature was built primarily with Codegen Cloud in mind. As such, this assumes a valid NodeJS and TypeScript environment.
+
+
+Enables using the TypeScript compiler to extract information from the codebase. Enables commands such as `inferred_return_type`.
+
+
+This will increase memory usage and parsing time. Larger repos may even hit resource constraints with the bundled TypeScript compiler integration.
+
+
+## Flag: `v8_ts_engine`
+> **Default: `False`**
+
+
+This feature flag requires `ts_language_engine` to be enabled as well.
+
+
+Enables using the **V8-based TypeScript compiler** to extract information from the codebase. Enables commands such as `inferred_return_type`.
+
+The V8 implementation (as opposed to the default external-process based implementation) is less stable, but provides the entire TypeScript API to be used from within Codegen.
+
+
+This will increase memory usage and parsing time. Larger repos may even hit resource constraints with the V8-based TypeScript compiler integration.
+
+
+## Flag: `unpacking_assignment_partial_removal`
+> **Default: `False`**
+
+Enables smarter removal of unpacking assignments.
+
+**Example Codebase:**
+```python
+a, b, c = (1, 2, 3)
+```
+
+**Codemod with `unpacking_assignment_partial_removal` on:**
+```python
+file = codebase.get_file(...)
+b = file.get_symbol("b")
+b.remove()
+codebase.commit()
+
+file.symbols # [a, c]
+file.source # "a, c = (1, 3)"
+```
+
+**Codemod with `unpacking_assignment_partial_removal` off:**
+```python
+file = codebase.get_file(...)
+b = file.get_symbol("b")
+b.remove()
+codebase.commit()
+
+file.symbols # []
+file.source # ""
+```
diff --git a/docs/introduction/getting-started.mdx b/docs/introduction/getting-started.mdx
index 50fd04e4d..ad9e2c5f2 100644
--- a/docs/introduction/getting-started.mdx
+++ b/docs/introduction/getting-started.mdx
@@ -276,6 +276,39 @@ if base_class:
references](/building-with-codegen/dependencies-and-usages) or [imports](/building-with-codegen/imports) and [exports](/building-with-codegen/exports).
+## Advanced Settings
+
+Codegen also supports a number of advanced settings that can be used to customize the behavior of the graph construction process.
+
+These flags are helpful for debugging problematic repos, optimizing Codegen’s performance, or testing unreleased or experimental (potentially backwards-breaking) features.
+
+```python
+from codegen import Codebase
+from codegen.configs import CodebaseConfig
+
+# Initialize a Codebase with custom configuration
+codebase = Codebase(
+ "path/to/git/repo"",
+ config=CodebaseConfig(
+ verify_graph=True,
+ method_usages=False,
+ sync_enabled=True,
+ generics=False,
+ import_resolution_overrides={
+ "old_module": "new_module"
+ },
+ ts_language_engine=True,
+ v8_ts_engine=True
+ )
+)
+```
+
+To learn more about available settings, see the [Advanced Settings](/introduction/advanced-settings) page.
+
+
+These are considered experimental and unstable features that may be removed or changed in the future.
+
+
## What's Next?
diff --git a/docs/mint.json b/docs/mint.json
index d5062557c..5a33f2590 100644
--- a/docs/mint.json
+++ b/docs/mint.json
@@ -72,6 +72,7 @@
"introduction/ide-usage",
"introduction/work-with-ai",
"introduction/how-it-works",
+ "introduction/advanced-settings",
"introduction/guiding-principles",
"introduction/community",
"introduction/about",
@@ -167,6 +168,7 @@
"group": "Blog",
"pages": [
"blog/posts",
+ "blog/devin",
"blog/act-via-code",
"blog/promise-to-async-await-twilio",
"blog/fixing-import-loops"
diff --git a/docs/tutorials/at-a-glance.mdx b/docs/tutorials/at-a-glance.mdx
index 1bdd1ce11..87c8f467f 100644
--- a/docs/tutorials/at-a-glance.mdx
+++ b/docs/tutorials/at-a-glance.mdx
@@ -53,7 +53,7 @@ Explore our tutorials to learn how to use Codegen for various code transformatio
Update SQLAlchemy code to use the new 2.0-style query interface and patterns.
diff --git a/docs/tutorials/github-review-bot.mdx b/docs/tutorials/github-review-bot.mdx
index ab8b0ad8f..9b9a669fd 100644
--- a/docs/tutorials/github-review-bot.mdx
+++ b/docs/tutorials/github-review-bot.mdx
@@ -186,37 +186,4 @@ While this example demonstrates a basic PR review bot, you can extend it to:
- Add automatic fix suggestions
- ... etc.
-Check out our [Code Agent tutorial](/tutorials/build-code-agent) to learn more about building sophisticated AI agents with Codegen
-
-## Learn More
-
-
-
- Learn how to build intelligent code agents with Codegen.
-
-
- Explore Codegen's GitHub integration features.
-
-
- Learn about deploying apps with Modal.
-
-
- Understand code review patterns and best practices.
-
-
\ No newline at end of file
+Check out our [Code Agent tutorial](/tutorials/build-code-agent) to learn more about building sophisticated AI agents with Codegen
\ No newline at end of file
diff --git a/docs/tutorials/promise-to-async-await.mdx b/docs/tutorials/promise-to-async-await.mdx
index 9e30cf3c4..2811ee2ae 100644
--- a/docs/tutorials/promise-to-async-await.mdx
+++ b/docs/tutorials/promise-to-async-await.mdx
@@ -96,7 +96,7 @@ new_code = promise_statement.edit(
- Ambiguous/conditional return blocks
-A list of all the covered cases can be found in the [example notebook](codegen-examples/examples/promises_to_async_await/promise_to_async_await.ipynb).
+A list of all the covered cases can be found in the [example notebook](https://github.com/codegen-sh/codegen-sdk/tree/codegen-examples/examples/promises_to_async_await/promise_to_async_await.ipynb).
diff --git a/pyproject.toml b/pyproject.toml
index e2a7470d1..3f30ba581 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,10 +6,11 @@ readme = "README.md"
# renovate: datasource=python-version depName=python
requires-python = ">=3.12, <3.14"
dependencies = [
- "openai==1.65.2",
+ "openai==1.65.5",
"tiktoken<1.0.0,>=0.5.1",
"tabulate>=0.9.0,<1.0.0",
"codeowners<1.0.0,>=0.6.0",
+ "anthropic",
"dataclasses-json<1.0.0,>=0.6.4",
"dicttoxml<2.0.0,>=1.7.16",
"xmltodict<1.0.0,>=0.13.0",
@@ -78,6 +79,7 @@ dependencies = [
"datasets",
"colorlog>=6.9.0",
"langsmith",
+ "langchain-xai>=0.2.1",
]
license = { text = "Apache-2.0" }
diff --git a/src/codegen/agents/chat_agent.py b/src/codegen/agents/chat_agent.py
index 2ecae36fb..24ecada26 100644
--- a/src/codegen/agents/chat_agent.py
+++ b/src/codegen/agents/chat_agent.py
@@ -44,7 +44,7 @@ def run(self, prompt: str, thread_id: Optional[str] = None) -> str:
if thread_id is None:
thread_id = str(uuid4())
- input = {"messages": [("user", prompt)]}
+ input = {"query": prompt}
stream = self.agent.stream(input, config={"configurable": {"thread_id": thread_id}}, stream_mode="values")
for s in stream:
@@ -57,7 +57,7 @@ def run(self, prompt: str, thread_id: Optional[str] = None) -> str:
else:
message.pretty_print()
- return s["messages"][-1].content
+ return s["final_answer"]
def chat(self, prompt: str, thread_id: Optional[str] = None) -> tuple[str, str]:
"""Chat with the agent, maintaining conversation history.
diff --git a/src/codegen/agents/code_agent.py b/src/codegen/agents/code_agent.py
index cb7be3ffa..99c01a874 100644
--- a/src/codegen/agents/code_agent.py
+++ b/src/codegen/agents/code_agent.py
@@ -3,11 +3,14 @@
from uuid import uuid4
from langchain.tools import BaseTool
-from langchain_core.messages import AIMessage
+from langchain_core.messages import AIMessage, HumanMessage
+from langchain_core.runnables.config import RunnableConfig
from langsmith import Client
from codegen.extensions.langchain.agent import create_codebase_agent
-from codegen.extensions.langchain.utils.get_langsmith_url import find_and_print_langsmith_run_url
+from codegen.extensions.langchain.utils.get_langsmith_url import (
+ find_and_print_langsmith_run_url,
+)
if TYPE_CHECKING:
from codegen import Codebase
@@ -16,7 +19,24 @@
class CodeAgent:
"""Agent for interacting with a codebase."""
- def __init__(self, codebase: "Codebase", model_provider: str = "anthropic", model_name: str = "claude-3-5-sonnet-latest", memory: bool = True, tools: Optional[list[BaseTool]] = None, **kwargs):
+ codebase: "Codebase"
+ agent: any
+ langsmith_client: Client
+ project_name: str
+ thread_id: str | None = None
+ config: dict = {}
+
+ def __init__(
+ self,
+ codebase: "Codebase",
+ model_provider: str = "anthropic",
+ model_name: str = "claude-3-7-sonnet-latest",
+ memory: bool = True,
+ tools: Optional[list[BaseTool]] = None,
+ tags: Optional[list[str]] = [],
+ metadata: Optional[dict] = {},
+ **kwargs,
+ ):
"""Initialize a CodeAgent.
Args:
@@ -25,6 +45,8 @@ def __init__(self, codebase: "Codebase", model_provider: str = "anthropic", mode
model_name: Name of the model to use
memory: Whether to let LLM keep track of the conversation history
tools: Additional tools to use
+ tags: Tags to add to the agent trace. Must be of the same type.
+ metadata: Metadata to use for the agent. Must be a dictionary.
**kwargs: Additional LLM configuration options. Supported options:
- temperature: Temperature parameter (0-1)
- top_p: Top-p sampling parameter (0-1)
@@ -32,13 +54,31 @@ def __init__(self, codebase: "Codebase", model_provider: str = "anthropic", mode
- max_tokens: Maximum number of tokens to generate
"""
self.codebase = codebase
- self.agent = create_codebase_agent(self.codebase, model_provider=model_provider, model_name=model_name, memory=memory, additional_tools=tools, **kwargs)
+ self.agent = create_codebase_agent(
+ self.codebase,
+ model_provider=model_provider,
+ model_name=model_name,
+ memory=memory,
+ additional_tools=tools,
+ **kwargs,
+ )
+ self.model_name = model_name
self.langsmith_client = Client()
# Get project name from environment variable or use a default
self.project_name = os.environ.get("LANGCHAIN_PROJECT", "RELACE")
print(f"Using LangSmith project: {self.project_name}")
+ # Initialize tags for agent trace
+ self.tags = [*tags, self.model_name]
+
+ # Initialize metadata for agent trace
+ self.metadata = {
+ "project": self.project_name,
+ "model": self.model_name,
+ **metadata,
+ }
+
def run(self, prompt: str, thread_id: Optional[str] = None) -> str:
"""Run the agent with a prompt.
@@ -51,19 +91,32 @@ def run(self, prompt: str, thread_id: Optional[str] = None) -> str:
"""
if thread_id is None:
thread_id = str(uuid4())
+ self.thread_id = thread_id
+ self.config = {
+ "configurable": {
+ "thread_id": thread_id,
+ "metadata": {"project": self.project_name},
+ },
+ "recursion_limit": 100,
+ }
# this message has a reducer which appends the current message to the existing history
# see more https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers
- input = {"messages": [("user", prompt)]}
+ input = {"query": prompt}
+ config = RunnableConfig(configurable={"thread_id": thread_id}, tags=self.tags, metadata=self.metadata, recursion_limit=100)
# we stream the steps instead of invoke because it allows us to access intermediate nodes
- stream = self.agent.stream(input, config={"configurable": {"thread_id": thread_id, "metadata": {"project": self.project_name}}, "recursion_limit": 100}, stream_mode="values")
+ stream = self.agent.stream(input, config=config, stream_mode="values")
# Keep track of run IDs from the stream
run_ids = []
for s in stream:
- message = s["messages"][-1]
+ if len(s["messages"]) == 0:
+ message = HumanMessage(content=prompt)
+ else:
+ message = s["messages"][-1]
+
if isinstance(message, tuple):
print(message)
else:
@@ -77,7 +130,7 @@ def run(self, prompt: str, thread_id: Optional[str] = None) -> str:
run_ids.append(message.additional_kwargs["run_id"])
# Get the last message content
- result = s["messages"][-1].content
+ result = s["final_answer"]
# Try to find run IDs in the LangSmith client's recent runs
try:
@@ -110,3 +163,27 @@ def get_agent_trace_url(self) -> str | None:
print(traceback.format_exc())
print(separator)
return None
+
+ def get_tools(self) -> list[BaseTool]:
+ return list(self.agent.get_graph().nodes["tools"].data.tools_by_name.values())
+
+ def get_state(self) -> dict:
+ return self.agent.get_state(self.config)
+
+ def get_tags_metadata(self) -> tuple[list[str], dict]:
+ tags = [self.model_name]
+ metadata = {"project": self.project_name, "model": self.model_name}
+ # Add SWEBench run ID and instance ID to the metadata and tags for filtering
+ if self.run_id is not None:
+ metadata["swebench_run_id"] = self.run_id
+ tags.append(self.run_id)
+
+ if self.instance_id is not None:
+ metadata["swebench_instance_id"] = self.instance_id
+ tags.append(self.instance_id)
+
+ if self.difficulty is not None:
+ metadata["swebench_difficulty"] = self.difficulty
+ tags.append(f"difficulty_{self.difficulty}")
+
+ return tags, metadata
diff --git a/src/codegen/extensions/index/file_index.py b/src/codegen/extensions/index/file_index.py
index 6672221c4..a76e62d5e 100644
--- a/src/codegen/extensions/index/file_index.py
+++ b/src/codegen/extensions/index/file_index.py
@@ -2,7 +2,9 @@
import pickle
from pathlib import Path
+from typing import Optional
+import modal
import numpy as np
import tiktoken
from openai import OpenAI
@@ -26,6 +28,7 @@ class FileIndex(CodeIndex):
EMBEDDING_MODEL = "text-embedding-3-small"
MAX_TOKENS = 8000
BATCH_SIZE = 100
+ USE_MODAL_DICT = True # Flag to control whether to use Modal Dict
def __init__(self, codebase: Codebase):
"""Initialize the file index.
@@ -37,10 +40,87 @@ def __init__(self, codebase: Codebase):
self.client = OpenAI()
self.encoding = tiktoken.get_encoding("cl100k_base")
+ def set_use_modal_dict(self, use_modal: bool) -> None:
+ """Set whether to use Modal Dict for storage.
+
+ Args:
+ use_modal: Whether to use Modal Dict for storage
+ """
+ self.USE_MODAL_DICT = use_modal
+ logger.info(f"Modal Dict storage {'enabled' if use_modal else 'disabled'}")
+
@property
def save_file_name(self) -> str:
return "file_index_{commit}.pkl"
+ @property
+ def modal_dict_id(self) -> str:
+ """Get the Modal Dict ID based on the same naming convention as the pickle file."""
+ if not self.commit_hash:
+ return "file_index_latest"
+ return f"file_index_{self.commit_hash}"
+
+ def delete_modal_dict(self) -> bool:
+ """Delete the Modal Dict storage for this index.
+
+ Returns:
+ bool: True if successfully deleted, False otherwise
+ """
+ if not self.USE_MODAL_DICT:
+ logger.warning("Modal Dict storage is disabled")
+ return False
+
+ try:
+ dict_id = self.modal_dict_id
+ logger.info(f"Deleting Modal Dict: {dict_id}")
+
+ # Check if the dict exists before trying to delete
+ try:
+ # Use modal.Dict.delete to properly delete the dict
+ modal.Dict.delete(dict_id)
+ logger.info(f"Successfully deleted Modal Dict: {dict_id}")
+ return True
+ except Exception as e:
+ logger.info(f"Modal Dict {dict_id} does not exist or cannot be deleted: {e}")
+ return False
+ except Exception as e:
+ logger.exception(f"Failed to delete Modal Dict: {e}")
+ return False
+
+ def modal_dict_exists(self, commit_hash: Optional[str] = None) -> bool:
+ """Check if a Modal Dict exists for a specific commit.
+
+ Args:
+ commit_hash: The commit hash to check, or None to use the current commit
+
+ Returns:
+ bool: True if the Modal Dict exists, False otherwise
+ """
+ if not self.USE_MODAL_DICT:
+ return False
+
+ try:
+ # Use provided commit hash or current one
+ old_commit = self.commit_hash
+ if commit_hash is not None:
+ self.commit_hash = commit_hash
+
+ dict_id = self.modal_dict_id
+
+ # Restore original commit hash
+ if commit_hash is not None:
+ self.commit_hash = old_commit
+
+ try:
+ # Try to access the dict - this will raise an exception if it doesn't exist
+ modal_dict = modal.Dict.from_name(dict_id, create_if_missing=False)
+ # Check if our data is in the dict
+ return "index_data" in modal_dict
+ except Exception:
+ return False
+ except Exception:
+ return False
+
def _split_by_tokens(self, text: str) -> list[str]:
"""Split text into chunks that fit within token limit."""
tokens = self.encoding.encode(text)
@@ -135,17 +215,69 @@ def _get_changed_items(self) -> set[File]:
return changed_files
def _save_index(self, path: Path) -> None:
- """Save index data to disk."""
+ """Save index data to disk and optionally to Modal Dict."""
+ # Save to local pickle file
with open(path, "wb") as f:
pickle.dump({"E": self.E, "items": self.items, "commit_hash": self.commit_hash}, f)
+ # Save to Modal Dict if enabled
+ if self.USE_MODAL_DICT:
+ try:
+ dict_id = self.modal_dict_id
+ logger.info(f"Saving index to Modal Dict: {dict_id}")
+
+ # Convert numpy arrays to lists for JSON serialization
+ modal_data = {"E": self.E.tolist() if self.E is not None else None, "items": self.items.tolist() if self.items is not None else None, "commit_hash": self.commit_hash}
+
+ # Create or update Modal Dict
+ # Note: from_name is lazy, so we need to explicitly set the data
+ modal_dict = modal.Dict.from_name(dict_id, create_if_missing=True)
+ modal_dict["index_data"] = modal_data
+
+ logger.info(f"Successfully saved index to Modal Dict: {dict_id}")
+ except Exception as e:
+ logger.exception(f"Failed to save index to Modal Dict: {e}")
+
def _load_index(self, path: Path) -> None:
- """Load index data from disk."""
- with open(path, "rb") as f:
- data = pickle.load(f)
- self.E = data["E"]
- self.items = data["items"]
- self.commit_hash = data["commit_hash"]
+ """Load index data from disk or Modal Dict."""
+ # Try loading from Modal Dict first if enabled
+ if self.USE_MODAL_DICT:
+ try:
+ dict_id = self.modal_dict_id
+ logger.info(f"Attempting to load index from Modal Dict: {dict_id}")
+
+ # from_name is lazy, so we need to check if the dict exists first
+ try:
+ modal_dict = modal.Dict.from_name(dict_id, create_if_missing=False)
+ # Check if the dict contains our data
+ if "index_data" in modal_dict:
+ data = modal_dict["index_data"]
+
+ # Convert lists back to numpy arrays
+ self.E = np.array(data["E"]) if data["E"] is not None else None
+ self.items = np.array(data["items"]) if data["items"] is not None else None
+ self.commit_hash = data["commit_hash"]
+
+ logger.info(f"Successfully loaded index from Modal Dict: {dict_id}")
+ return
+ else:
+ logger.info(f"No index data found in Modal Dict: {dict_id}")
+ except Exception as e:
+ logger.warning(f"Modal Dict {dict_id} not found or error accessing it: {e}")
+ except Exception as e:
+ logger.warning(f"Failed to load index from Modal Dict, falling back to local file: {e}")
+
+ # Fall back to loading from local file
+ try:
+ with open(path, "rb") as f:
+ data = pickle.load(f)
+ self.E = data["E"]
+ self.items = data["items"]
+ self.commit_hash = data["commit_hash"]
+ logger.info(f"Loaded index from local file: {path}")
+ except Exception as e:
+ logger.exception(f"Failed to load index from local file: {e}")
+ raise
def similarity_search(self, query: str, k: int = 5) -> list[tuple[File, float]]:
"""Find the k most similar files to a query.
@@ -216,3 +348,20 @@ def update(self) -> None:
# Update commit hash
self.commit_hash = self._get_current_commit()
+
+ # Save updated index to Modal Dict if enabled
+ if self.USE_MODAL_DICT and (num_updated > 0 or num_added > 0):
+ try:
+ dict_id = self.modal_dict_id
+ logger.info(f"Updating index in Modal Dict: {dict_id}")
+
+ # Convert numpy arrays to lists for JSON serialization
+ modal_data = {"E": self.E.tolist() if self.E is not None else None, "items": self.items.tolist() if self.items is not None else None, "commit_hash": self.commit_hash}
+
+ # Create or update Modal Dict
+ modal_dict = modal.Dict.from_name(dict_id, create_if_missing=True)
+ modal_dict["index_data"] = modal_data
+
+ logger.info(f"Successfully updated index in Modal Dict: {dict_id}")
+ except Exception as e:
+ logger.exception(f"Failed to update index in Modal Dict: {e}")
diff --git a/src/codegen/extensions/langchain/agent.py b/src/codegen/extensions/langchain/agent.py
index d834b7b6a..fe44594b1 100644
--- a/src/codegen/extensions/langchain/agent.py
+++ b/src/codegen/extensions/langchain/agent.py
@@ -6,11 +6,10 @@
from langchain_core.messages import SystemMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph.graph import CompiledGraph
-from langgraph.prebuilt import create_react_agent
-from .llm import LLM
-from .prompts import REASONER_SYSTEM_MESSAGE
-from .tools import (
+from codegen.extensions.langchain.llm import LLM
+from codegen.extensions.langchain.prompts import REASONER_SYSTEM_MESSAGE
+from codegen.extensions.langchain.tools import (
CreateFileTool,
DeleteFileTool,
ListDirectoryTool,
@@ -25,6 +24,8 @@
ViewFileTool,
)
+from .graph import create_react_agent
+
if TYPE_CHECKING:
from codegen import Codebase
@@ -67,8 +68,8 @@ def create_codebase_agent(
CreateFileTool(codebase),
DeleteFileTool(codebase),
RenameFileTool(codebase),
- MoveSymbolTool(codebase),
- RevealSymbolTool(codebase),
+ # MoveSymbolTool(codebase),
+ # RevealSymbolTool(codebase),
# SemanticEditTool(codebase),
ReplacementEditTool(codebase),
RelaceEditTool(codebase),
@@ -88,7 +89,7 @@ def create_codebase_agent(
memory = MemorySaver() if memory else None
- return create_react_agent(model=llm, tools=tools, prompt=system_message, checkpointer=memory, debug=debug)
+ return create_react_agent(model=llm, tools=tools, system_message=system_message, checkpointer=memory, debug=debug)
def create_chat_agent(
@@ -137,7 +138,7 @@ def create_chat_agent(
memory = MemorySaver() if memory else None
- return create_react_agent(model=llm, tools=tools, prompt=system_message, checkpointer=memory, debug=debug)
+ return create_react_agent(model=llm, tools=tools, system_message=system_message, checkpointer=memory, debug=debug)
def create_codebase_inspector_agent(
@@ -174,7 +175,7 @@ def create_codebase_inspector_agent(
]
memory = MemorySaver() if memory else None
- return create_react_agent(model=llm, tools=tools, prompt=system_message, checkpointer=memory, debug=debug)
+ return create_react_agent(model=llm, tools=tools, system_message=system_message, checkpointer=memory, debug=debug)
def create_agent_with_tools(
@@ -208,4 +209,4 @@ def create_agent_with_tools(
memory = MemorySaver() if memory else None
- return create_react_agent(model=llm, tools=tools, prompt=system_message, checkpointer=memory, debug=debug)
+ return create_react_agent(model=llm, tools=tools, system_message=system_message, checkpointer=memory, debug=debug)
diff --git a/src/codegen/extensions/langchain/graph.py b/src/codegen/extensions/langchain/graph.py
new file mode 100644
index 000000000..e5116630f
--- /dev/null
+++ b/src/codegen/extensions/langchain/graph.py
@@ -0,0 +1,102 @@
+"""Demo implementation of an agent with Codegen tools."""
+
+from typing import TYPE_CHECKING, Annotated, Any, Literal, Optional
+
+import anthropic
+import openai
+from langchain.tools import BaseTool
+from langchain_core.messages import AIMessage, AnyMessage, HumanMessage, SystemMessage
+from langgraph.checkpoint.memory import MemorySaver
+from langgraph.graph import END, START
+from langgraph.graph.message import add_messages
+from langgraph.graph.state import CompiledGraph, StateGraph
+from langgraph.prebuilt import ToolNode
+from langgraph.pregel import RetryPolicy
+
+
+class GraphState(dict[str, Any]):
+ """State of the graph."""
+
+ query: str
+ final_answer: str
+ messages: Annotated[list[AnyMessage], add_messages]
+
+
+class AgentGraph:
+ """Main graph class for the agent."""
+
+ def __init__(self, model: "LLM", tools: list[BaseTool], system_message: SystemMessage):
+ self.model = model.bind_tools(tools)
+ self.tools = tools
+ self.system_message = system_message
+
+ # =================================== NODES ====================================
+
+ # Reasoner node
+ def reasoner(self, state: GraphState) -> dict[str, Any]:
+ new_turn = len(state["messages"]) == 0 or isinstance(state["messages"][-1], AIMessage)
+ messages = state["messages"]
+ if new_turn:
+ query = state["query"]
+ messages.append(HumanMessage(content=query))
+
+ result = self.model.invoke([self.system_message, *messages])
+
+ if isinstance(result, AIMessage):
+ return {"messages": [*messages, result], "final_answer": result.content}
+
+ return {"messages": [*messages, result]}
+
+ # =================================== EDGE CONDITIONS ====================================
+ def should_continue(self, state: GraphState) -> Literal["tools", END]:
+ messages = state["messages"]
+ last_message = messages[-1]
+ if hasattr(last_message, "tool_calls") and last_message.tool_calls:
+ return "tools"
+ return END
+
+ # =================================== COMPILE GRAPH ====================================
+ def create(self, checkpointer: Optional[MemorySaver] = None, debug: bool = False) -> CompiledGraph:
+ """Create and compile the graph."""
+ builder = StateGraph(GraphState)
+
+ # the retry policy has an initial interval, a backoff factor, and a max interval of controlling the
+ # amount of time between retries
+ retry_policy = RetryPolicy(
+ retry_on=[anthropic.RateLimitError, openai.RateLimitError, anthropic.InternalServerError],
+ max_attempts=10,
+ initial_interval=30.0, # Start with 30 second wait
+ backoff_factor=2, # Double the wait time each retry
+ max_interval=1000.0, # Cap at 1000 second max wait
+ jitter=True,
+ )
+
+ # Add nodes
+ builder.add_node("reasoner", self.reasoner, retry=retry_policy)
+ builder.add_node("tools", ToolNode(self.tools), retry=retry_policy)
+
+ # Add edges
+ builder.add_edge(START, "reasoner")
+ builder.add_edge("tools", "reasoner")
+ builder.add_conditional_edges(
+ "reasoner",
+ self.should_continue,
+ )
+
+ return builder.compile(checkpointer=checkpointer, debug=debug)
+
+
+def create_react_agent(
+ model: "LLM",
+ tools: list[BaseTool],
+ system_message: SystemMessage,
+ checkpointer: Optional[MemorySaver] = None,
+ debug: bool = False,
+) -> CompiledGraph:
+ """Create a reactive agent graph."""
+ graph = AgentGraph(model, tools, system_message)
+ return graph.create(checkpointer=checkpointer, debug=debug)
+
+
+if TYPE_CHECKING:
+ from codegen.extensions.langchain.llm import LLM
diff --git a/src/codegen/extensions/langchain/llm.py b/src/codegen/extensions/langchain/llm.py
index 1aafce31c..54b9a91a2 100644
--- a/src/codegen/extensions/langchain/llm.py
+++ b/src/codegen/extensions/langchain/llm.py
@@ -13,6 +13,7 @@
from langchain_core.runnables import Runnable
from langchain_core.tools import BaseTool
from langchain_openai import ChatOpenAI
+from langchain_xai import ChatXAI
from pydantic import Field
@@ -76,6 +77,9 @@ def _get_model_kwargs(self) -> dict[str, Any]:
if self.model_provider == "anthropic":
return {**base_kwargs, "model": self.model_name}
+ elif self.model_provider == "xai":
+ xai_api_base = os.getenv("XAI_API_BASE", "https://api.x.ai/v1/")
+ return {**base_kwargs, "model": self.model_name, "xai_api_base": xai_api_base}
else: # openai
return {**base_kwargs, "model": self.model_name}
@@ -85,15 +89,21 @@ def _get_model(self) -> BaseChatModel:
if not os.getenv("ANTHROPIC_API_KEY"):
msg = "ANTHROPIC_API_KEY not found in environment. Please set it in your .env file or environment variables."
raise ValueError(msg)
- return ChatAnthropic(**self._get_model_kwargs())
+ return ChatAnthropic(**self._get_model_kwargs(), max_retries=10, timeout=1000)
elif self.model_provider == "openai":
if not os.getenv("OPENAI_API_KEY"):
msg = "OPENAI_API_KEY not found in environment. Please set it in your .env file or environment variables."
raise ValueError(msg)
- return ChatOpenAI(**self._get_model_kwargs())
+ return ChatOpenAI(**self._get_model_kwargs(), max_retries=10, timeout=1000)
- msg = f"Unknown model provider: {self.model_provider}. Must be one of: anthropic, openai"
+ elif self.model_provider == "xai":
+ if not os.getenv("XAI_API_KEY"):
+ msg = "XAI_API_KEY not found in environment. Please set it in your .env file or environment variables."
+ raise ValueError(msg)
+ return ChatXAI(**self._get_model_kwargs())
+
+ msg = f"Unknown model provider: {self.model_provider}. Must be one of: anthropic, openai, xai"
raise ValueError(msg)
def _generate(
diff --git a/src/codegen/extensions/langchain/tools.py b/src/codegen/extensions/langchain/tools.py
index f4fc68471..2ab5b0179 100644
--- a/src/codegen/extensions/langchain/tools.py
+++ b/src/codegen/extensions/langchain/tools.py
@@ -7,6 +7,8 @@
from codegen.extensions.linear.linear_client import LinearClient
from codegen.extensions.tools.bash import run_bash_command
+from codegen.extensions.tools.github.checkout_pr import checkout_pr
+from codegen.extensions.tools.github.view_pr_checks import view_pr_checks
from codegen.extensions.tools.linear.linear import (
linear_comment_on_issue_tool,
linear_create_issue_tool,
@@ -114,8 +116,8 @@ class SearchInput(BaseModel):
query: str = Field(
...,
- description="The search query to find in the codebase. When ripgrep is available, this will be passed as a ripgrep pattern. "
- "For regex searches, set use_regex=True. Ripgrep is the preferred method.",
+ description="""The search query to find in the codebase. When ripgrep is available, this will be passed as a ripgrep pattern. For regex searches, set use_regex=True.
+ Ripgrep is the preferred method.""",
)
target_directories: Optional[list[str]] = Field(default=None, description="Optional list of directories to search in")
file_extensions: Optional[list[str]] = Field(default=None, description="Optional list of file extensions to search (e.g. ['.py', '.ts'])")
@@ -151,7 +153,27 @@ class EditFileTool(BaseTool):
"""Tool for editing files."""
name: ClassVar[str] = "edit_file"
- description: ClassVar[str] = "Edit a file by replacing its entire content. This tool should only be used for replacing entire file contents."
+ description: ClassVar[str] = r"""
+Edit a file by replacing its entire content. This tool should only be used for replacing entire file contents.
+Input for searching the codebase.
+
+ This tool provides powerful text-based search capabilities across your codebase,
+ with support for both simple text matching and regular expressions. It uses ripgrep
+ when available for high-performance searches, falling back to Python's regex engine
+ when necessary.
+
+ Features:
+ - Plain text or regex pattern matching
+ - Directory and file type filtering
+ - Paginated results for large codebases
+ - Case-insensitive by default for simple text searches
+
+ Example queries:
+ 1. Simple text: "function calculateTotal" (matches exactly, case-insensitive)
+ 2. Regex: "def.*calculate.*\(.*\)" (with use_regex=True)
+ 3. File-specific: "TODO" with file_extensions=[".py", ".ts"]
+ 4. Directory-specific: "api" with target_directories=["src/backend"]
+ """
args_schema: ClassVar[type[BaseModel]] = EditFileInput
codebase: Codebase = Field(exclude=True)
@@ -454,6 +476,28 @@ def _run(self, title: str, body: str) -> str:
return result.render()
+class GithubSearchIssuesInput(BaseModel):
+ """Input for searching GitHub issues."""
+
+ query: str = Field(..., description="Search query string to find issues")
+
+
+class GithubSearchIssuesTool(BaseTool):
+ """Tool for searching GitHub issues."""
+
+ name: ClassVar[str] = "search_issues"
+ description: ClassVar[str] = "Search for GitHub issues/PRs using a query string from pygithub, e.g. 'is:pr is:open test_query'"
+ args_schema: ClassVar[type[BaseModel]] = GithubSearchIssuesInput
+ codebase: Codebase = Field(exclude=True)
+
+ def __init__(self, codebase: Codebase) -> None:
+ super().__init__(codebase=codebase)
+
+ def _run(self, query: str) -> str:
+ result = search(self.codebase, query)
+ return result.render()
+
+
class GithubViewPRInput(BaseModel):
"""Input for getting PR contents."""
@@ -476,6 +520,28 @@ def _run(self, pr_id: int) -> str:
return result.render()
+class GithubCheckoutPRInput(BaseModel):
+ """Input for checkout out a PR head branch."""
+
+ pr_number: int = Field(..., description="Number of the PR to checkout")
+
+
+class GithubCheckoutPRTool(BaseTool):
+ """Tool for checking out a PR head branch."""
+
+ name: ClassVar[str] = "checkout_pr"
+ description: ClassVar[str] = "Checkout out a PR head branch"
+ args_schema: ClassVar[type[BaseModel]] = GithubCheckoutPRInput
+ codebase: Codebase = Field(exclude=True)
+
+ def __init__(self, codebase: Codebase) -> None:
+ super().__init__(codebase=codebase)
+
+ def _run(self, pr_number: int) -> str:
+ result = checkout_pr(self.codebase, pr_number)
+ return result.render()
+
+
class GithubCreatePRCommentInput(BaseModel):
"""Input for creating a PR comment"""
@@ -541,6 +607,28 @@ def _run(
return result.render()
+class GithubViewPRCheckInput(BaseModel):
+ """Input for viewing PR checks"""
+
+ pr_number: int = Field(..., description="The PR number to view checks for")
+
+
+class GithubViewPRCheckTool(BaseTool):
+ """Tool for viewing PR checks."""
+
+ name: ClassVar[str] = "view_pr_checks"
+ description: ClassVar[str] = "View the check suites for a PR"
+ args_schema: ClassVar[type[BaseModel]] = GithubCreatePRReviewCommentInput
+ codebase: Codebase = Field(exclude=True)
+
+ def __init__(self, codebase: Codebase) -> None:
+ super().__init__(codebase=codebase)
+
+ def _run(self, pr_number: int) -> str:
+ result = view_pr_checks(self.codebase, pr_number=pr_number)
+ return result.render()
+
+
########################################################################################################################
# LINEAR
########################################################################################################################
@@ -741,7 +829,7 @@ def get_workspace_tools(codebase: Codebase) -> list["BaseTool"]:
RunBashCommandTool(), # Note: This tool doesn't need the codebase
SearchTool(codebase),
# SemanticEditTool(codebase),
- SemanticSearchTool(codebase),
+ # SemanticSearchTool(codebase),
ViewFileTool(codebase),
RelaceEditTool(codebase),
ReflectionTool(codebase),
@@ -750,6 +838,7 @@ def get_workspace_tools(codebase: Codebase) -> list["BaseTool"]:
GithubCreatePRCommentTool(codebase),
GithubCreatePRReviewCommentTool(codebase),
GithubViewPRTool(codebase),
+ GithubSearchIssuesTool(codebase),
# Linear
LinearGetIssueTool(codebase),
LinearGetIssueCommentsTool(codebase),
@@ -761,14 +850,46 @@ def get_workspace_tools(codebase: Codebase) -> list["BaseTool"]:
class ReplacementEditInput(BaseModel):
- """Input for regex-based replacement editing."""
+ """Input for replacement editing."""
- filepath: str = Field(..., description="Path to the file to edit")
- pattern: str = Field(..., description="Regex pattern to match")
- replacement: str = Field(..., description="Replacement text (can include regex groups)")
- start: int = Field(default=1, description="Starting line number (1-indexed, inclusive). Default is 1.")
- end: int = Field(default=-1, description="Ending line number (1-indexed, inclusive). Default is -1 (end of file).")
- count: Optional[int] = Field(default=None, description="Maximum number of replacements. Default is None (replace all).")
+ filepath: str = Field(
+ ...,
+ description=("Path to the file to edit relative to the workspace root. The file must exist and be a text file."),
+ )
+ pattern: str = Field(
+ ...,
+ description=(
+ "Regular expression pattern to match text that should be replaced. "
+ "Supports all Python regex syntax including capture groups (\\1, \\2, etc). "
+ "The pattern is compiled with re.MULTILINE flag by default."
+ ),
+ )
+ replacement: str = Field(
+ ...,
+ description=(
+ "Text to replace matched patterns with. Can reference regex capture groups using \\1, \\2, etc. If using regex groups in pattern, make sure to preserve them in replacement if needed."
+ ),
+ )
+ start: int = Field(
+ default=1,
+ description=("Starting line number (1-indexed, inclusive) to begin replacements from. Use this with 'end' to limit changes to a specific region. Default is 1 (start of file)."),
+ )
+ end: int = Field(
+ default=-1,
+ description=(
+ "Ending line number (1-indexed, inclusive) to stop replacements at. "
+ "Use -1 to indicate end of file. Use this with 'start' to limit changes to a specific region. "
+ "Default is -1 (end of file)."
+ ),
+ )
+ count: Optional[int] = Field(
+ default=None,
+ description=(
+ "Maximum number of replacements to make. "
+ "Use None to replace all occurrences (default), or specify a number to limit replacements. "
+ "Useful when you only want to replace the first N occurrences."
+ ),
+ )
class ReplacementEditTool(BaseTool):
diff --git a/src/codegen/extensions/slack/types.py b/src/codegen/extensions/slack/types.py
index 04d96e433..a7203c526 100644
--- a/src/codegen/extensions/slack/types.py
+++ b/src/codegen/extensions/slack/types.py
@@ -7,15 +7,19 @@ class RichTextElement(BaseModel):
type: str
user_id: str | None = None
text: str | None = None
+ style: dict | None = None
+ url: str | None = None
+ channel_id: str | None = None
class RichTextSection(BaseModel):
- type: Literal["rich_text_section"]
+ type: Literal["rich_text_section", "rich_text_list", "rich_text_quote", "rich_text_preformatted", "text", "channel", "user", "emoji", "link"]
elements: list[RichTextElement]
+ style: dict | str | None = None # Can be either a dict for rich text styling or a string for list styles (e.g. "bullet")
class Block(BaseModel):
- type: Literal["rich_text"]
+ type: Literal["rich_text", "section", "divider", "header", "context", "actions", "image"]
block_id: str
elements: list[RichTextSection]
diff --git a/src/codegen/extensions/swebench/enums.py b/src/codegen/extensions/swebench/enums.py
new file mode 100644
index 000000000..0cf3a484a
--- /dev/null
+++ b/src/codegen/extensions/swebench/enums.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class SWEBenchDataset(Enum):
+ LITE = "princeton-nlp/SWE-bench_Lite"
+ FULL = "princeton-nlp/SWE-bench"
+ VERIFIED = "princeton-nlp/SWE-bench-verified"
+
+
+class SWEBenchLiteSubset(Enum):
+ LITE_SMALL = "lite_small"
+ LITE_MEDIUM = "lite_medium"
+ LITE_LARGE = "lite_large"
diff --git a/src/codegen/extensions/swebench/harness.py b/src/codegen/extensions/swebench/harness.py
index 5f4055d9c..7eaacd5ad 100644
--- a/src/codegen/extensions/swebench/harness.py
+++ b/src/codegen/extensions/swebench/harness.py
@@ -49,7 +49,7 @@ def show_problems(dataset):
print(f"{inst}: {problem}")
-def run_agent_on_entry(entry: SweBenchExample, codebase: Codebase | None = None):
+def run_agent_on_entry(entry: SweBenchExample, model: str, codebase: Codebase | None = None, run_id: str | None = None):
"""Process one `entry` from SWE Bench using the LLM `models` at the
given `temperature`. Set `model_name_or_path` in the result json.
"""
@@ -70,7 +70,9 @@ def run_agent_on_entry(entry: SweBenchExample, codebase: Codebase | None = None)
)
codebase = Codebase.from_repo(repo_full_name=entry.repo, commit=base_commit, language="python", config=config) # check out the repo
- agent = CodeAgent(codebase=codebase)
+ metadata = {"run_id": run_id, "instance_id": instance_id, "difficulty": f"difficulty_{entry.difficulty}"}
+ tags = [str(value) for value in metadata.values()]
+ agent = CodeAgent(codebase=codebase, tags=tags, metadata=metadata)
pprint.pprint(instance_id)
pprint.pprint(gold_files)
diff --git a/src/codegen/extensions/swebench/report.py b/src/codegen/extensions/swebench/report.py
index a2b624bb5..f8100e36d 100755
--- a/src/codegen/extensions/swebench/report.py
+++ b/src/codegen/extensions/swebench/report.py
@@ -5,8 +5,8 @@
from collections import defaultdict
from pathlib import Path
+from codegen.extensions.swebench.enums import SWEBenchDataset
from codegen.extensions.swebench.tests import remove_patches_to_tests
-from codegen.extensions.swebench.utils import SWEBenchDataset
NUM_EVAL_PROCS = 5
@@ -113,6 +113,8 @@ def generate_report(predictions_dir: Path, logs_dir: Path, dataset: SWEBenchData
print(f"Directory does not exist: {predictions_dir}")
return 1
+ predictions_jsonl = predictions_dir / "all_preds.jsonl"
+ existing_preds = predictions_jsonl.exists()
prediction_files = list(predictions_dir.glob("*.json"))
print(f"Found {len(prediction_files)} prediction files")
@@ -126,29 +128,27 @@ def generate_report(predictions_dir: Path, logs_dir: Path, dataset: SWEBenchData
except json.JSONDecodeError:
print(f"Error reading JSON from {file_path}")
continue
+ if not existing_preds:
+ if not predictions:
+ print("No valid predictions found")
+ return 1
- print(f"Successfully loaded {len(predictions)} predictions")
+ print(f"Successfully loaded {len(predictions)} predictions")
- if predictions:
- # Create predictions JSONL file
predictions_jsonl = preds_to_jsonl(predictions, predictions_dir)
- print(f"\nCreated predictions JSONL: {predictions_jsonl}")
- # Setup log directory
- log_dir = logs_dir / "results"
- log_dir.mkdir(exist_ok=True, parents=True)
- print(f"Using log directory: {log_dir}")
+ # Setup log directory
+ log_dir = logs_dir / "results"
+ log_dir.mkdir(exist_ok=True, parents=True)
+ print(f"Using log directory: {log_dir}")
- # Run evaluations
- run_evals(predictions_jsonl, logs_dir, dataset, run_id)
+ # Run evaluations
+ run_evals(predictions_jsonl, logs_dir, dataset, run_id)
- # Get and display report
- report = get_report(predictions_jsonl, logs_dir)
+ # Get and display report
+ report = get_report(predictions_jsonl, logs_dir)
- # Update prediction JSONs with results
- predictions = update_pred_json(predictions, report, predictions_dir)
- else:
- print("No valid predictions found")
- return 1
+ # Update prediction JSONs with results
+ predictions = update_pred_json(predictions, report, predictions_dir)
return 0
diff --git a/src/codegen/extensions/swebench/subsets.py b/src/codegen/extensions/swebench/subsets.py
new file mode 100644
index 000000000..a2f522ffe
--- /dev/null
+++ b/src/codegen/extensions/swebench/subsets.py
@@ -0,0 +1,146 @@
+from codegen.extensions.swebench.enums import SWEBenchLiteSubset
+
+SMALL_LITE_SUBSET = [
+ "mwaskom__seaborn-2848",
+ "sphinx-doc__sphinx-8627",
+ "sphinx-doc__sphinx-7975",
+ "django__django-17087",
+ "sympy__sympy-17655",
+ "matplotlib__matplotlib-26020",
+ "sympy__sympy-20154",
+ "scikit-learn__scikit-learn-13439",
+ "pytest-dev__pytest-7373",
+ "django__django-16527",
+]
+
+MEDIUM_LITE_SUBSET = [
+ "sympy__sympy-15346",
+ "sympy__sympy-16281",
+ "sympy__sympy-22840",
+ "pytest-dev__pytest-7220",
+ "django__django-12284",
+ "pytest-dev__pytest-7490",
+ "matplotlib__matplotlib-25442",
+ "django__django-13757",
+ "django__django-15790",
+ "sympy__sympy-18532",
+ "sympy__sympy-13471",
+ "scikit-learn__scikit-learn-15535",
+ "django__django-13447",
+ "django__django-15789",
+ "scikit-learn__scikit-learn-14894",
+ "django__django-14238",
+ "django__django-10914",
+ "pytest-dev__pytest-11143",
+ "django__django-16255",
+ "django__django-13658",
+]
+
+LARGE_LITE_SUBSET = [
+ "pytest-dev__pytest-5495",
+ "django__django-11797",
+ "django__django-14730",
+ "scikit-learn__scikit-learn-25500",
+ "sphinx-doc__sphinx-8506",
+ "django__django-16408",
+ "django__django-16910",
+ "sympy__sympy-12236",
+ "matplotlib__matplotlib-24265",
+ "django__django-15320",
+ "matplotlib__matplotlib-25311",
+ "django__django-12125",
+ "django__django-12747",
+ "matplotlib__matplotlib-24334",
+ "scikit-learn__scikit-learn-14983",
+ "scikit-learn__scikit-learn-13497",
+ "django__django-14580",
+ "pylint-dev__pylint-6506",
+ "matplotlib__matplotlib-23987",
+ "scikit-learn__scikit-learn-13497",
+ "django__django-14017",
+ "django__django-15213",
+ "django__django-12284",
+ "pylint-dev__pylint-7114",
+ "django__django-11422",
+ "django__django-11620",
+ "django__django-12284",
+ "sympy__sympy-13971",
+ "django__django-12284",
+ "sphinx-doc__sphinx-7975",
+ "scikit-learn__scikit-learn-15512",
+ "scikit-learn__scikit-learn-15512",
+ "pylint-dev__pylint-7993",
+ "django__django-12184",
+ "django__django-13315",
+ "sympy__sympy-15609",
+ "pylint-dev__pylint-7993",
+ "sympy__sympy-17022",
+ "pylint-dev__pylint-7993",
+ "sympy__sympy-15678",
+ "sympy__sympy-18057",
+ "sympy__sympy-17655",
+ "sympy__sympy-17655",
+ "django__django-13028",
+ "sympy__sympy-17139",
+ "django__django-14999",
+ "django__django-15790",
+ "scikit-learn__scikit-learn-11281",
+ "astropy__astropy-12907",
+ "django__django-11815",
+ "sympy__sympy-18621",
+ "django__django-11999",
+ "sphinx-doc__sphinx-8721",
+ "matplotlib__matplotlib-23314",
+ "sphinx-doc__sphinx-8721",
+ "sympy__sympy-18621",
+ "django__django-12497",
+ "scikit-learn__scikit-learn-13584",
+ "matplotlib__matplotlib-24970",
+ "scikit-learn__scikit-learn-13584",
+ "django__django-12453",
+ "sympy__sympy-20154",
+ "django__django-13447",
+ "sphinx-doc__sphinx-8595",
+ "sympy__sympy-20154",
+ "sympy__sympy-20154",
+ "django__django-12700",
+ "psf__requests-2317",
+ "django__django-16046",
+ "sympy__sympy-20154",
+ "sympy__sympy-20212",
+ "django__django-13710",
+ "sympy__sympy-13647",
+ "django__django-15851",
+ "scikit-learn__scikit-learn-14894",
+ "sympy__sympy-24213",
+ "scikit-learn__scikit-learn-13779",
+ "django__django-13710",
+ "django__django-13933",
+ "sympy__sympy-20212",
+ "django__django-14855",
+ "django__django-11039",
+ "django__django-16379",
+ "pydata__xarray-5131",
+ "pytest-dev__pytest-7373",
+ "django__django-16139",
+ "django__django-14382",
+ "pytest-dev__pytest-5227",
+ "django__django-16595",
+ "django__django-16379",
+ "django__django-16527",
+ "django__django-13658",
+ "django__django-16255",
+ "django__django-16527",
+ "django__django-13658",
+ "django__django-13658",
+ "django__django-13658",
+ "django__django-11099",
+ "django__django-16527",
+ "django__django-11099",
+]
+
+LITE_SUBSETS = {
+ SWEBenchLiteSubset.LITE_SMALL: SMALL_LITE_SUBSET,
+ SWEBenchLiteSubset.LITE_MEDIUM: MEDIUM_LITE_SUBSET,
+ SWEBenchLiteSubset.LITE_LARGE: LARGE_LITE_SUBSET,
+}
diff --git a/src/codegen/extensions/swebench/success_rates.py b/src/codegen/extensions/swebench/success_rates.py
new file mode 100644
index 000000000..2d3cbbdf1
--- /dev/null
+++ b/src/codegen/extensions/swebench/success_rates.py
@@ -0,0 +1,302 @@
+LITE_SUCCESS_RATES = {
+ "pallets__flask-5063": 0.0,
+ "sphinx-doc__sphinx-8282": 0.0,
+ "django__django-14667": 0.0,
+ "sphinx-doc__sphinx-8474": 0.0,
+ "sympy__sympy-11400": 0.0,
+ "sympy__sympy-11870": 0.0,
+ "sympy__sympy-11897": 0.0,
+ "sympy__sympy-12171": 0.0,
+ "sympy__sympy-12236": 0.0,
+ "sympy__sympy-13146": 0.0,
+ "sympy__sympy-13773": 0.0,
+ "sympy__sympy-13895": 0.0,
+ "django__django-13220": 0.0,
+ "sympy__sympy-13915": 0.0,
+ "sympy__sympy-14024": 0.0,
+ "sympy__sympy-14308": 0.0,
+ "django__django-14730": 0.0,
+ "sphinx-doc__sphinx-7738": 0.0,
+ "sphinx-doc__sphinx-7686": 0.0,
+ "django__django-14997": 0.0,
+ "matplotlib__matplotlib-25079": 0.0,
+ "pydata__xarray-4493": 0.0,
+ "matplotlib__matplotlib-22835": 0.0,
+ "matplotlib__matplotlib-18869": 0.0,
+ "pylint-dev__pylint-7228": 0.0,
+ "pytest-dev__pytest-5103": 0.0,
+ "pytest-dev__pytest-5221": 0.0,
+ "sympy__sympy-14317": 0.0,
+ "django__django-16820": 0.0,
+ "django__django-16229": 0.0,
+ "pytest-dev__pytest-9359": 0.0,
+ "scikit-learn__scikit-learn-10508": 0.0,
+ "scikit-learn__scikit-learn-10949": 0.0,
+ "scikit-learn__scikit-learn-11040": 0.0,
+ "django__django-15695": 0.0,
+ "scikit-learn__scikit-learn-25638": 0.0,
+ "django__django-16816": 0.0,
+ "sympy__sympy-15308": 0.0,
+ "matplotlib__matplotlib-25433": 0.0,
+ "sympy__sympy-18087": 0.0,
+ "astropy__astropy-7746": 0.0,
+ "django__django-11630": 0.0,
+ "sympy__sympy-18199": 0.0,
+ "sympy__sympy-23191": 0.0,
+ "sympy__sympy-17630": 0.0,
+ "sympy__sympy-19254": 0.0,
+ "sympy__sympy-21627": 0.0,
+ "sympy__sympy-16281": 0.0,
+ "sympy__sympy-16106": 0.0,
+ "sympy__sympy-24102": 0.0,
+ "django__django-11905": 0.0,
+ "sympy__sympy-21171": 0.0,
+ "sympy__sympy-20639": 0.0,
+ "django__django-12589": 0.0,
+ "sympy__sympy-20322": 0.0,
+ "django__django-11564": 0.0,
+ "django__django-11019": 0.0,
+ "django__django-16910": 0.02,
+ "django__django-15252": 0.02,
+ "pytest-dev__pytest-5413": 0.02,
+ "django__django-11742": 0.02,
+ "sphinx-doc__sphinx-8273": 0.02,
+ "pytest-dev__pytest-8906": 0.02,
+ "django__django-15996": 0.02,
+ "sympy__sympy-19007": 0.02,
+ "django__django-11910": 0.02,
+ "matplotlib__matplotlib-22711": 0.02,
+ "django__django-13768": 0.02,
+ "astropy__astropy-14182": 0.02,
+ "mwaskom__seaborn-3407": 0.02,
+ "pallets__flask-4045": 0.02,
+ "django__django-12908": 0.02,
+ "pallets__flask-4992": 0.02,
+ "pydata__xarray-3364": 0.02,
+ "sympy__sympy-16503": 0.02,
+ "django__django-15738": 0.02,
+ "pydata__xarray-4248": 0.02,
+ "django__django-13265": 0.02,
+ "sympy__sympy-13177": 0.02,
+ "django__django-13448": 0.02,
+ "django__django-12113": 0.02,
+ "sympy__sympy-13043": 0.02,
+ "sympy__sympy-12454": 0.02,
+ "sympy__sympy-13437": 0.02,
+ "django__django-16408": 0.03,
+ "pytest-dev__pytest-6116": 0.03,
+ "pytest-dev__pytest-8365": 0.03,
+ "psf__requests-2148": 0.03,
+ "sympy__sympy-21612": 0.03,
+ "astropy__astropy-14365": 0.03,
+ "matplotlib__matplotlib-23299": 0.03,
+ "django__django-11283": 0.03,
+ "django__django-14155": 0.03,
+ "sphinx-doc__sphinx-8506": 0.03,
+ "django__django-11797": 0.03,
+ "sympy__sympy-18698": 0.03,
+ "django__django-15320": 0.03,
+ "sphinx-doc__sphinx-10451": 0.03,
+ "django__django-15388": 0.03,
+ "sympy__sympy-20049": 0.03,
+ "django__django-15781": 0.05,
+ "django__django-13321": 0.05,
+ "sympy__sympy-18835": 0.05,
+ "django__django-14534": 0.05,
+ "matplotlib__matplotlib-24265": 0.05,
+ "django__django-15202": 0.05,
+ "django__django-12856": 0.05,
+ "matplotlib__matplotlib-23476": 0.05,
+ "django__django-15061": 0.05,
+ "sphinx-doc__sphinx-11445": 0.06,
+ "django__django-12470": 0.06,
+ "django__django-16400": 0.06,
+ "sympy__sympy-15346": 0.06,
+ "pytest-dev__pytest-5495": 0.06,
+ "sphinx-doc__sphinx-8801": 0.08,
+ "matplotlib__matplotlib-23563": 0.08,
+ "sympy__sympy-21379": 0.08,
+ "django__django-15819": 0.08,
+ "mwaskom__seaborn-2848": 0.08,
+ "scikit-learn__scikit-learn-25500": 0.08,
+ "sympy__sympy-12419": 0.08,
+ "django__django-12308": 0.09,
+ "sympy__sympy-14396": 0.09,
+ "sympy__sympy-15345": 0.09,
+ "sympy__sympy-19487": 0.09,
+ "pytest-dev__pytest-7168": 0.09,
+ "scikit-learn__scikit-learn-25747": 0.09,
+ "matplotlib__matplotlib-25498": 0.11,
+ "sympy__sympy-22840": 0.11,
+ "sphinx-doc__sphinx-8627": 0.11,
+ "pydata__xarray-4094": 0.11,
+ "pytest-dev__pytest-7220": 0.11,
+ "django__django-12747": 0.11,
+ "sympy__sympy-13031": 0.12,
+ "django__django-13660": 0.12,
+ "scikit-learn__scikit-learn-14983": 0.12,
+ "sphinx-doc__sphinx-8435": 0.14,
+ "sympy__sympy-20590": 0.14,
+ "scikit-learn__scikit-learn-14087": 0.14,
+ "sympy__sympy-24909": 0.14,
+ "django__django-15400": 0.14,
+ "matplotlib__matplotlib-25311": 0.14,
+ "pylint-dev__pylint-6506": 0.15,
+ "django__django-12125": 0.15,
+ "matplotlib__matplotlib-24334": 0.15,
+ "scikit-learn__scikit-learn-13497": 0.17,
+ "sympy__sympy-16792": 0.17,
+ "django__django-14580": 0.17,
+ "pylint-dev__pylint-7080": 0.18,
+ "matplotlib__matplotlib-25332": 0.18,
+ "sympy__sympy-22005": 0.18,
+ "sympy__sympy-20442": 0.2,
+ "django__django-13551": 0.2,
+ "sympy__sympy-14817": 0.2,
+ "matplotlib__matplotlib-23987": 0.2,
+ "django__django-13033": 0.21,
+ "sphinx-doc__sphinx-7975": 0.21,
+ "django__django-13925": 0.23,
+ "sphinx-doc__sphinx-10325": 0.23,
+ "sympy__sympy-16988": 0.23,
+ "pytest-dev__pytest-7490": 0.24,
+ "django__django-15213": 0.24,
+ "django__django-12284": 0.24,
+ "pytest-dev__pytest-11148": 0.24,
+ "django__django-11964": 0.24,
+ "pylint-dev__pylint-7114": 0.26,
+ "django__django-11422": 0.26,
+ "django__django-14017": 0.27,
+ "django__django-15902": 0.27,
+ "django__django-10924": 0.27,
+ "django__django-13158": 0.29,
+ "django__django-11620": 0.29,
+ "sympy__sympy-13971": 0.29,
+ "django__django-15498": 0.3,
+ "django__django-12184": 0.3,
+ "django__django-13964": 0.3,
+ "psf__requests-1963": 0.3,
+ "matplotlib__matplotlib-25442": 0.3,
+ "django__django-13757": 0.32,
+ "scikit-learn__scikit-learn-15512": 0.32,
+ "sympy__sympy-21614": 0.33,
+ "sympy__sympy-15609": 0.33,
+ "matplotlib__matplotlib-23562": 0.33,
+ "django__django-13315": 0.33,
+ "django__django-11848": 0.35,
+ "django__django-17087": 0.35,
+ "matplotlib__matplotlib-26011": 0.36,
+ "sympy__sympy-21055": 0.36,
+ "sympy__sympy-17022": 0.36,
+ "pylint-dev__pylint-7993": 0.36,
+ "astropy__astropy-6938": 0.38,
+ "sympy__sympy-15678": 0.38,
+ "django__django-17051": 0.38,
+ "scikit-learn__scikit-learn-14092": 0.38,
+ "pylint-dev__pylint-5859": 0.39,
+ "django__django-14411": 0.39,
+ "django__django-11001": 0.41,
+ "astropy__astropy-12907": 0.41,
+ "sympy__sympy-18057": 0.42,
+ "sympy__sympy-23262": 0.44,
+ "sympy__sympy-18189": 0.44,
+ "sympy__sympy-17139": 0.45,
+ "django__django-15790": 0.45,
+ "django__django-14999": 0.45,
+ "sympy__sympy-18532": 0.47,
+ "scikit-learn__scikit-learn-11281": 0.47,
+ "django__django-12915": 0.47,
+ "sympy__sympy-12481": 0.47,
+ "sympy__sympy-24066": 0.48,
+ "django__django-11815": 0.48,
+ "django__django-13028": 0.48,
+ "sympy__sympy-17655": 0.48,
+ "django__django-12708": 0.48,
+ "matplotlib__matplotlib-24970": 0.5,
+ "mwaskom__seaborn-3190": 0.52,
+ "scikit-learn__scikit-learn-13142": 0.52,
+ "matplotlib__matplotlib-26020": 0.53,
+ "scikit-learn__scikit-learn-15535": 0.53,
+ "sympy__sympy-13471": 0.53,
+ "sympy__sympy-15011": 0.53,
+ "psf__requests-3362": 0.55,
+ "matplotlib__matplotlib-24149": 0.55,
+ "matplotlib__matplotlib-23314": 0.55,
+ "django__django-14608": 0.56,
+ "scikit-learn__scikit-learn-13241": 0.56,
+ "scikit-learn__scikit-learn-25570": 0.56,
+ "sympy__sympy-18621": 0.56,
+ "scikit-learn__scikit-learn-13584": 0.56,
+ "django__django-13401": 0.58,
+ "pytest-dev__pytest-5692": 0.58,
+ "django__django-14787": 0.58,
+ "django__django-15814": 0.58,
+ "sphinx-doc__sphinx-8721": 0.58,
+ "django__django-14016": 0.58,
+ "django__django-11999": 0.59,
+ "django__django-12497": 0.59,
+ "psf__requests-2674": 0.59,
+ "matplotlib__matplotlib-23913": 0.59,
+ "pytest-dev__pytest-7432": 0.59,
+ "django__django-11049": 0.59,
+ "sympy__sympy-22714": 0.62,
+ "scikit-learn__scikit-learn-12471": 0.62,
+ "psf__requests-863": 0.62,
+ "django__django-14672": 0.62,
+ "sympy__sympy-20154": 0.62,
+ "django__django-13590": 0.64,
+ "django__django-12700": 0.64,
+ "sphinx-doc__sphinx-8595": 0.64,
+ "django__django-15789": 0.65,
+ "django__django-12453": 0.68,
+ "django__django-13447": 0.68,
+ "psf__requests-2317": 0.7,
+ "django__django-11583": 0.7,
+ "django__django-16046": 0.7,
+ "django__django-14238": 0.71,
+ "django__django-15851": 0.71,
+ "django__django-13710": 0.73,
+ "sympy__sympy-21847": 0.73,
+ "sympy__sympy-23117": 0.73,
+ "django__django-12983": 0.73,
+ "scikit-learn__scikit-learn-13779": 0.74,
+ "sympy__sympy-13647": 0.74,
+ "django__django-16041": 0.74,
+ "scikit-learn__scikit-learn-10297": 0.74,
+ "django__django-15347": 0.74,
+ "scikit-learn__scikit-learn-13496": 0.74,
+ "sympy__sympy-20212": 0.76,
+ "scikit-learn__scikit-learn-13439": 0.76,
+ "django__django-13933": 0.76,
+ "django__django-12286": 0.76,
+ "django__django-13230": 0.77,
+ "astropy__astropy-14995": 0.77,
+ "django__django-11179": 0.77,
+ "sphinx-doc__sphinx-8713": 0.77,
+ "sympy__sympy-24213": 0.77,
+ "matplotlib__matplotlib-23964": 0.79,
+ "scikit-learn__scikit-learn-14894": 0.79,
+ "django__django-10914": 0.8,
+ "pydata__xarray-5131": 0.8,
+ "django__django-11039": 0.82,
+ "pytest-dev__pytest-7373": 0.82,
+ "django__django-14915": 0.82,
+ "django__django-16595": 0.83,
+ "pytest-dev__pytest-11143": 0.85,
+ "sympy__sympy-14774": 0.85,
+ "pytest-dev__pytest-5227": 0.85,
+ "django__django-16873": 0.85,
+ "django__django-16139": 0.85,
+ "mwaskom__seaborn-3010": 0.86,
+ "django__django-14382": 0.86,
+ "django__django-14752": 0.86,
+ "sympy__sympy-13480": 0.86,
+ "django__django-16379": 0.86,
+ "sympy__sympy-24152": 0.88,
+ "django__django-14855": 0.88,
+ "django__django-11133": 0.88,
+ "django__django-11099": 0.91,
+ "django__django-13658": 0.91,
+ "django__django-16255": 0.91,
+ "django__django-16527": 0.91,
+}
diff --git a/src/codegen/extensions/swebench/utils.py b/src/codegen/extensions/swebench/utils.py
index cd1ded36e..d977dce4e 100644
--- a/src/codegen/extensions/swebench/utils.py
+++ b/src/codegen/extensions/swebench/utils.py
@@ -1,17 +1,14 @@
import json
from dataclasses import dataclass
-from enum import Enum
from pathlib import Path
from pprint import pprint
from typing import Literal, Optional
from datasets import load_dataset
-
-class SWEBenchDataset(Enum):
- LITE = "princeton-nlp/SWE-bench_Lite"
- FULL = "princeton-nlp/SWE-bench"
- VERIFIED = "princeton-nlp/SWE-bench-verified"
+from codegen.extensions.swebench.enums import SWEBenchDataset, SWEBenchLiteSubset
+from codegen.extensions.swebench.subsets import LITE_SUBSETS
+from codegen.extensions.swebench.success_rates import LITE_SUCCESS_RATES
@dataclass
@@ -30,6 +27,7 @@ class SweBenchExample:
fail_to_pass: str
pass_to_pass: Optional[str]
environment_setup_commit: Optional[str]
+ difficulty: Optional[int]
def load_predictions(paths):
@@ -64,11 +62,16 @@ def load_predictions(paths):
return predictions
+def get_difficulty(instance_id: str) -> int | None:
+ if instance_id in LITE_SUCCESS_RATES:
+ return 10 - int(LITE_SUCCESS_RATES[instance_id] * 10)
+ return None
+
+
def get_swe_bench_examples(
- dataset: SWEBenchDataset = SWEBenchDataset.LITE,
+ dataset: SWEBenchDataset | SWEBenchLiteSubset = SWEBenchLiteSubset.LITE_SMALL,
split: Literal["train", "dev", "test"] = "test",
- offset: int = 0,
- length: int = 100,
+ length: int | None = None,
instance_id: str | None = None,
repo: str | None = None,
) -> list[SweBenchExample]:
@@ -87,31 +90,26 @@ def get_swe_bench_examples(
# Convert string dataset name to enum
# Load the dataset with caching enabled
- swe_bench_dataset = load_dataset(dataset.value, download_mode="reuse_dataset_if_exists")
+ instance_ids = []
+ if isinstance(dataset, SWEBenchLiteSubset):
+ swe_bench_dataset = load_dataset(SWEBenchDataset.LITE.value, download_mode="reuse_dataset_if_exists")
+ instance_ids = LITE_SUBSETS[dataset]
+ else:
+ swe_bench_dataset = load_dataset(dataset.value, download_mode="reuse_dataset_if_exists")
# Get the requested split
split_data = swe_bench_dataset[split]
- # Apply offset and length
- if instance_id or repo:
- offset = 0
- end_idx = len(split_data)
- else:
- end_idx = min(offset + length, len(split_data))
- if offset >= len(split_data):
- return []
-
- # Use the select method instead of slicing
- # This ensures we get dictionary-like objects
- selected_rows = split_data.select(range(offset, end_idx))
-
# Convert to SweBenchExample objects
examples = []
- for row in selected_rows:
+ for row in split_data:
if instance_id and row["instance_id"] != instance_id:
continue
if repo and row["repo"] != repo:
continue
+ if instance_ids and row["instance_id"] not in instance_ids:
+ continue
+
example = SweBenchExample(
repo=row["repo"],
instance_id=row["instance_id"],
@@ -125,7 +123,11 @@ def get_swe_bench_examples(
fail_to_pass=row["FAIL_TO_PASS"],
pass_to_pass=row.get("PASS_TO_PASS"),
environment_setup_commit=row.get("environment_setup_commit"),
+ difficulty=get_difficulty(row["instance_id"]),
)
examples.append(example)
- return examples[:length]
+ if length:
+ examples = examples[:length]
+
+ return examples
diff --git a/src/codegen/extensions/tools/github/__init__.py b/src/codegen/extensions/tools/github/__init__.py
index a59669dd2..f5f9761f3 100644
--- a/src/codegen/extensions/tools/github/__init__.py
+++ b/src/codegen/extensions/tools/github/__init__.py
@@ -1,11 +1,13 @@
from .create_pr import create_pr
from .create_pr_comment import create_pr_comment
from .create_pr_review_comment import create_pr_review_comment
+from .search import search
from .view_pr import view_pr
__all__ = [
"create_pr",
"create_pr_comment",
"create_pr_review_comment",
+ "search",
"view_pr",
]
diff --git a/src/codegen/extensions/tools/github/checkout_pr.py b/src/codegen/extensions/tools/github/checkout_pr.py
new file mode 100644
index 000000000..1b4b6d769
--- /dev/null
+++ b/src/codegen/extensions/tools/github/checkout_pr.py
@@ -0,0 +1,47 @@
+"""Tool for viewing PR contents and modified symbols."""
+
+from pydantic import Field
+
+from codegen.sdk.core.codebase import Codebase
+
+from ..observation import Observation
+
+
+class CheckoutPRObservation(Observation):
+ """Response from checking out a PR."""
+
+ pr_number: int = Field(
+ description="PR number",
+ )
+ success: bool = Field(
+ description="Whether the checkout was successful",
+ default=False,
+ )
+
+
+def checkout_pr(codebase: Codebase, pr_number: int) -> CheckoutPRObservation:
+ """Checkout a PR.
+
+ Args:
+ codebase: The codebase to operate on
+ pr_number: Number of the PR to get the contents for
+ """
+ try:
+ pr = codebase.op.remote_git_repo.get_pull_safe(pr_number)
+ if not pr:
+ return CheckoutPRObservation(
+ pr_number=pr_number,
+ success=False,
+ )
+
+ codebase.checkout(branch=pr.head.ref)
+ return CheckoutPRObservation(
+ pr_number=pr_number,
+ success=True,
+ )
+ except Exception as e:
+ return CheckoutPRObservation(
+ pr_number=pr_number,
+ success=False,
+ error=f"Failed to checkout PR: {e!s}",
+ )
diff --git a/src/codegen/extensions/tools/github/search.py b/src/codegen/extensions/tools/github/search.py
new file mode 100644
index 000000000..b83504937
--- /dev/null
+++ b/src/codegen/extensions/tools/github/search.py
@@ -0,0 +1,77 @@
+"""Tools for searching GitHub issues and pull requests."""
+
+from typing import ClassVar
+
+from pydantic import Field
+
+from codegen.sdk.core.codebase import Codebase
+
+from ..observation import Observation
+
+
+class SearchResultObservation(Observation):
+ """Response from searching issues and pull requests."""
+
+ query: str = Field(
+ description="The search query that was used",
+ )
+ results: list[dict] = Field(
+ description="List of matching issues/PRs with their details. Use is:pr in query to search for PRs, is:issue for issues.",
+ )
+
+ str_template: ClassVar[str] = "Found {total} results matching query: {query}"
+
+ @property
+ def total(self) -> int:
+ return len(self.results)
+
+
+def search(
+ codebase: Codebase,
+ query: str,
+ max_results: int = 20,
+) -> SearchResultObservation:
+ """Search for GitHub issues and pull requests using the provided query.
+
+ To search for pull requests specifically, include 'is:pr' in your query.
+ To search for issues specifically, include 'is:issue' in your query.
+ If neither is specified, both issues and PRs will be included in results.
+
+ Args:
+ codebase: The codebase to operate on
+ query: Search query string (e.g. "is:pr label:bug", "is:issue is:open")
+ state: Filter by state ("open", "closed", or "all")
+ max_results: Maximum number of results to return
+ """
+ try:
+ # Get the GitHub repo object
+ repo = codebase._op.remote_git_repo
+
+ # Search using PyGitHub's search_issues (which searches both issues and PRs)
+ results = []
+ for item in repo.search_issues(query)[:max_results]:
+ result = {
+ "title": item.title,
+ "number": item.number,
+ "state": item.state,
+ "labels": [label.name for label in item.labels],
+ "created_at": item.created_at.isoformat(),
+ "updated_at": item.updated_at.isoformat(),
+ "url": item.html_url,
+ "is_pr": item.pull_request is not None,
+ }
+ results.append(result)
+
+ return SearchResultObservation(
+ status="success",
+ query=query,
+ results=results,
+ )
+
+ except Exception as e:
+ return SearchResultObservation(
+ status="error",
+ error=f"Failed to search: {e!s}",
+ query=query,
+ results=[],
+ )
diff --git a/src/codegen/extensions/tools/github/view_pr_checks.py b/src/codegen/extensions/tools/github/view_pr_checks.py
new file mode 100644
index 000000000..9f17edaa2
--- /dev/null
+++ b/src/codegen/extensions/tools/github/view_pr_checks.py
@@ -0,0 +1,54 @@
+"""Tool for creating PR review comments."""
+
+import json
+
+from pydantic import Field
+
+from codegen.sdk.core.codebase import Codebase
+
+from ..observation import Observation
+
+
+class PRCheckObservation(Observation):
+ """Response from retrieving PR checks."""
+
+ pr_number: int = Field(
+ description="PR number that was viewed",
+ )
+ head_sha: str | None = Field(
+ description="SHA of the head commit",
+ )
+ summary: str | None = Field(
+ description="Summary of the checks",
+ )
+
+
+def view_pr_checks(codebase: Codebase, pr_number: int) -> PRCheckObservation:
+ """Retrieve check information from a Github PR .
+
+ Args:
+ codebase: The codebase to operate on
+ pr_number: The PR number to view checks on
+ """
+ try:
+ pr = codebase.op.remote_git_repo.get_pull_safe(pr_number)
+ if not pr:
+ return PRCheckObservation(
+ pr_number=pr_number,
+ head_sha=None,
+ summary=None,
+ )
+ commit = codebase.op.remote_git_repo.get_commit_safe(pr.head.sha)
+ all_check_suites = commit.get_check_suites()
+ return PRCheckObservation(
+ pr_number=pr_number,
+ head_sha=pr.head.sha,
+ summary="\n".join([json.dumps(check_suite.raw_data) for check_suite in all_check_suites]),
+ )
+
+ except Exception as e:
+ return PRCheckObservation(
+ pr_number=pr_number,
+ head_sha=None,
+ summary=None,
+ )
diff --git a/src/codegen/extensions/tools/replacement_edit.py b/src/codegen/extensions/tools/replacement_edit.py
index 0c61c8f96..aa5cd98be 100644
--- a/src/codegen/extensions/tools/replacement_edit.py
+++ b/src/codegen/extensions/tools/replacement_edit.py
@@ -30,6 +30,14 @@ class ReplacementEditObservation(Observation):
default=None,
description="Message describing the result",
)
+ error: Optional[str] = Field(
+ default=None,
+ description="Error message if an error occurred",
+ )
+ error_pattern: Optional[str] = Field(
+ default=None,
+ description="Regex pattern that failed to compile",
+ )
str_template: ClassVar[str] = "{message}" if "{message}" else "Edited file {filepath}"
@@ -138,8 +146,13 @@ def replacement_edit(
# Compile pattern for better error messages
regex = re.compile(pattern, flags)
except re.error as e:
- msg = f"Invalid regex pattern: {e}"
- raise ValueError(msg)
+ return ReplacementEditObservation(
+ status="error",
+ error=f"Invalid regex pattern: {e!s}",
+ error_pattern=pattern,
+ filepath=filepath,
+ message="Invalid regex pattern",
+ )
# Perform the replacement
if count is None:
diff --git a/src/codegen/extensions/tools/search.py b/src/codegen/extensions/tools/search.py
index 4bcdfb74e..08a52c48b 100644
--- a/src/codegen/extensions/tools/search.py
+++ b/src/codegen/extensions/tools/search.py
@@ -146,7 +146,7 @@ def _search_with_ripgrep(
pass
# Add the query and path
- cmd.append(query)
+ cmd.append(f"{query}")
cmd.append(search_path)
# Run ripgrep
diff --git a/src/codegen/extensions/tools/semantic_edit.py b/src/codegen/extensions/tools/semantic_edit.py
index 80099830e..91f35083d 100644
--- a/src/codegen/extensions/tools/semantic_edit.py
+++ b/src/codegen/extensions/tools/semantic_edit.py
@@ -109,7 +109,7 @@ def get_llm_edit(original_file_section: str, edit_content: str) -> str:
def _validate_edit_boundaries(original_lines: list[str], modified_lines: list[str], start_idx: int, end_idx: int) -> None:
- """Validate that the edit only modified lines within the specified boundaries.
+ """Validate` that the edit only modified lines within the specified boundaries.
Args:
original_lines: Original file lines
diff --git a/src/codegen/git/clients/git_repo_client.py b/src/codegen/git/clients/git_repo_client.py
index 79c8df2a4..e90735639 100644
--- a/src/codegen/git/clients/git_repo_client.py
+++ b/src/codegen/git/clients/git_repo_client.py
@@ -7,6 +7,7 @@
from github.Commit import Commit
from github.GithubException import GithubException, UnknownObjectException
from github.GithubObject import NotSet, Opt
+from github.Issue import Issue
from github.IssueComment import IssueComment
from github.Label import Label
from github.PullRequest import PullRequest
@@ -431,3 +432,13 @@ def merge_upstream(self, branch_name: str) -> bool:
post_parameters = {"branch": branch_name}
status, _, _ = self.repo._requester.requestJson("POST", f"{self.repo.url}/merge-upstream", input=post_parameters)
return status == 200
+
+ ####################################################################################################################
+ # SEARCH
+ ####################################################################################################################
+
+ def search_issues(self, query: str, **kwargs) -> list[Issue]:
+ return self.gh_client.client.search_issues(query, **kwargs)
+
+ def search_prs(self, query: str, **kwargs) -> list[PullRequest]:
+ return self.gh_client.client.search_issues(query, **kwargs)
diff --git a/src/codegen/git/models/pull_request_context.py b/src/codegen/git/models/pull_request_context.py
index 6729acf63..1f97afbd1 100644
--- a/src/codegen/git/models/pull_request_context.py
+++ b/src/codegen/git/models/pull_request_context.py
@@ -14,10 +14,10 @@ class PullRequestContext(BaseModel):
state: str
title: str
user: GithubNamedUserContext
- body: str
draft: bool
head: PRPartContext
base: PRPartContext
+ body: str | None = None
merged: bool | None = None
merged_by: dict | None = None
additions: int | None = None
diff --git a/src/codegen/git/repo_operator/repo_operator.py b/src/codegen/git/repo_operator/repo_operator.py
index 42d9c7e47..c68ce1157 100644
--- a/src/codegen/git/repo_operator/repo_operator.py
+++ b/src/codegen/git/repo_operator/repo_operator.py
@@ -20,7 +20,7 @@
from codegen.git.clients.git_repo_client import GitRepoClient
from codegen.git.configs.constants import CODEGEN_BOT_EMAIL, CODEGEN_BOT_NAME
from codegen.git.repo_operator.local_git_repo import LocalGitRepo
-from codegen.git.schemas.enums import CheckoutResult, FetchResult, SetupOption
+from codegen.git.schemas.enums import CheckoutResult, FetchResult, RepoVisibility, SetupOption
from codegen.git.schemas.repo_config import RepoConfig
from codegen.git.utils.clone import clone_or_pull_repo, clone_repo, pull_repo
from codegen.git.utils.clone_url import add_access_token_to_url, get_authenticated_clone_url_for_repo_config, get_clone_url_for_repo_config, url_to_github
@@ -89,7 +89,7 @@ def repo_path(self) -> str:
@property
def remote_git_repo(self) -> GitRepoClient:
- if not self.access_token:
+ if not self.access_token and self.repo_config.visibility != RepoVisibility.PUBLIC:
msg = "Must initialize with access_token to get remote"
raise ValueError(msg)
@@ -616,6 +616,7 @@ def iter_files(
subdirs: list[str] | None = None,
extensions: list[str] | None = None,
ignore_list: list[str] | None = None,
+ skip_content: bool = False,
) -> Generator[tuple[str, str]]:
"""Iterates over all files in the codebase, yielding the filepath and its content.
@@ -642,8 +643,14 @@ def iter_files(
if extensions is None or any(filepath.endswith(e) for e in extensions):
try:
- content = self.get_file(filepath)
- yield rel_filepath, content
+ if os.path.isfile(filepath):
+ if not skip_content:
+ content = self.get_file(filepath)
+ yield rel_filepath, content
+ else:
+ yield rel_filepath, ""
+ else:
+ logger.warning(f"Skipping {filepath} because it does not exist or is not a valid file.")
except Exception as e:
logger.warning(f"Error reading file {filepath}: {e}")
@@ -843,13 +850,14 @@ def create_from_commit(cls, repo_path: str, commit: str, url: str, access_token:
return op
@classmethod
- def create_from_repo(cls, repo_path: str, url: str, access_token: str | None = None) -> Self | None:
+ def create_from_repo(cls, repo_path: str, url: str, access_token: str | None = None, full_history: bool = False) -> Self | None:
"""Create a fresh clone of a repository or use existing one if up to date.
Args:
repo_path (str): Path where the repo should be cloned
url (str): Git URL of the repository
access_token (str | None): Optional GitHub API key for operations that need GitHub access
+ full_history (bool): If True, clones the complete repository history. If False, performs a shallow clone. Defaults to False.
"""
access_token = access_token or SecretsConfig().github_token
if access_token:
@@ -879,9 +887,13 @@ def create_from_repo(cls, repo_path: str, url: str, access_token: str | None = N
import shutil
shutil.rmtree(repo_path)
+
try:
- # Clone the repository
- GitCLI.clone_from(url=url, to_path=repo_path, depth=1)
+ # Clone the repository with or without full history
+ if full_history:
+ GitCLI.clone_from(url=url, to_path=repo_path)
+ else:
+ GitCLI.clone_from(url=url, to_path=repo_path, depth=1)
# Initialize with the cloned repo
git_cli = GitCLI(repo_path)
diff --git a/src/codegen/git/utils/pr_review.py b/src/codegen/git/utils/pr_review.py
index 4ebdc204a..ffb3f52f0 100644
--- a/src/codegen/git/utils/pr_review.py
+++ b/src/codegen/git/utils/pr_review.py
@@ -1,6 +1,5 @@
from typing import TYPE_CHECKING
-import requests
from github import Repository
from github.PullRequest import PullRequest
from unidiff import PatchSet
@@ -39,28 +38,6 @@ def get_file_to_changed_ranges(pull_patch_set: PatchSet) -> dict[str, list]:
return file_to_changed_ranges
-def get_pull_patch_set(op: RepoOperator, pull: PullRequestContext) -> PatchSet:
- # Get the diff directly from GitHub's API
- if not op.remote_git_repo:
- msg = "GitHub API client is required to get PR diffs"
- raise ValueError(msg)
-
- # Get the diff directly from the PR
- diff_url = pull.raw_data.get("diff_url")
- if diff_url:
- # Fetch the diff content from the URL
- response = requests.get(diff_url)
- response.raise_for_status()
- diff = response.text
- else:
- # If diff_url not available, get the patch directly
- diff = pull.get_patch()
-
- # Parse the diff into a PatchSet
- pull_patch_set = PatchSet(diff)
- return pull_patch_set
-
-
def to_1_indexed(zero_indexed_range: range) -> range:
"""Converts a n-indexed range to n+1-indexed.
Primarily to convert 0-indexed ranges to 1 indexed
@@ -131,7 +108,7 @@ def __init__(self, op: RepoOperator, codebase: "Codebase", pr: PullRequest):
def modified_file_ranges(self) -> dict[str, list[tuple[int, int]]]:
"""Files and the ranges within that are modified"""
if not self._modified_file_ranges:
- pull_patch_set = get_pull_patch_set(op=self._op, pull=self._gh_pr)
+ pull_patch_set = self.get_pull_patch_set()
self._modified_file_ranges = get_file_to_changed_ranges(pull_patch_set)
return self._modified_file_ranges
@@ -174,15 +151,16 @@ def get_pr_diff(self) -> str:
raise ValueError(msg)
# Get the diff directly from the PR
- diff_url = self._gh_pr.raw_data.get("diff_url")
- if diff_url:
- # Fetch the diff content from the URL
- response = requests.get(diff_url)
- response.raise_for_status()
- return response.text
- else:
- # If diff_url not available, get the patch directly
- return self._gh_pr.get_patch()
+ status, _, res = self._op.remote_git_repo.repo._requester.requestJson("GET", self._gh_pr.url, headers={"Accept": "application/vnd.github.v3.diff"})
+ if status != 200:
+ msg = f"Failed to get PR diff: {res}"
+ raise Exception(msg)
+ return res
+
+ def get_pull_patch_set(self) -> PatchSet:
+ diff = self.get_pr_diff()
+ pull_patch_set = PatchSet(diff)
+ return pull_patch_set
def get_commit_sha(self) -> str:
"""Get the commit SHA of the PR"""
diff --git a/src/codegen/sdk/codebase/codebase_context.py b/src/codegen/sdk/codebase/codebase_context.py
index 9a015ba10..7f1fdc29e 100644
--- a/src/codegen/sdk/codebase/codebase_context.py
+++ b/src/codegen/sdk/codebase/codebase_context.py
@@ -365,7 +365,11 @@ def build_directory_tree(self) -> None:
# Reset and rebuild the directory tree
self.directories = dict()
- for file_path, _ in self.projects[0].repo_operator.iter_files(subdirs=self.projects[0].subdirectories, ignore_list=GLOBAL_FILE_IGNORE_LIST):
+ for file_path, _ in self.projects[0].repo_operator.iter_files(
+ subdirs=self.projects[0].subdirectories,
+ ignore_list=GLOBAL_FILE_IGNORE_LIST,
+ skip_content=True,
+ ):
file_path = Path(file_path)
directory = self.get_directory(file_path.parent, create_on_missing=True)
directory._add_file(file_path.name)
@@ -510,7 +514,6 @@ def _process_diff_files(self, files_to_sync: Mapping[SyncType, list[Path]], incr
# Step 6: Build directory tree
logger.info("> Building directory tree")
- files = [f for f in sort_editables(self.get_nodes(NodeType.FILE), alphabetical=True, dedupe=False)]
self.build_directory_tree()
# Step 7: Build configs
diff --git a/src/codegen/sdk/core/codebase.py b/src/codegen/sdk/core/codebase.py
index 735a8b5ea..d9a6e6960 100644
--- a/src/codegen/sdk/core/codebase.py
+++ b/src/codegen/sdk/core/codebase.py
@@ -26,6 +26,7 @@
from codegen.configs.models.secrets import SecretsConfig
from codegen.git.repo_operator.repo_operator import RepoOperator
from codegen.git.schemas.enums import CheckoutResult, SetupOption
+from codegen.git.schemas.repo_config import RepoConfig
from codegen.git.utils.pr_review import CodegenPR
from codegen.sdk._proxy import proxy_property
from codegen.sdk.ai.client import get_openai_client
@@ -1312,6 +1313,7 @@ def from_repo(
config: CodebaseConfig | None = None,
secrets: SecretsConfig | None = None,
setup_option: SetupOption | None = None,
+ full_history: bool = False,
) -> "Codebase":
"""Fetches a codebase from GitHub and returns a Codebase instance.
@@ -1343,15 +1345,17 @@ def from_repo(
repo_path = os.path.join(tmp_dir, repo)
repo_url = f"https://github.com/{repo_full_name}.git"
logger.info(f"Will clone {repo_url} to {repo_path}")
+ access_token = secrets.github_token if secrets else None
try:
# Use RepoOperator to fetch the repository
logger.info("Cloning repository...")
if commit is None:
- repo_operator = RepoOperator.create_from_repo(repo_path=repo_path, url=repo_url)
+ repo_config = RepoConfig.from_repo_path(repo_path)
+ repo_config.full_name = repo_full_name
+ repo_operator = RepoOperator.create_from_repo(repo_config=repo_config, access_token=access_token, setup_option=setup_option, full_history=full_history)
else:
# Ensure the operator can handle remote operations
- access_token = secrets.github_token if secrets else None
repo_operator = RepoOperator.create_from_commit(repo_path=repo_path, commit=commit, url=repo_url, full_name=repo_full_name, access_token=access_token)
logger.info("Clone completed successfully")
diff --git a/src/codegen/sdk/core/import_resolution.py b/src/codegen/sdk/core/import_resolution.py
index a824d8a72..c6d11af9d 100644
--- a/src/codegen/sdk/core/import_resolution.py
+++ b/src/codegen/sdk/core/import_resolution.py
@@ -706,6 +706,11 @@ def _resolved_types(self) -> Generator[ResolutionStack[Self], None, None]:
def _compute_dependencies(self, usage_type: UsageKind, dest: HasName | None = None) -> None:
pass
+ @property
+ @override
+ def filepath(self) -> str:
+ return self.imp.filepath
+
class ExternalImportResolver:
def resolve(self, imp: Import) -> str | None:
diff --git a/src/codegen/sdk/python/assignment.py b/src/codegen/sdk/python/assignment.py
index a85f57a82..2614b6d43 100644
--- a/src/codegen/sdk/python/assignment.py
+++ b/src/codegen/sdk/python/assignment.py
@@ -12,6 +12,7 @@
from codegen.sdk.python.symbol import PySymbol
from codegen.sdk.python.symbol_groups.comment_group import PyCommentGroup
from codegen.shared.decorators.docs import noapidoc, py_apidoc
+from codegen.shared.logging.get_logger import get_logger
if TYPE_CHECKING:
from tree_sitter import Node as TSNode
@@ -20,6 +21,8 @@
from codegen.sdk.core.node_id_factory import NodeId
from codegen.sdk.python.statements.assignment_statement import PyAssignmentStatement
+logger = get_logger(__name__)
+
@py_apidoc
class PyAssignment(Assignment["PyAssignmentStatement"], PySymbol):
@@ -152,6 +155,9 @@ def remove(self, delete_formatting: bool = True, priority: int = 0, dedupe: bool
else:
self.parent._values_scheduled_for_removal = []
else:
+ if name.source == "_":
+ logger.warning("Attempting to remove '_' in unpacking, command will be ignored. If you wish to remove the statement, remove the other remaining variable(s)!")
+ return
transaction_count = self._active_transactions_on_assignment_names(TransactionPriority.Edit)
throwaway = [asgnmt.name == "_" for asgnmt in self.parent.assignments].count(True)
# Only edit if we didn't already omit all the other assignments, otherwise just remove the whole thing
diff --git a/src/codegen/sdk/system-prompt.txt b/src/codegen/sdk/system-prompt.txt
index e2fee43ec..bcb57217d 100644
--- a/src/codegen/sdk/system-prompt.txt
+++ b/src/codegen/sdk/system-prompt.txt
@@ -437,6 +437,39 @@ if base_class:
references](/building-with-codegen/dependencies-and-usages) or [imports](/building-with-codegen/imports) and [exports](/building-with-codegen/exports).
+## Advanced Settings
+
+Codegen also supports a number of advanced settings that can be used to customize the behavior of the graph construction process.
+
+These flags are helpful for debugging problematic repos, optimizing Codegen’s performance, or testing unreleased or experimental (potentially backwards-breaking) features.
+
+```python
+from codegen import Codebase
+from codegen.configs import CodebaseConfig
+
+# Initialize a Codebase with custom configuration
+codebase = Codebase(
+ "path/to/git/repo"",
+ config=CodebaseConfig(
+ verify_graph=True,
+ method_usages=False,
+ sync_enabled=True,
+ generics=False,
+ import_resolution_overrides={
+ "old_module": "new_module"
+ },
+ ts_language_engine=True,
+ v8_ts_engine=True
+ )
+)
+```
+
+To learn more about available settings, see the [Advanced Settings](/introduction/advanced-settings) page.
+
+
+These are considered experimental and unstable features that may be removed or changed in the future.
+
+
## What's Next?
@@ -956,6 +989,399 @@ Codegen is just getting started, and we're excited about the possibilities ahead
Check out our [community guide](/introduction/community) to get involved!
+---
+title: "Advanced Settings"
+sidebarTitle: "Advanced Settings"
+icon: "memory"
+iconType: "solid"
+---
+
+Codegen's [Codebase](/api-reference/core/Codebase) constructor accepts a `CodebaseConfig` object which is used to configure more advanced behaviors of the graph construction process.
+
+These flags are helpful for debugging problematic repos, optimizing Codegen's performance, or testing unreleased or experimental (potentially backwards-breaking) features.
+
+
+**These are considered experimental features and may change in the future!**
+
+As such, they may have little to no testing or documentation. Many of these flags may also be unsupported in the future!
+
+If you need help, please visit our [community](/introduction/community).
+
+
+
+These configuration options are defined in [src/codegen/configs/models/codebase.py](https://github.com/codegen-sh/codegen/blob/develop/src/codegen/configs/models/codebase.py).
+
+
+# Usage
+
+You can customize the behavior of the graph construction process when initializing a [Codebase](/api-reference/core/Codebase) by passing a `CodebaseConfig` object with the desired configuration flags.
+
+```python
+from codegen import Codebase
+from codegen.configs import CodebaseConfig
+
+# Initialize a Codebase with custom configuration
+codebase = Codebase(
+ "",
+ config=CodebaseConfig(
+ flag1=...,
+ flag2=...,
+ ...
+ )
+)
+```
+
+# Table of Contents
+
+- [debug](#flag-debug)
+- [verify-graph](#flag-verify-graph)
+- [track-graph](#flag-track-graph)
+- [method-usages](#flag-method-usages)
+- [sync-enabled](#flag-sync-enabled)
+- [full-range-index](#flag-full-range-index)
+- [ignore-process-errors](#flag-ignore-process-errors)
+- [disable-graph](#flag-disable-graph)
+- [disable-file-parse](#flag-disable-file-parse)
+- [exp-lazy-graph](#flag-exp-lazy-graph)
+- [generics](#flag-generics)
+- [import-resolution-paths](#flag-import-resolution-paths)
+- [import-resolution-overrides](#flag-import-resolution-overrides)
+- [py-resolve-syspath](#flag-py-resolve-syspath)
+- [ts-dependency-manager](#flag-ts-dependency-manager)
+- [ts-language-engine](#flag-ts-language-engine)
+- [v8-ts-engine](#flag-v8-ts-engine)
+- [unpacking-assignment-partial-removal](#flag-unpacking-assignment-partial-removal)
+
+# Configuration Flags
+
+## Flag: `debug`
+> **Default: `False`**
+
+Enables verbose logging for debugging purposes. In its current form, it enables:
+- Verbose logging when adding nodes to the graph
+- Verbose logging during initial file parsing
+- Additional assertions on graph creation
+- Additional (costly) debug metrics on codebase construction
+- etc.
+
+
+This flag may be very noisy and significantly impact performance. It is generally not recommended to use.
+
+
+## Flag: `verify_graph`
+> **Default: `False`**
+
+Adds assertions for graph state during reset resync. Used to test and debug graph desyncs after a codebase reset.
+
+Runs `post_reset_validation` after a reset resync.
+
+
+This is an internal debug flag.
+
+
+## Flag: `track_graph`
+> **Default: `False`**
+
+Keeps a copy of the original graph before a resync. Used in conjunction with `verify_graph` to test and debug graph desyncs.
+
+Original graph is saved as `ctx.old_graph`.
+
+
+This is an internal debug flag.
+
+
+## Flag: `method_usages`
+> **Default: `True`**
+
+Enables and disables resolving method usages.
+
+**Example Codebase:**
+```python
+class Foo:
+ def bar():
+ ...
+
+obj = Foo()
+obj.bar() # Method Usage
+```
+
+**Codemod with `method_usages` on:**
+```python
+bar_func = codebase.get_class("Foo").get_method("bar")
+len(bar_func.usages) # 1
+bar_func.usages # [obj.bar()]
+```
+
+**Codemod with `method_usages` off:**
+```python
+bar_func = codebase.get_class("Foo").get_method("bar")
+len(bar_func.usages) # 0
+bar_func.usages # []
+```
+
+Method usage resolution could be disabled for a marginal performance boost. However, it is generally recommended to leave it enabled.
+
+## Flag: `sync_enabled`
+> **Default: `False`**
+
+Enables or disables graph sync during `codebase.commit`.
+
+
+Implementation-specific details on sync graph can be found [here](https://github.com/codegen-sh/codegen/blob/develop/architecture/6.%20incremental-computation/C.%20Graph%20Recomputation.md).
+
+
+This section won't go into the specific details of sync graph, but the general idea is that enabling sync graph will update the Codebase object to whatever new changes were made.
+
+**Example with `sync_enabled` on:**
+```python
+file = codebase.get_file(...)
+file.insert_after("foobar = 1")
+codebase.commit()
+
+foobar = codebase.get_symbol("foobar")
+assert foobar # foobar is available after commit / graph sync
+```
+
+**Example with `sync_enabled` disabled:**
+```python
+file = codebase.get_file(...)
+file.insert_after("foobar = 1")
+
+foobar = codebase.get_symbol("foobar", optional=True)
+assert not foobar # foobar is not available after commit
+```
+
+
+Enabling sync graph will have a performance impact on codebase commit, but will also unlock a bunch of operations that were previously not possible.
+
+
+## Flag: `full_range_index`
+> **Default: `False`**
+
+By default, Codebase maintains an internal range-to-node index for fast lookups. (i.e. `bytes 120 to 130 maps to node X`).
+For optimization purposes, this only applies to nodes defined and handled by `parser.py`.
+
+Enabling `full_range_index` will create an additional index that maps **all** tree-sitter ranges to nodes.
+This can be useful for debugging or when you need to build any applications that require a full range-to-node index (i.e. a codebase tree lookup).
+
+
+This flag **significantly** increases memory usage!
+
+
+## Flag: `ignore_process_errors`
+> **Default: `True`**
+
+Controls whether to ignore errors that occur during external process execution (such as dependency manager or language engine).
+
+Disabling `ignore_process_errors` would make Codegen fail on errors that would otherwise be logged then ignored.
+
+## Flag: `disable_graph`
+> **Default: `False`**
+
+Disables the graph construction process. Any operations that require the graph will no longer work. (In other words, this turns off import resolution and usage/dependency resolution)
+
+Functions that operate purely on AST such as getting and editing parameters or modifying function and class definitions will still work.
+
+
+For codemods that do not require the graph (aka only AST/Syntax-level changes), **disabling graph parse could yield a 30%-40% decrease in parse time and memory usage**!
+
+
+## Flag: `disable_file_parse`
+> **Default: `False`**
+
+Disables **ALL** parsing, including file and graph parsing. This essentially treats all codebases as the "UNSUPPORTED" language mode.
+
+Nearly all functions except for editing primitives like `codebase.get_file` and `file.edit` will no longer work.
+
+
+This flag is useful for any usages of Codegen that do **NOT** require any AST/CST/Graph parsing. (i.e. using Codegen purely as a file editing harness)
+
+If this is your use case, this **could decrease parse and memory usage by 95%.**
+
+
+## Flag: `exp_lazy_graph`
+> **Default: `False`**
+
+This experimental flag pushes the graph creation back until the graph is needed. This is an experimental feature and may have some unintended consequences.
+
+**Example Codemod:**
+```python
+from codegen import Codebase
+from codegen.configs import CodebaseConfig
+
+# Enable lazy graph parsing
+codebase = Codebase("", config=CodebaseConfig(exp_lazy_graph=True))
+
+# The codebase object will be created immediately with no parsing done
+# These all do not require graph parsing
+codebase.files
+codebase.directories
+codebase.get_file("...")
+
+# These do require graph parsing, and will create the graph only if called
+codebase.get_function("...")
+codebase.get_class("...")
+codebase.imports
+```
+
+
+This may have a very slight performance boost. Use at your own risk!
+
+
+## Flag: `generics`
+> **Default: `True`**
+
+Enables and disables generic type resolution.
+
+**Example Codebase:**
+```python
+class Point:
+ def scale(cls, n: int):
+ pass
+
+class List[T]():
+ def pop(self) -> T:
+ ...
+
+l: List[Point] = []
+l.pop().scale(1) # Generic Usage
+```
+
+**Codemod with `generics` on:**
+```python
+bar_func = codebase.get_class("Point").get_method("scale")
+len(bar_func.usages) # 1
+bar_func.usages # [l.pop().scale(1)]
+```
+
+**Codemod with `generics` off:**
+```python
+bar_func = codebase.get_class("Point").get_method("scale")
+len(bar_func.usages) # 0
+bar_func.usages # []
+```
+
+
+Generic resolution is still largely WIP and experimental, and may not work in all cases. In some rare circumstances, disabling generics may result in a significant performance boost.
+
+
+## Flag: `import_resolution_paths`
+> **Default: `[]`**
+
+Controls alternative paths to resolve imports from.
+
+**Example Codebase:**
+```python
+# a/b/c/src.py
+def update():
+ pass
+
+# consumer.py
+from c import src as operations
+
+operations.update()
+```
+
+**Codemod:**
+```python
+codebase.ctx.config.import_resolution_paths = ["a/b"]
+```
+
+## Flag: `import_resolution_overrides`
+> **Default: `{}`**
+
+Controls import path overrides during import resolution.
+
+**Example**
+`from a.b.c import d` with the override `a/b` -> `foo/bar` will internally resolve the import as `from foo.bar.c import d`.
+
+## Flag: `py_resolve_syspath`
+> **Default: `False`**
+
+Enables and disables resolution of imports from `sys.path`.
+
+## Flag: `ts_dependency_manager`
+> **Default: `False`**
+
+
+**This is an internal flag used for Codegen Cloud and should not be used externally!**
+
+This flag **WILL** nuke any existing `node_modules` folder!
+
+
+
+This flag also assumes many constants for Codegen Cloud. Very likely this will not work if run locally.
+
+Instead, just install `node_modules` as normal (either through `npm`, `pnpm`, or `yarn`) and skip this setting!
+
+
+Enables Codegen's internal dependency installer for TypeScript. This will modify `package.json` and install the bare minimum set of installable dependencies.
+
+
+More documentation on TypeScript dependency manager can be found [here](https://github.com/codegen-sh/codegen/blob/develop/architecture/external/dependency-manager.md)
+
+
+## Flag: `ts_language_engine`
+> **Default: `False`**
+
+
+This feature was built primarily with Codegen Cloud in mind. As such, this assumes a valid NodeJS and TypeScript environment.
+
+
+Enables using the TypeScript compiler to extract information from the codebase. Enables commands such as `inferred_return_type`.
+
+
+This will increase memory usage and parsing time. Larger repos may even hit resource constraints with the bundled TypeScript compiler integration.
+
+
+## Flag: `v8_ts_engine`
+> **Default: `False`**
+
+
+This feature flag requires `ts_language_engine` to be enabled as well.
+
+
+Enables using the **V8-based TypeScript compiler** to extract information from the codebase. Enables commands such as `inferred_return_type`.
+
+The V8 implementation (as opposed to the default external-process based implementation) is less stable, but provides the entire TypeScript API to be used from within Codegen.
+
+
+This will increase memory usage and parsing time. Larger repos may even hit resource constraints with the V8-based TypeScript compiler integration.
+
+
+## Flag: `unpacking_assignment_partial_removal`
+> **Default: `False`**
+
+Enables smarter removal of unpacking assignments.
+
+**Example Codebase:**
+```python
+a, b, c = (1, 2, 3)
+```
+
+**Codemod with `unpacking_assignment_partial_removal` on:**
+```python
+file = codebase.get_file(...)
+b = file.get_symbol("b")
+b.remove()
+codebase.commit()
+
+file.symbols # [a, c]
+file.source # "a, c = (1, 3)"
+```
+
+**Codemod with `unpacking_assignment_partial_removal` off:**
+```python
+file = codebase.get_file(...)
+b = file.get_symbol("b")
+b.remove()
+codebase.commit()
+
+file.symbols # []
+file.source # ""
+```
+
+
---
title: "Guiding Principles"
sidebarTitle: "Principles"
@@ -6358,7 +6784,7 @@ Explore our tutorials to learn how to use Codegen for various code transformatio
Update SQLAlchemy code to use the new 2.0-style query interface and patterns.
@@ -7050,39 +7476,6 @@ While this example demonstrates a basic PR review bot, you can extend it to:
Check out our [Code Agent tutorial](/tutorials/build-code-agent) to learn more about building sophisticated AI agents with Codegen
-## Learn More
-
-
-
- Learn how to build intelligent code agents with Codegen.
-
-
- Explore Codegen's GitHub integration features.
-
-
- Learn about deploying apps with Modal.
-
-
- Understand code review patterns and best practices.
-
-
-
---
title: "Deep Code Research with AI"
sidebarTitle: "Code Research Agent"
@@ -8470,7 +8863,7 @@ new_code = promise_statement.edit(
- Ambiguous/conditional return blocks
-A list of all the covered cases can be found in the [example notebook](codegen-examples/examples/promises_to_async_await/promise_to_async_await.ipynb).
+A list of all the covered cases can be found in the [example notebook](https://github.com/codegen-sh/codegen-sdk/tree/codegen-examples/examples/promises_to_async_await/promise_to_async_await.ipynb).
diff --git a/tests/integration/codegen/git/codebase/conftest.py b/tests/integration/codegen/git/codebase/conftest.py
index a8ab00e4f..4e163c87d 100644
--- a/tests/integration/codegen/git/codebase/conftest.py
+++ b/tests/integration/codegen/git/codebase/conftest.py
@@ -2,11 +2,12 @@
import pytest
+from codegen.git.schemas.enums import SetupOption
from codegen.sdk.core.codebase import Codebase
@pytest.fixture
def codebase(tmpdir):
os.chdir(tmpdir)
- codebase = Codebase.from_repo(repo_full_name="codegen-sh/Kevin-s-Adventure-Game", tmp_dir=tmpdir, language="python")
+ codebase = Codebase.from_repo(repo_full_name="codegen-sh/Kevin-s-Adventure-Game", tmp_dir=tmpdir, language="python", setup_option=SetupOption.PULL_OR_CLONE)
yield codebase
diff --git a/tests/integration/extension/test_github.py b/tests/integration/extension/test_github.py
index 7f050bba7..4b6b82693 100644
--- a/tests/integration/extension/test_github.py
+++ b/tests/integration/extension/test_github.py
@@ -1,17 +1,16 @@
-"""Tests for Linear tools."""
+"""Tests for GitHub tools."""
import os
import pytest
-from codegen.extensions.linear.linear_client import LinearClient
-from codegen.extensions.tools.github import view_pr
+from codegen.extensions.tools.github import search, view_pr
from codegen.sdk.core.codebase import Codebase
@pytest.fixture
-def client() -> LinearClient:
- """Create a Linear client for testing."""
+def codebase() -> Codebase:
+ """Create a Codebase instance for testing."""
token = os.getenv("GITHUB_TOKEN")
if not token:
pytest.skip("GITHUB_TOKEN environment variable not set")
@@ -19,8 +18,44 @@ def client() -> LinearClient:
return codebase
-def test_github_view_pr(client: LinearClient) -> None:
- """Test getting an issue from Linear."""
+def test_github_view_pr(codebase: Codebase) -> None:
+ """Test viewing a PR from GitHub."""
# Link to PR: https://github.com/codegen-sh/Kevin-s-Adventure-Game/pull/419
- pr = view_pr(client, 419)
+ pr = view_pr(codebase, 419)
print(pr)
+
+
+def test_github_search_issues(codebase: Codebase) -> None:
+ """Test searching GitHub issues."""
+ # Search for closed issues with the 'bug' label
+ result = search(codebase, query="is:issue is:closed")
+ assert result.status == "success"
+ assert len(result.results) > 0
+ assert "is:issue is:closed" in result.query
+
+ # Verify issue structure
+ if result.results:
+ issue = result.results[0]
+ assert "title" in issue
+ assert "number" in issue
+ assert "state" in issue
+ assert issue["state"] == "closed"
+ assert not issue["is_pr"] # Should be an issue, not a PR
+
+
+def test_github_search_prs(codebase: Codebase) -> None:
+ """Test searching GitHub pull requests."""
+ # Search for merged PRs
+ result = search(codebase, query="is:pr is:merged")
+ assert result.status == "success"
+ assert len(result.results) > 0
+ assert "is:pr is:merged" in result.query
+
+ # Verify PR structure
+ if result.results:
+ pr = result.results[0]
+ assert "title" in pr
+ assert "number" in pr
+ assert "state" in pr
+ assert pr["state"] == "closed"
+ assert pr["is_pr"] # Should be a PR
diff --git a/tests/unit/codegen/extensions/test_tools.py b/tests/unit/codegen/extensions/test_tools.py
index ec394312e..70bf68512 100644
--- a/tests/unit/codegen/extensions/test_tools.py
+++ b/tests/unit/codegen/extensions/test_tools.py
@@ -1,7 +1,5 @@
"""Tests for codebase tools."""
-import subprocess
-
import pytest
from codegen.extensions.tools import (
@@ -17,7 +15,6 @@
replacement_edit,
reveal_symbol,
run_codemod,
- search,
semantic_edit,
semantic_search,
view_file,
@@ -138,10 +135,12 @@ def test_view_file_pagination(large_codebase):
result = view_file(large_codebase, "src/large_file.py", start_line=350)
assert result.status == "success"
assert result.start_line == 350
- assert result.has_more is True # File has 2010 lines, so there should be more content
+ # File has 2010 lines, so there should be more content
+ assert result.has_more is True
assert "def method_69" in result.content # Regular method
assert "def class_method_80" in result.content # Class method at 80
- assert result.end_line == 599 # Should show 250 lines from start (350 to 599)
+ # Should show 250 lines from start (350 to 599)
+ assert result.end_line == 599
# Test custom max_lines
result = view_file(large_codebase, "src/large_file.py", max_lines=100)
@@ -189,7 +188,8 @@ def test_view_file_pagination_edge_cases(large_codebase):
result = view_file(large_codebase, "src/large_file.py", start_line=200, end_line=2000)
assert result.status == "success"
assert result.start_line == 200
- assert result.end_line == min(200 + 250 - 1, 2010) # Should respect max_lines and file length
+ # Should respect max_lines and file length
+ assert result.end_line == min(200 + 250 - 1, 2010)
# Test negative start_line (should default to 1)
result = view_file(large_codebase, "src/large_file.py", start_line=-10)
@@ -205,7 +205,8 @@ def test_list_directory(codebase):
create_file(codebase, "src/core/models.py", "")
create_file(codebase, "src/utils.py", "")
- result = list_directory(codebase, "./", depth=2) # Ensure we get nested structure
+ # Ensure we get nested structure
+ result = list_directory(codebase, "./", depth=2)
assert result.status == "success"
# Check directory structure
@@ -232,229 +233,6 @@ def test_list_directory(codebase):
assert expected_tree in rendered.strip()
-def test_search(codebase):
- """Test searching the codebase."""
- result = search(codebase, "hello")
- assert result.status == "success"
- assert len(result.results) > 0
-
- # Check that we found the right content
- assert any("hello" in match.match.lower() for file_result in result.results for match in file_result.matches)
-
- # Check pagination info
- assert result.page == 1
- assert result.total_pages >= 1
- assert result.files_per_page == 10
-
-
-def test_search_regex(codebase):
- """Test searching with regex."""
- # Search for function definitions
- result = search(codebase, r"def\s+\w+", use_regex=True)
- assert result.status == "success"
- assert len(result.results) > 0
-
- # Should find both 'def hello' and 'def greet'
- matches = [match.line for file_result in result.results for match in file_result.matches]
- assert any("def hello" in match for match in matches)
- assert any("def greet" in match for match in matches)
-
-
-def test_search_target_directories(codebase):
- """Test searching with target directory filtering."""
- # First search without filter to ensure we have results
- result_all = search(codebase, "hello")
- assert result_all.status == "success"
- assert len(result_all.results) > 0
-
- # Now search with correct target directory
- result_filtered = search(codebase, "hello", target_directories=["src"])
- assert result_filtered.status == "success"
- assert len(result_filtered.results) > 0
-
- # Search with non-existent directory
- result_none = search(codebase, "hello", target_directories=["nonexistent"])
- assert result_none.status == "success"
- assert len(result_none.results) == 0
-
-
-def test_search_file_extensions(codebase, tmpdir):
- """Test searching with file extension filtering."""
- # Add a non-Python file
- js_content = "function hello() { console.log('Hello from JS!'); }"
- js_file = tmpdir / "src" / "script.js"
- js_file.write_text(js_content, encoding="utf-8")
-
- # Search all files
- result_all = search(codebase, "hello")
- assert result_all.status == "success"
- assert len(result_all.results) > 0
-
- # Search only Python files
- result_py = search(codebase, "hello", file_extensions=[".py"])
- assert result_py.status == "success"
- assert all(file_result.filepath.endswith(".py") for file_result in result_py.results)
-
- # Search only JS files
- result_js = search(codebase, "hello", file_extensions=[".js"])
- assert result_js.status == "success"
- if len(result_js.results) > 0: # Only if JS file was properly added to codebase
- assert all(file_result.filepath.endswith(".js") for file_result in result_js.results)
-
-
-def test_search_pagination(codebase, tmpdir):
- """Test search pagination."""
- # Create multiple files to test pagination
- files_dict = {}
- for i in range(15): # Create enough files to span multiple pages
- content = f"def function_{i}():\n print('Hello from function {i}!')"
- files_dict[f"src/file_{i}.py"] = content
-
- # Create a new codebase with all the files
- with get_codebase_session(tmpdir=tmpdir, files=files_dict) as pagination_codebase:
- # Search with default pagination (page 1)
- result_page1 = search(pagination_codebase, "Hello", files_per_page=5)
- assert result_page1.status == "success"
- assert result_page1.page == 1
- assert len(result_page1.results) <= 5
-
- # If we have enough results for multiple pages
- if result_page1.total_pages > 1:
- # Get page 2
- result_page2 = search(pagination_codebase, "Hello", page=2, files_per_page=5)
- assert result_page2.status == "success"
- assert result_page2.page == 2
- assert len(result_page2.results) <= 5
-
- # Ensure different files on different pages
- page1_files = {r.filepath for r in result_page1.results}
- page2_files = {r.filepath for r in result_page2.results}
- assert not page1_files.intersection(page2_files)
-
-
-def test_search_invalid_regex(codebase):
- """Test search with invalid regex pattern."""
- result = search(codebase, "(unclosed", use_regex=True)
- assert result.status == "error"
- # Check for either Python's error message or ripgrep's error message
- assert any(
- error_msg in result.error
- for error_msg in [
- "Invalid regex pattern", # Python error message
- "regex parse error", # ripgrep error message
- "unclosed group", # Common error description
- ]
- )
-
-
-def test_search_fallback(codebase, monkeypatch):
- """Test fallback to Python implementation when ripgrep fails."""
-
- # Mock subprocess.run to simulate ripgrep failure
- def mock_subprocess_run(*args, **kwargs):
- msg = "Simulated ripgrep failure"
- raise subprocess.SubprocessError(msg)
-
- # Apply the mock
- monkeypatch.setattr(subprocess, "run", mock_subprocess_run)
-
- # Search should still work using Python fallback
- result = search(codebase, "hello")
- assert result.status == "success"
- assert len(result.results) > 0
-
-
-def test_search_ripgrep_not_found(codebase, monkeypatch):
- """Test fallback to Python implementation when ripgrep is not installed."""
-
- # Mock subprocess.run to simulate ripgrep not found
- def mock_subprocess_run(*args, **kwargs):
- msg = "Simulated ripgrep not found"
- raise FileNotFoundError(msg)
-
- # Apply the mock
- monkeypatch.setattr(subprocess, "run", mock_subprocess_run)
-
- # Search should still work using Python fallback
- result = search(codebase, "hello")
- assert result.status == "success"
- assert len(result.results) > 0
-
-
-def test_search_uses_ripgrep(codebase, monkeypatch):
- """Test that ripgrep is used when available."""
- # Track if ripgrep was called
- ripgrep_called = False
-
- # Store original subprocess.run
- original_run = subprocess.run
-
- # Mock subprocess.run to track calls and then call the original
- def mock_subprocess_run(*args, **kwargs):
- nonlocal ripgrep_called
- # Check if this is a ripgrep call
- if args and args[0] and isinstance(args[0], list) and args[0][0] == "rg":
- ripgrep_called = True
- # Call the original implementation
- return original_run(*args, **kwargs)
-
- # Apply the mock
- monkeypatch.setattr(subprocess, "run", mock_subprocess_run)
-
- # Perform a search
- result = search(codebase, "hello")
- assert result.status == "success"
-
- # Verify ripgrep was called
- assert ripgrep_called, "Ripgrep was not used for the search"
-
-
-def test_search_implementation_consistency(codebase, monkeypatch):
- """Test that ripgrep and Python implementations produce consistent results."""
- from codegen.extensions.tools.search import _search_with_python, _search_with_ripgrep
-
- # Skip test if ripgrep is not available
- try:
- subprocess.run(["rg", "--version"], capture_output=True, check=False)
- except FileNotFoundError:
- pytest.skip("Ripgrep not available, skipping consistency test")
-
- # Simple search that should work in both implementations
- query = "hello"
-
- # Get results from both implementations
- ripgrep_result = _search_with_ripgrep(codebase, query)
- python_result = _search_with_python(codebase, query)
-
- # Compare basic metadata
- assert ripgrep_result.status == python_result.status
- assert ripgrep_result.query == python_result.query
-
- # Compare file paths found (order might differ)
- ripgrep_files = {r.filepath for r in ripgrep_result.results}
- python_files = {r.filepath for r in python_result.results}
-
- # There might be slight differences in which files are found due to how ripgrep handles
- # certain files, so we'll check for substantial overlap rather than exact equality
- common_files = ripgrep_files.intersection(python_files)
- assert len(common_files) > 0, "No common files found between ripgrep and Python implementations"
-
- # For common files, compare the line numbers found
- for filepath in common_files:
- # Find the corresponding file results
- ripgrep_file_result = next(r for r in ripgrep_result.results if r.filepath == filepath)
- python_file_result = next(r for r in python_result.results if r.filepath == filepath)
-
- # Compare line numbers - there might be slight differences in how matches are found
- ripgrep_lines = {m.line_number for m in ripgrep_file_result.matches}
- python_lines = {m.line_number for m in python_file_result.matches}
-
- # Check for substantial overlap in line numbers
- common_lines = ripgrep_lines.intersection(python_lines)
- if ripgrep_lines and python_lines: # Only check if both found matches
- assert len(common_lines) > 0, f"No common line matches found in {filepath}"
-
-
def test_edit_file(codebase):
"""Test editing a file."""
result = edit_file(codebase, "src/main.py", "print('edited')")
diff --git a/tests/unit/codegen/sdk/python/expressions/test_unpacking.py b/tests/unit/codegen/sdk/python/expressions/test_unpacking.py
index cdf853e37..274329bea 100644
--- a/tests/unit/codegen/sdk/python/expressions/test_unpacking.py
+++ b/tests/unit/codegen/sdk/python/expressions/test_unpacking.py
@@ -1,5 +1,11 @@
+from typing import TYPE_CHECKING
+from unittest.mock import patch
+
from codegen.sdk.codebase.factory.get_session import get_codebase_session
+if TYPE_CHECKING:
+ from codegen.sdk.core.file import SourceFile
+
def test_remove_unpacking_assignment(tmpdir) -> None:
# language=python
@@ -155,3 +161,27 @@ def test_remove_unpacking_assignment_num(tmpdir) -> None:
assert len(file2.symbols) == 0
assert file2.source == """"""
+
+
+@patch("codegen.sdk.python.assignment.logger")
+def test_unpacking_function_with_underscore_removal(mock_logger, tmpdir: str) -> None:
+ # language=python
+ content1 = """
+ args, _ = parser.parse_known_args() ##args gets deleted
+ with open(args.template_path) as f:
+ print('test')
+ """
+ with get_codebase_session(
+ tmpdir=tmpdir,
+ files={
+ "file1.py": content1,
+ },
+ ) as codebase:
+ file1: SourceFile = codebase.get_file("file1.py")
+
+ for symbol in codebase.symbols:
+ if not symbol.usages:
+ symbol.remove()
+ codebase.commit()
+ assert len(file1.symbols) != 0
+ assert mock_logger.warning.call_count == 1
diff --git a/uv.lock b/uv.lock
index 2c51348b3..8e0364f57 100644
--- a/uv.lock
+++ b/uv.lock
@@ -8,11 +8,11 @@ resolution-markers = [
[[package]]
name = "aiohappyeyeballs"
-version = "2.4.6"
+version = "2.5.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/08/07/508f9ebba367fc3370162e53a3cfd12f5652ad79f0e0bfdf9f9847c6f159/aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0", size = 21726 }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/0c/458958007041f4b4de2d307e6b75d9e7554dad0baf26fe7a48b741aac126/aiohappyeyeballs-2.5.0.tar.gz", hash = "sha256:18fde6204a76deeabc97c48bdd01d5801cfda5d6b9c8bbeb1aaaee9d648ca191", size = 22494 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/44/4c/03fb05f56551828ec67ceb3665e5dc51638042d204983a03b0a1541475b6/aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1", size = 14543 },
+ { url = "https://files.pythonhosted.org/packages/1b/9a/e4886864ce06e1579bd428208127fbdc0d62049c751e4e9e3b509c0059dc/aiohappyeyeballs-2.5.0-py3-none-any.whl", hash = "sha256:0850b580748c7071db98bffff6d4c94028d0d3035acc20fd721a0ce7e8cac35d", size = 15128 },
]
[[package]]
@@ -76,15 +76,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 },
]
-[[package]]
-name = "alabaster"
-version = "1.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 },
-]
-
[[package]]
name = "annotated-types"
version = "0.7.0"
@@ -137,11 +128,11 @@ wheels = [
[[package]]
name = "argcomplete"
-version = "3.5.3"
+version = "3.6.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/0c/be/6c23d80cb966fb8f83fb1ebfb988351ae6b0554d0c3a613ee4531c026597/argcomplete-3.5.3.tar.gz", hash = "sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392", size = 72999 }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/be/29abccb5d9f61a92886a2fba2ac22bf74326b5c4f55d36d0a56094630589/argcomplete-3.6.0.tar.gz", hash = "sha256:2e4e42ec0ba2fff54b0d244d0b1623e86057673e57bafe72dda59c64bd5dee8b", size = 73135 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/c4/08/2a4db06ec3d203124c967fc89295e85a202e5cbbcdc08fd6a64b65217d1e/argcomplete-3.5.3-py3-none-any.whl", hash = "sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61", size = 43569 },
+ { url = "https://files.pythonhosted.org/packages/08/94/e786d91ccc3a1fc664c20332825b73da20928eb067cdc984b821948a1acc/argcomplete-3.6.0-py3-none-any.whl", hash = "sha256:4e3e4e10beb20e06444dbac0ac8dda650cb6349caeefe980208d3c548708bedd", size = 43769 },
]
[[package]]
@@ -354,7 +345,7 @@ wheels = [
[[package]]
name = "braintrust"
-version = "0.0.185"
+version = "0.0.187"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "braintrust-core" },
@@ -368,9 +359,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/3d/22/1d0cd915b5455f3cfcf6167ece3c98850c297d507979bdc46d0b62e84dbb/braintrust-0.0.185.tar.gz", hash = "sha256:20712119928bb555cdf0ff8a8158a18b53d9b93909fdaefb3321252dcb97200c", size = 102666 }
+sdist = { url = "https://files.pythonhosted.org/packages/3a/2c/04494d3ffaf4f21518d026c7d033a5d0330459643539eee44fda21e8f5de/braintrust-0.0.187.tar.gz", hash = "sha256:8189eee23ba709db249260ad8fe75eecd5e8e9792ada77be3d2f55719ea00f68", size = 102881 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/da/d7/8ca9e03e4d76766b8985b02d8bf886727f845df072187d942e9d2d0e745b/braintrust-0.0.185-py3-none-any.whl", hash = "sha256:ec83f2e5ff87a56a9268c176ab83470ba0a1944ccf96081163c38631907f5d4d", size = 119452 },
+ { url = "https://files.pythonhosted.org/packages/50/d6/bc4288ebaea1f96183210c608d3bdd072cfa60cd54dfe573da7b6d8533d9/braintrust-0.0.187-py3-none-any.whl", hash = "sha256:0b628f27497ca30ea34e30606d834a7a9ff8a10203049b7e59cacdd5b8ec0ebc", size = 119629 },
]
[[package]]
@@ -561,6 +552,7 @@ dependencies = [
{ name = "langchain-anthropic" },
{ name = "langchain-core" },
{ name = "langchain-openai" },
+ { name = "langchain-xai" },
{ name = "langgraph" },
{ name = "langgraph-prebuilt" },
{ name = "langsmith" },
@@ -689,6 +681,7 @@ requires-dist = [
{ name = "langchain-anthropic", specifier = ">=0.3.7" },
{ name = "langchain-core" },
{ name = "langchain-openai" },
+ { name = "langchain-xai", specifier = ">=0.2.1" },
{ name = "langgraph" },
{ name = "langgraph-prebuilt" },
{ name = "langsmith" },
@@ -701,7 +694,7 @@ requires-dist = [
{ name = "neo4j" },
{ name = "networkx", specifier = ">=3.4.1" },
{ name = "numpy", specifier = ">=2.2.2" },
- { name = "openai", specifier = "==1.65.2" },
+ { name = "openai", specifier = "==1.65.5" },
{ name = "packaging", specifier = ">=24.2" },
{ name = "pip", specifier = ">=24.3.1" },
{ name = "plotly", specifier = ">=5.24.0,<7.0.0" },
@@ -991,19 +984,19 @@ wheels = [
[[package]]
name = "debugpy"
-version = "1.8.12"
+version = "1.8.13"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/68/25/c74e337134edf55c4dfc9af579eccb45af2393c40960e2795a94351e8140/debugpy-1.8.12.tar.gz", hash = "sha256:646530b04f45c830ceae8e491ca1c9320a2d2f0efea3141487c82130aba70dce", size = 1641122 }
+sdist = { url = "https://files.pythonhosted.org/packages/51/d4/f35f539e11c9344652f362c22413ec5078f677ac71229dc9b4f6f85ccaa3/debugpy-1.8.13.tar.gz", hash = "sha256:837e7bef95bdefba426ae38b9a94821ebdc5bea55627879cd48165c90b9e50ce", size = 1641193 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ba/e6/0f876ecfe5831ebe4762b19214364753c8bc2b357d28c5d739a1e88325c7/debugpy-1.8.12-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:7e94b643b19e8feb5215fa508aee531387494bf668b2eca27fa769ea11d9f498", size = 2500846 },
- { url = "https://files.pythonhosted.org/packages/19/64/33f41653a701f3cd2cbff8b41ebaad59885b3428b5afd0d93d16012ecf17/debugpy-1.8.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:086b32e233e89a2740c1615c2f775c34ae951508b28b308681dbbb87bba97d06", size = 4222181 },
- { url = "https://files.pythonhosted.org/packages/32/a6/02646cfe50bfacc9b71321c47dc19a46e35f4e0aceea227b6d205e900e34/debugpy-1.8.12-cp312-cp312-win32.whl", hash = "sha256:2ae5df899732a6051b49ea2632a9ea67f929604fd2b036613a9f12bc3163b92d", size = 5227017 },
- { url = "https://files.pythonhosted.org/packages/da/a6/10056431b5c47103474312cf4a2ec1001f73e0b63b1216706d5fef2531eb/debugpy-1.8.12-cp312-cp312-win_amd64.whl", hash = "sha256:39dfbb6fa09f12fae32639e3286112fc35ae976114f1f3d37375f3130a820969", size = 5267555 },
- { url = "https://files.pythonhosted.org/packages/cf/4d/7c3896619a8791effd5d8c31f0834471fc8f8fb3047ec4f5fc69dd1393dd/debugpy-1.8.12-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:696d8ae4dff4cbd06bf6b10d671e088b66669f110c7c4e18a44c43cf75ce966f", size = 2485246 },
- { url = "https://files.pythonhosted.org/packages/99/46/bc6dcfd7eb8cc969a5716d858e32485eb40c72c6a8dc88d1e3a4d5e95813/debugpy-1.8.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:898fba72b81a654e74412a67c7e0a81e89723cfe2a3ea6fcd3feaa3395138ca9", size = 4218616 },
- { url = "https://files.pythonhosted.org/packages/03/dd/d7fcdf0381a9b8094da1f6a1c9f19fed493a4f8576a2682349b3a8b20ec7/debugpy-1.8.12-cp313-cp313-win32.whl", hash = "sha256:22a11c493c70413a01ed03f01c3c3a2fc4478fc6ee186e340487b2edcd6f4180", size = 5226540 },
- { url = "https://files.pythonhosted.org/packages/25/bd/ecb98f5b5fc7ea0bfbb3c355bc1dd57c198a28780beadd1e19915bf7b4d9/debugpy-1.8.12-cp313-cp313-win_amd64.whl", hash = "sha256:fdb3c6d342825ea10b90e43d7f20f01535a72b3a1997850c0c3cefa5c27a4a2c", size = 5267134 },
- { url = "https://files.pythonhosted.org/packages/38/c4/5120ad36405c3008f451f94b8f92ef1805b1e516f6ff870f331ccb3c4cc0/debugpy-1.8.12-py2.py3-none-any.whl", hash = "sha256:274b6a2040349b5c9864e475284bce5bb062e63dce368a394b8cc865ae3b00c6", size = 5229490 },
+ { url = "https://files.pythonhosted.org/packages/79/ad/dff929b6b5403feaab0af0e5bb460fd723f9c62538b718a9af819b8fff20/debugpy-1.8.13-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1", size = 2501004 },
+ { url = "https://files.pythonhosted.org/packages/d6/4f/b7d42e6679f0bb525888c278b0c0d2b6dff26ed42795230bb46eaae4f9b3/debugpy-1.8.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522", size = 4222346 },
+ { url = "https://files.pythonhosted.org/packages/ec/18/d9b3e88e85d41f68f77235112adc31012a784e45a3fcdbb039777d570a0f/debugpy-1.8.13-cp312-cp312-win32.whl", hash = "sha256:3872ce5453b17837ef47fb9f3edc25085ff998ce63543f45ba7af41e7f7d370f", size = 5226639 },
+ { url = "https://files.pythonhosted.org/packages/c9/f7/0df18a4f530ed3cc06f0060f548efe9e3316102101e311739d906f5650be/debugpy-1.8.13-cp312-cp312-win_amd64.whl", hash = "sha256:63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea", size = 5268735 },
+ { url = "https://files.pythonhosted.org/packages/b1/db/ae7cd645c1826aae557cebccbc448f0cc9a818d364efb88f8d80e7a03f41/debugpy-1.8.13-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:31abc9618be4edad0b3e3a85277bc9ab51a2d9f708ead0d99ffb5bb750e18503", size = 2485416 },
+ { url = "https://files.pythonhosted.org/packages/ec/ed/db4b10ff3b5bb30fe41d9e86444a08bb6448e4d8265e7768450b8408dd36/debugpy-1.8.13-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0bd87557f97bced5513a74088af0b84982b6ccb2e254b9312e29e8a5c4270eb", size = 4218784 },
+ { url = "https://files.pythonhosted.org/packages/82/82/ed81852a8d94086f51664d032d83c7f87cd2b087c6ea70dabec7c1ba813d/debugpy-1.8.13-cp313-cp313-win32.whl", hash = "sha256:5268ae7fdca75f526d04465931cb0bd24577477ff50e8bb03dab90983f4ebd02", size = 5226270 },
+ { url = "https://files.pythonhosted.org/packages/15/63/aa92fb341a78ec40f1c414ec7a7885c2ee17032eee00d12cee0cdc502af4/debugpy-1.8.13-cp313-cp313-win_amd64.whl", hash = "sha256:79ce4ed40966c4c1631d0131606b055a5a2f8e430e3f7bf8fd3744b09943e8e8", size = 5268621 },
+ { url = "https://files.pythonhosted.org/packages/37/4f/0b65410a08b6452bfd3f7ed6f3610f1a31fb127f46836e82d31797065dcb/debugpy-1.8.13-py2.py3-none-any.whl", hash = "sha256:d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f", size = 5229306 },
]
[[package]]
@@ -1138,15 +1131,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637", size = 36533 },
]
-[[package]]
-name = "docutils"
-version = "0.21.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 },
-]
-
[[package]]
name = "dotty-dict"
version = "1.3.1"
@@ -1542,7 +1526,7 @@ wheels = [
[[package]]
name = "huggingface-hub"
-version = "0.29.1"
+version = "0.29.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "filelock" },
@@ -1553,9 +1537,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/22/37/797d6476f13e5ef6af5fc48a5d641d32b39c37e166ccf40c3714c5854a85/huggingface_hub-0.29.1.tar.gz", hash = "sha256:9524eae42077b8ff4fc459ceb7a514eca1c1232b775276b009709fe2a084f250", size = 389776 }
+sdist = { url = "https://files.pythonhosted.org/packages/58/b2/f8b3c9842a794e8203448725aefa02d7c9e0da42d5f22f4ed806057cc36e/huggingface_hub-0.29.2.tar.gz", hash = "sha256:590b29c0dcbd0ee4b7b023714dc1ad8563fe4a68a91463438b74e980d28afaf3", size = 389816 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ae/05/75b90de9093de0aadafc868bb2fa7c57651fd8f45384adf39bd77f63980d/huggingface_hub-0.29.1-py3-none-any.whl", hash = "sha256:352f69caf16566c7b6de84b54a822f6238e17ddd8ae3da4f8f2272aea5b198d5", size = 468049 },
+ { url = "https://files.pythonhosted.org/packages/13/5f/088ff08dc41808fcd99d9972b9bcfa7e3a35e30e8b0a3155b57938f1611c/huggingface_hub-0.29.2-py3-none-any.whl", hash = "sha256:c56f20fca09ef19da84dcde2b76379ecdaddf390b083f59f166715584953307d", size = 468087 },
]
[[package]]
@@ -1578,11 +1562,11 @@ wheels = [
[[package]]
name = "identify"
-version = "2.6.8"
+version = "2.6.9"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f9/fa/5eb460539e6f5252a7c5a931b53426e49258cde17e3d50685031c300a8fd/identify-2.6.8.tar.gz", hash = "sha256:61491417ea2c0c5c670484fd8abbb34de34cdae1e5f39a73ee65e48e4bb663fc", size = 99249 }
+sdist = { url = "https://files.pythonhosted.org/packages/9b/98/a71ab060daec766acc30fb47dfca219d03de34a70d616a79a38c6066c5bf/identify-2.6.9.tar.gz", hash = "sha256:d40dfe3142a1421d8518e3d3985ef5ac42890683e32306ad614a29490abeb6bf", size = 99249 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/78/8c/4bfcab2d8286473b8d83ea742716f4b79290172e75f91142bc1534b05b9a/identify-2.6.8-py2.py3-none-any.whl", hash = "sha256:83657f0f766a3c8d0eaea16d4ef42494b39b34629a4b3192a9d020d349b3e255", size = 99109 },
+ { url = "https://files.pythonhosted.org/packages/07/ce/0845144ed1f0e25db5e7a79c2354c1da4b5ce392b8966449d5db8dca18f1/identify-2.6.9-py2.py3-none-any.whl", hash = "sha256:c98b4322da415a8e5a70ff6e51fbc2d2932c015532d77e9f8537b4ba7813b150", size = 99101 },
]
[[package]]
@@ -1594,15 +1578,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
]
-[[package]]
-name = "imagesize"
-version = "1.4.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 },
-]
-
[[package]]
name = "importlib-metadata"
version = "8.6.1"
@@ -1677,7 +1652,7 @@ wheels = [
[[package]]
name = "ipython"
-version = "9.0.1"
+version = "9.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
@@ -1691,9 +1666,9 @@ dependencies = [
{ name = "stack-data" },
{ name = "traitlets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/9d/33/1901c9a842b301d8674f367dee597e654e402548a903faf7280aae8fc2d4/ipython-9.0.1.tar.gz", hash = "sha256:377ea91c8226b48dc9021ac9846a64761abc7ddf74c5efe38e6eb06f6e052f3a", size = 4365847 }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/ce/012a0f40ca58a966f87a6e894d6828e2817657cbdf522b02a5d3a87d92ce/ipython-9.0.2.tar.gz", hash = "sha256:ec7b479e3e5656bf4f58c652c120494df1820f4f28f522fb7ca09e213c2aab52", size = 4366102 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/28/39/fda74f8215ef94a812dd780073c61a826a88a01e51f627a3454f7ae6951d/ipython-9.0.1-py3-none-any.whl", hash = "sha256:3e878273824b52e0a2280ed84f8193aba8c4ba9a6f45a438348a3d5ef1a34bd0", size = 600186 },
+ { url = "https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl", hash = "sha256:143ef3ea6fb1e1bffb4c74b114051de653ffb7737a3f7ab1670e657ca6ae8c44", size = 600524 },
]
[[package]]
@@ -1743,14 +1718,14 @@ wheels = [
[[package]]
name = "jinja2"
-version = "3.1.5"
+version = "3.1.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 }
+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/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 },
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 },
]
[[package]]
@@ -2027,23 +2002,20 @@ wheels = [
[[package]]
name = "langchain"
-version = "0.3.19"
+version = "0.3.20"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "aiohttp" },
{ name = "langchain-core" },
{ name = "langchain-text-splitters" },
{ name = "langsmith" },
- { name = "numpy" },
{ name = "pydantic" },
{ name = "pyyaml" },
{ name = "requests" },
{ name = "sqlalchemy" },
- { name = "tenacity" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/a2/cf/a064ef27d5f3154491c85783590a25d7ae22340cddedf9bf47496044e4eb/langchain-0.3.19.tar.gz", hash = "sha256:b96f8a445f01d15d522129ffe77cc89c8468dbd65830d153a676de8f6b899e7b", size = 10224228 }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/b0/5121cdd19cf99e684043f4eae528c893f56bd25e7711d4de89f27832a5f3/langchain-0.3.20.tar.gz", hash = "sha256:edcc3241703e1f6557ef5a5c35cd56f9ccc25ff12e38b4829c66d94971737a93", size = 10225276 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/18/7d/0f4cc3317634195381f87c5d90268f29b9a31fda62aa7a7f36a1c27b06f3/langchain-0.3.19-py3-none-any.whl", hash = "sha256:1e16d97db9106640b7de4c69f8f5ed22eeda56b45b9241279e83f111640eff16", size = 1010630 },
+ { url = "https://files.pythonhosted.org/packages/b5/d4/afe8174838bdd3baba5d6a19e9f3af4c54c5db1ab4d66ef0b650c6157919/langchain-0.3.20-py3-none-any.whl", hash = "sha256:273287f8e61ffdf7e811cf8799e6a71e9381325b8625fd6618900faba79cfdd0", size = 1011577 },
]
[package.optional-dependencies]
@@ -2053,21 +2025,21 @@ openai = [
[[package]]
name = "langchain-anthropic"
-version = "0.3.8"
+version = "0.3.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anthropic" },
{ name = "langchain-core" },
{ name = "pydantic" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/63/2f/6ec88725da9cbb1c2b1295f6903faa2fa87fda07c87f8f0dfdec85f687dc/langchain_anthropic-0.3.8.tar.gz", hash = "sha256:1932977b8105744739ffdcb39861b041b73ae93846d0896a775fcea9a29e4b2b", size = 40585 }
+sdist = { url = "https://files.pythonhosted.org/packages/be/0a/7ccb79c41575b04266fc4def50f41d0a4689361421d82a14350d9d5e783e/langchain_anthropic-0.3.9.tar.gz", hash = "sha256:e8012d7986ad1d8412df6914c56f3c0d2797f231766a03bb1ad22cc7023e6e1d", size = 42205 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f2/b1/9f3f1b94c8770b2745c6cb950ef0f3299c2178ed3f9d73d61ccf3215390c/langchain_anthropic-0.3.8-py3-none-any.whl", hash = "sha256:05a70f51500d3c4e0f3e463730e193a25b6244e06b3bda3d7b2ec21d83d081ae", size = 23266 },
+ { url = "https://files.pythonhosted.org/packages/b9/27/258565b4a487fca7db363ea95765e6f1f00c23baa83dc4ec19a009213658/langchain_anthropic-0.3.9-py3-none-any.whl", hash = "sha256:adbbfaf3ce9798d46fb43d6fc01105630238f375dc6043d35d0aafab61fdbb71", size = 24414 },
]
[[package]]
name = "langchain-core"
-version = "0.3.40"
+version = "0.3.43"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jsonpatch" },
@@ -2078,23 +2050,23 @@ dependencies = [
{ name = "tenacity" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/4f/6b/7c3f5fa60639b885d8dbc932c37f0b0584ac5151ac6bdcd00b67b591e5e9/langchain_core-0.3.40.tar.gz", hash = "sha256:893a238b38491967c804662c1ec7c3e6ebaf223d1125331249c3cf3862ff2746", size = 528341 }
+sdist = { url = "https://files.pythonhosted.org/packages/8e/18/26255368f56d2749709fc2884c521d64471f32118ce09dfc677e0596be20/langchain_core-0.3.43.tar.gz", hash = "sha256:bec60f4f5665b536434ff747b8f23375a812e82cfa529f519b54cc1e7a94a875", size = 529403 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b7/01/b52e43f63261b5aae016cbe170bb5d8e8899770530075d11c1e45a07b97b/langchain_core-0.3.40-py3-none-any.whl", hash = "sha256:9f31358741f10a13db8531e8288b8a5ae91904018c5c2e6f739d6645a98fca03", size = 414346 },
+ { url = "https://files.pythonhosted.org/packages/20/0e/ddf9f5dc46b178df5c101666bb3bc7fc526d68cd81cdd60cbe1b6b438b30/langchain_core-0.3.43-py3-none-any.whl", hash = "sha256:caa6bc1f4c6ab71d3c2e400f8b62e1cd6dc5ac2c37e03f12f3e2c60befd5b273", size = 415421 },
]
[[package]]
name = "langchain-openai"
-version = "0.3.7"
+version = "0.3.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
{ name = "openai" },
{ name = "tiktoken" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/8e/3c/08add067e46409d3e881933155f546edb08644e5e4e2360ff22c6a2104a8/langchain_openai-0.3.7.tar.gz", hash = "sha256:b8b51a3aaa1cc3bda060651ea41145f7728219e8a7150b5404fb1e8446de9cef", size = 256488 }
+sdist = { url = "https://files.pythonhosted.org/packages/2e/04/ae071af0b04d1c3a8040498714091afd21149f6f8ae1dbab584317d9dfd7/langchain_openai-0.3.8.tar.gz", hash = "sha256:4d73727eda8102d1d07a2ca036278fccab0bb5e0abf353cec9c3973eb72550ec", size = 256898 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/36/0e/816c5293eda67600d374bb8484a9adab873c9096489f6f91634581919f35/langchain_openai-0.3.7-py3-none-any.whl", hash = "sha256:0aefc7bdf8e7398d41e09c4313cace816df6438f2aa93d34f79523487310f0da", size = 55254 },
+ { url = "https://files.pythonhosted.org/packages/a5/43/9c6a1101bcd751d52a3328a06956f85122f9aaa31da1b15a8e0f99a70317/langchain_openai-0.3.8-py3-none-any.whl", hash = "sha256:9004dc8ef853aece0d8f0feca7753dc97f710fa3e53874c8db66466520436dbb", size = 55446 },
]
[[package]]
@@ -2109,9 +2081,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4c/f8/6b82af988e65af9697f6a2f25373fb173fd32d48b62772a8773c5184c870/langchain_text_splitters-0.3.6-py3-none-any.whl", hash = "sha256:e5d7b850f6c14259ea930be4a964a65fa95d9df7e1dbdd8bad8416db72292f4e", size = 31197 },
]
+[[package]]
+name = "langchain-xai"
+version = "0.2.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "aiohttp" },
+ { name = "langchain-core" },
+ { name = "langchain-openai" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a3/94/a633bf1b4bbf66e4516f4188adc1174480c465ae12fb98f06c3e23c98519/langchain_xai-0.2.1.tar.gz", hash = "sha256:143a6f52be7617b5e5c68ab10c9b7df90914f54a6b3098566ce22b5d8fd89da5", size = 7788 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7b/88/d8050e610fadabf97c1745d24f0987b3e53b72fca63c8038ab1e0c103da9/langchain_xai-0.2.1-py3-none-any.whl", hash = "sha256:87228125cb15131663979d627210fca47dcd6b9a28462e8b5fee47f73bbed9f4", size = 6263 },
+]
+
[[package]]
name = "langgraph"
-version = "0.3.2"
+version = "0.3.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
@@ -2119,53 +2106,53 @@ dependencies = [
{ name = "langgraph-prebuilt" },
{ name = "langgraph-sdk" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/82/21/83cc5f941da39ba31b8ff07e5e55b3112839f0bf332d52e6b405ad365ae5/langgraph-0.3.2.tar.gz", hash = "sha256:4712c11a9355e5d15126e15a166807a1d6275d72cf74fd2303609ffc2505e7a8", size = 113460 }
+sdist = { url = "https://files.pythonhosted.org/packages/4e/fa/b1ecc95a2464bc7dbe5e67fbd21096013829119899c33236090b98c75508/langgraph-0.3.5.tar.gz", hash = "sha256:7c0d8e61aa02578b41036c9f7a599ccba2562d269f66ef76bacbba47a99a7eca", size = 114020 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/33/1c/c50719e89442094bace035e632da7be161e5389974f2b805b75fef7aab8f/langgraph-0.3.2-py3-none-any.whl", hash = "sha256:1e17f85e225bf4fc5f0f70bce89d8bc5d1536b7993e39e2e47baa1b1a17a439c", size = 130875 },
+ { url = "https://files.pythonhosted.org/packages/a4/5f/1e1d9173b5c41eff54f88d9f4ee82c38eb4928120ab6a21a68a78d1c499e/langgraph-0.3.5-py3-none-any.whl", hash = "sha256:be313ec300633c857873ea3e44aece4dd7d0b11f131d385108b359d377a85bf7", size = 131527 },
]
[[package]]
name = "langgraph-checkpoint"
-version = "2.0.16"
+version = "2.0.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
{ name = "msgpack" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/01/66/5d4a2013a84c511be289bb4a5ef91cbaad28c091b6b366fdb79710a1458b/langgraph_checkpoint-2.0.16.tar.gz", hash = "sha256:49ba8cfa12b2aae845ccc3b1fbd1d7a8d3a6c4a2e387ab3a92fca40dd3d4baa5", size = 34206 }
+sdist = { url = "https://files.pythonhosted.org/packages/76/1d/27a178de8a40c0cd53671f6a7e9aa21967a17672fdc774e5c0ae6cc406a4/langgraph_checkpoint-2.0.18.tar.gz", hash = "sha256:2822eedd028b454b7bfebfb7e04347aed1b64db97dedb7eb68ef0fb42641606d", size = 34947 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7c/63/03bc3dd304ead45b53313cab8727329e1d139a2d220f2d030c72242c860e/langgraph_checkpoint-2.0.16-py3-none-any.whl", hash = "sha256:dfab51076a6eddb5f9e146cfe1b977e3dd6419168b2afa23ff3f4e47973bf06f", size = 38291 },
+ { url = "https://files.pythonhosted.org/packages/21/11/91062b03b22b9ce6474df7c3e056417a4c2b029f9cc71829dd6f62479dd0/langgraph_checkpoint-2.0.18-py3-none-any.whl", hash = "sha256:941de442e5a893a6cabb8c3845f03159301b85f63ff4e8f2b308f7dfd96a3f59", size = 39106 },
]
[[package]]
name = "langgraph-prebuilt"
-version = "0.1.1"
+version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
{ name = "langgraph-checkpoint" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/22/15/848593ccace12e4f8b80cc0b159b0ba1da17605e1eecbda5f37d891748a3/langgraph_prebuilt-0.1.1.tar.gz", hash = "sha256:420a748ff93842f2b1a345a0c1ca3939d2bc7a2d46c20e9a9a0d8f148152cc47", size = 23257 }
+sdist = { url = "https://files.pythonhosted.org/packages/99/68/e1e692dbaeb4e9159b60a585fbfc26fbf073b3bb061caa2ff3153f85121a/langgraph_prebuilt-0.1.2.tar.gz", hash = "sha256:cfa7e54006d45e8f3d034ee88fa1d457c381bf6a2a0de0e64c5d3a776659e6d0", size = 23310 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3c/62/a424fdb892f578fa88b2ff4df0bfdebdc8b89501dacb8ca3b480305cbfef/langgraph_prebuilt-0.1.1-py3-none-any.whl", hash = "sha256:148a9558a36ec7e83cc6512f3521425c862b0463251ae0242ade52a448c54e78", size = 24622 },
+ { url = "https://files.pythonhosted.org/packages/73/2c/2fd70d557b7343f766f79dc8184b391f3417fc85b34dd04439cdd12dc2e1/langgraph_prebuilt-0.1.2-py3-none-any.whl", hash = "sha256:32028c4c4370576748e6c2e075cab1e13b5e3f2c196a390d71cacfb455212311", size = 24684 },
]
[[package]]
name = "langgraph-sdk"
-version = "0.1.53"
+version = "0.1.55"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
{ name = "orjson" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/39/b2/a261cfbf91a4499396ba0993cf5601076301dd22883d3c0901e905253917/langgraph_sdk-0.1.53.tar.gz", hash = "sha256:12906ed965905fa27e0c28d9fa07dc6fd89e6895ff321ff049fdf3965d057cc4", size = 42369 }
+sdist = { url = "https://files.pythonhosted.org/packages/7a/6c/8286151a21124dc0189b57495541c2e3cace317056f60feb04076b438f82/langgraph_sdk-0.1.55.tar.gz", hash = "sha256:89a0240157a27822cc4edd1c9e72bc852e20f5c71165a4c9b91eeffa11fd6a6b", size = 42690 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fc/97/3492a07b454cc74bf49938e83f0a95c608a8bc5c3dda338091d3c66e3ec5/langgraph_sdk-0.1.53-py3-none-any.whl", hash = "sha256:4fab62caad73661ffe4c3ababedcd0d7bfaaba986bee4416b9c28948458a3af5", size = 45441 },
+ { url = "https://files.pythonhosted.org/packages/4e/64/4b75f4b57f0c8f39bdb43aa74b1d2edcdb604b5baa58465ccc54b8b906c5/langgraph_sdk-0.1.55-py3-none-any.whl", hash = "sha256:266e92a558eb738da1ef04c29fbfc2157cd3a977b80905d9509a2cb79331f8fc", size = 45785 },
]
[[package]]
name = "langsmith"
-version = "0.3.11"
+version = "0.3.13"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -2176,9 +2163,9 @@ dependencies = [
{ name = "requests-toolbelt" },
{ name = "zstandard" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ea/34/c4c0eddad03e00457cd6be1a88c288cd4419da8d368d8f519a29abe5392c/langsmith-0.3.11.tar.gz", hash = "sha256:ddf29d24352e99de79c9618aaf95679214324e146c5d3d9475a7ddd2870018b1", size = 323815 }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/18/14b2427d627bba44abc613dc78cbd395580310856774ce8c555bd58308dd/langsmith-0.3.13.tar.gz", hash = "sha256:14014058cff408772acb93344e03cb64174837292d5f1ae09b2c8c1d8df45e92", size = 326588 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ff/68/514ffa62860202a5a0a3acbf5c05017ef9df38d4437d2cb44a3cf93d617b/langsmith-0.3.11-py3-none-any.whl", hash = "sha256:0cca22737ef07d3b038a437c141deda37e00add56022582680188b681bec095e", size = 335265 },
+ { url = "https://files.pythonhosted.org/packages/e0/09/3f909694aa0b104a611444959227832206864d92703e191a0f4b2a27d55b/langsmith-0.3.13-py3-none-any.whl", hash = "sha256:73aaf52bbc293b9415fff4f6dad68df40658081eb26c9cb2c7bd1ff57cedd695", size = 339683 },
]
[[package]]
@@ -2253,15 +2240,14 @@ wheels = [
[[package]]
name = "lox"
-version = "0.12.0"
+version = "0.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pathos" },
- { name = "sphinx-rtd-theme" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0f/b5/2bfa8da2a1dd6647c3ea0b8d7ae366bbb36b49f9f3858a253199daacb860/lox-0.12.0.tar.gz", hash = "sha256:cc7d5f867afb4dc7c2bce7bd6e90f4665c6df492863f35ff63229300b7219977", size = 37579 }
+sdist = { url = "https://files.pythonhosted.org/packages/95/85/923891e93122afcd724241a2bca01331ac2b956cde021445f51cf223e642/lox-0.13.0.tar.gz", hash = "sha256:f27b17e01d8ae92eec5e6e782477e0fb78ab8ceccec0a64385e50f5b7211bb34", size = 37565 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/02/9a/cc790ca4b853821b76acb5944d32036590a789e5f3b9e4f10a8962bcfda5/lox-0.12.0-py2.py3-none-any.whl", hash = "sha256:ac0a392662f3a75cc9097655d26169d5e3564e2670431fd9884a7a09a09f6921", size = 25372 },
+ { url = "https://files.pythonhosted.org/packages/70/d5/eca08aa7cd286c2dacd0c39c1dd9828e537b000a1ca246af0bdafae56340/lox-0.13.0-py2.py3-none-any.whl", hash = "sha256:37e1a206b7ac932082e7bdc49c4c26f1b9be1a737010db5b6cff8c707714fe67", size = 25363 },
]
[[package]]
@@ -2411,7 +2397,7 @@ wheels = [
[[package]]
name = "modal"
-version = "0.73.81"
+version = "0.73.91"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -2429,9 +2415,9 @@ dependencies = [
{ name = "typing-extensions" },
{ name = "watchfiles" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0c/d6/800423a59ea862f696804059e5fb49bbb8ca3884aecfc62b4af7cba8f1a8/modal-0.73.81.tar.gz", hash = "sha256:9404481b1dcd2b926597f87afb9e1729caac8f49b8dc58302ba8e6f138d1be56", size = 469407 }
+sdist = { url = "https://files.pythonhosted.org/packages/d0/b6/c44d67b8468f86e2cad6c6f61afdc4021c97adabcc826d465eb45bd1b139/modal-0.73.91.tar.gz", hash = "sha256:77d8c556f9be37298e042ea0ea1602f5de3261ef1e3c4135f63a6f758be9c06d", size = 469844 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e8/a9/9dd0e5f58e0e7f37fee6761a4cdeb3352c2d32ee85a5022099e68f953224/modal-0.73.81-py3-none-any.whl", hash = "sha256:9c9ce548c1bde97aeba07904f6754910667a97250b5a44eb4dd9797bc387c969", size = 535608 },
+ { url = "https://files.pythonhosted.org/packages/1b/a9/8bf787c9dde7e0ae5d5c33ba9a75e5b67aadd90fd6046441c88024f651c7/modal-0.73.91-py3-none-any.whl", hash = "sha256:5d47a250dc8af992934359ffe9ee7c0cb1a1b7a732f47651750a982ed6b9a214", size = 536057 },
]
[[package]]
@@ -2563,11 +2549,11 @@ wheels = [
[[package]]
name = "narwhals"
-version = "1.29.0"
+version = "1.29.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e6/f7/caa23ebc4aed3ef2314441c44e1d842e701adc6af57587ffda9263c03b6e/narwhals-1.29.0.tar.gz", hash = "sha256:1021c345d56c66ff0cc8e6d03ca8c543d01ffc411630973a5cb69ee86824d823", size = 248349 }
+sdist = { url = "https://files.pythonhosted.org/packages/a7/17/7d35094da0820ae941d8ce51842f253da36c6f95360ea0afabfc18bc02c6/narwhals-1.29.1.tar.gz", hash = "sha256:c408acf09e90c116f247cf34f24a3a89d147e3e235b1d3c708cfd1960baf320a", size = 251464 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ee/f6/1fcd6b3d0e21d9b75e71ae68fbc92bbb9b9b1f4f33dd81c61d8f53378b30/narwhals-1.29.0-py3-none-any.whl", hash = "sha256:653aa8e5eb435816e7b50c8def17e7e5e3324c2ffd8a3eec03fef85792e9cf5e", size = 305214 },
+ { url = "https://files.pythonhosted.org/packages/f1/22/380df533b08a57bc9013bb5714f33c571e1447828d83213a66adaefc0a04/narwhals-1.29.1-py3-none-any.whl", hash = "sha256:2f68cfbb2562672c4dfa54f158ed8c2828e9920ef784981cd9114e419c444216", size = 308220 },
]
[[package]]
@@ -2716,7 +2702,7 @@ wheels = [
[[package]]
name = "openai"
-version = "1.65.2"
+version = "1.65.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
@@ -2728,9 +2714,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f6/03/0bbf201a7e44920d892db0445874c8111be4255cb9495379df18d6d36ea1/openai-1.65.2.tar.gz", hash = "sha256:729623efc3fd91c956f35dd387fa5c718edd528c4bed9f00b40ef290200fb2ce", size = 359185 }
+sdist = { url = "https://files.pythonhosted.org/packages/56/cf/e02fb2c5a834803e6f29f43fd3dfe010303282d1ea450a5b95e28608860a/openai-1.65.5.tar.gz", hash = "sha256:17d39096bbcaf6c86580244b493a59e16613460147f0ba5ab6e608cdb6628149", size = 359548 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/2c/3b/722ed868cb56f70264190ed479b38b3e46d14daa267d559a3fe3bd9061cf/openai-1.65.2-py3-none-any.whl", hash = "sha256:27d9fe8de876e31394c2553c4e6226378b6ed85e480f586ccfe25b7193fb1750", size = 473206 },
+ { url = "https://files.pythonhosted.org/packages/fc/8f/a178d73277bf2d838617fa20ba4ae6952e26074664aacb53ae4532a69588/openai-1.65.5-py3-none-any.whl", hash = "sha256:5948a504e7b4003d921cfab81273813793a31c25b1d7b605797c01757e0141f1", size = 474468 },
]
[[package]]
@@ -3565,11 +3551,11 @@ wheels = [
[[package]]
name = "python-json-logger"
-version = "3.2.1"
+version = "3.3.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e3/c4/358cd13daa1d912ef795010897a483ab2f0b41c9ea1b35235a8b2f7d15a7/python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008", size = 16287 }
+sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/4b/72/2f30cf26664fcfa0bd8ec5ee62ec90c03bd485e4a294d92aabc76c5203a5/python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090", size = 14924 },
+ { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163 },
]
[[package]]
@@ -3640,15 +3626,15 @@ wheels = [
[[package]]
name = "pywin32"
-version = "308"
+version = "309"
source = { registry = "https://pypi.org/simple" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 },
- { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 },
- { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 },
- { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 },
- { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 },
- { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 },
+ { url = "https://files.pythonhosted.org/packages/20/2c/b0240b14ff3dba7a8a7122dc9bbf7fbd21ed0e8b57c109633675b5d1761f/pywin32-309-cp312-cp312-win32.whl", hash = "sha256:de9acacced5fa82f557298b1fed5fef7bd49beee04190f68e1e4783fbdc19926", size = 8790648 },
+ { url = "https://files.pythonhosted.org/packages/dd/11/c36884c732e2b3397deee808b5dac1abbb170ec37f94c6606fcb04d1e9d7/pywin32-309-cp312-cp312-win_amd64.whl", hash = "sha256:6ff9eebb77ffc3d59812c68db33c0a7817e1337e3537859499bd27586330fc9e", size = 9497399 },
+ { url = "https://files.pythonhosted.org/packages/18/9f/79703972958f8ba3fd38bc9bf1165810bd75124982419b0cc433a2894d46/pywin32-309-cp312-cp312-win_arm64.whl", hash = "sha256:619f3e0a327b5418d833f44dc87859523635cf339f86071cc65a13c07be3110f", size = 8454122 },
+ { url = "https://files.pythonhosted.org/packages/6c/c3/51aca6887cc5e410aa4cdc55662cf8438212440c67335c3f141b02eb8d52/pywin32-309-cp313-cp313-win32.whl", hash = "sha256:008bffd4afd6de8ca46c6486085414cc898263a21a63c7f860d54c9d02b45c8d", size = 8789700 },
+ { url = "https://files.pythonhosted.org/packages/dd/66/330f265140fa814b4ed1bf16aea701f9d005f8f4ab57a54feb17f53afe7e/pywin32-309-cp313-cp313-win_amd64.whl", hash = "sha256:bd0724f58492db4cbfbeb1fcd606495205aa119370c0ddc4f70e5771a3ab768d", size = 9496714 },
+ { url = "https://files.pythonhosted.org/packages/2c/84/9a51e6949a03f25cd329ece54dbf0846d57fadd2e79046c3b8d140aaa132/pywin32-309-cp313-cp313-win_arm64.whl", hash = "sha256:8fd9669cfd41863b688a1bc9b1d4d2d76fd4ba2128be50a70b0ea66b8d37953b", size = 8453052 },
]
[[package]]
@@ -3898,16 +3884,16 @@ wheels = [
[[package]]
name = "rich-click"
-version = "1.8.6"
+version = "1.8.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "rich" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ea/e3/ff1c715b673ec9e01f4482d8d0edfd9adf891f3630d83e695b38337a3889/rich_click-1.8.6.tar.gz", hash = "sha256:8a2448fd80e3d4e16fcb3815bfbc19be9bae75c9bb6aedf637901e45f3555752", size = 38247 }
+sdist = { url = "https://files.pythonhosted.org/packages/a6/7a/4b78c5997f2a799a8c5c07f3b2145bbcda40115c4d35c76fbadd418a3c89/rich_click-1.8.8.tar.gz", hash = "sha256:547c618dea916620af05d4a6456da797fbde904c97901f44d2f32f89d85d6c84", size = 39066 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/09/c20b04b6c9cf273995753f226ca51656e00f8a37f1e723f8c713b93b2ad4/rich_click-1.8.6-py3-none-any.whl", hash = "sha256:55fb571bad7d3d69ac43ca45f05b44616fd019616161b1815ff053567b9a8e22", size = 35076 },
+ { url = "https://files.pythonhosted.org/packages/fa/69/963f0bf44a654f6465bdb66fb5a91051b0d7af9f742b5bd7202607165036/rich_click-1.8.8-py3-none-any.whl", hash = "sha256:205aabd5a98e64ab2c105dee9e368be27480ba004c7dfa2accd0ed44f9f1550e", size = 35747 },
]
[[package]]
@@ -3924,15 +3910,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/1b/1c2f43af46456050b27810a7a013af8a7e12bc545a0cdc00eb0df55eb769/rich_toolkit-0.13.2-py3-none-any.whl", hash = "sha256:f3f6c583e5283298a2f7dbd3c65aca18b7f818ad96174113ab5bec0b0e35ed61", size = 13566 },
]
-[[package]]
-name = "roman-numerals-py"
-version = "3.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742 },
-]
-
[[package]]
name = "rpds-py"
version = "0.23.1"
@@ -3982,27 +3959,27 @@ wheels = [
[[package]]
name = "ruff"
-version = "0.9.9"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/6f/c3/418441a8170e8d53d05c0b9dad69760dbc7b8a12c10dbe6db1e1205d2377/ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933", size = 3717448 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bc/c3/2c4afa9ba467555d074b146d9aed0633a56ccdb900839fb008295d037b89/ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367", size = 10027252 },
- { url = "https://files.pythonhosted.org/packages/33/d1/439e58487cf9eac26378332e25e7d5ade4b800ce1eec7dc2cfc9b0d7ca96/ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7", size = 10840721 },
- { url = "https://files.pythonhosted.org/packages/50/44/fead822c38281ba0122f1b76b460488a175a9bd48b130650a6fb6dbcbcf9/ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d", size = 10161439 },
- { url = "https://files.pythonhosted.org/packages/11/ae/d404a2ab8e61ddf6342e09cc6b7f7846cce6b243e45c2007dbe0ca928a5d/ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a", size = 10336264 },
- { url = "https://files.pythonhosted.org/packages/6a/4e/7c268aa7d84cd709fb6f046b8972313142cffb40dfff1d2515c5e6288d54/ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe", size = 9908774 },
- { url = "https://files.pythonhosted.org/packages/cc/26/c618a878367ef1b76270fd027ca93692657d3f6122b84ba48911ef5f2edc/ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c", size = 11428127 },
- { url = "https://files.pythonhosted.org/packages/d7/9a/c5588a93d9bfed29f565baf193fe802fa676a0c837938137ea6cf0576d8c/ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be", size = 12133187 },
- { url = "https://files.pythonhosted.org/packages/3e/ff/e7980a7704a60905ed7e156a8d73f604c846d9bd87deda9cabfa6cba073a/ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590", size = 11602937 },
- { url = "https://files.pythonhosted.org/packages/24/78/3690444ad9e3cab5c11abe56554c35f005b51d1d118b429765249095269f/ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb", size = 13771698 },
- { url = "https://files.pythonhosted.org/packages/6e/bf/e477c2faf86abe3988e0b5fd22a7f3520e820b2ee335131aca2e16120038/ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0", size = 11249026 },
- { url = "https://files.pythonhosted.org/packages/f7/82/cdaffd59e5a8cb5b14c408c73d7a555a577cf6645faaf83e52fe99521715/ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17", size = 10220432 },
- { url = "https://files.pythonhosted.org/packages/fe/a4/2507d0026225efa5d4412b6e294dfe54725a78652a5c7e29e6bd0fc492f3/ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1", size = 9874602 },
- { url = "https://files.pythonhosted.org/packages/d5/be/f3aab1813846b476c4bcffe052d232244979c3cd99d751c17afb530ca8e4/ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57", size = 10851212 },
- { url = "https://files.pythonhosted.org/packages/8b/45/8e5fd559bea0d2f57c4e12bf197a2fade2fac465aa518284f157dfbca92b/ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e", size = 11327490 },
- { url = "https://files.pythonhosted.org/packages/42/55/e6c90f13880aeef327746052907e7e930681f26a164fe130ddac28b08269/ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1", size = 10227912 },
- { url = "https://files.pythonhosted.org/packages/35/b2/da925693cb82a1208aa34966c0f36cb222baca94e729dd22a587bc22d0f3/ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1", size = 11355632 },
- { url = "https://files.pythonhosted.org/packages/31/d8/de873d1c1b020d668d8ec9855d390764cb90cf8f6486c0983da52be8b7b7/ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf", size = 10435860 },
+version = "0.9.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", size = 3759776 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", size = 10049494 },
+ { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", size = 10853584 },
+ { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", size = 10155692 },
+ { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", size = 10369760 },
+ { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", size = 9912196 },
+ { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", size = 11434985 },
+ { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", size = 12155842 },
+ { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", size = 11613804 },
+ { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", size = 13823776 },
+ { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", size = 11302673 },
+ { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", size = 10235358 },
+ { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", size = 9886177 },
+ { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", size = 10864747 },
+ { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", size = 11360441 },
+ { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", size = 10247401 },
+ { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", size = 11366360 },
+ { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", size = 10436892 },
]
[[package]]
@@ -4066,11 +4043,11 @@ wheels = [
[[package]]
name = "setuptools"
-version = "75.8.2"
+version = "76.0.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d1/53/43d99d7687e8cdef5ab5f9ec5eaf2c0423c2b35133a2b7e7bc276fc32b21/setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2", size = 1344083 }
+sdist = { url = "https://files.pythonhosted.org/packages/32/d2/7b171caf085ba0d40d8391f54e1c75a1cda9255f542becf84575cfd8a732/setuptools-76.0.0.tar.gz", hash = "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4", size = 1349387 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a9/38/7d7362e031bd6dc121e5081d8cb6aa6f6fedf2b67bf889962134c6da4705/setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f", size = 1229385 },
+ { url = "https://files.pythonhosted.org/packages/37/66/d2d7e6ad554f3a7c7297c3f8ef6e22643ad3d35ef5c63bf488bc89f32f31/setuptools-76.0.0-py3-none-any.whl", hash = "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6", size = 1236106 },
]
[[package]]
@@ -4143,15 +4120,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
]
-[[package]]
-name = "snowballstemmer"
-version = "2.2.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 },
-]
-
[[package]]
name = "soupsieve"
version = "2.6"
@@ -4161,114 +4129,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 },
]
-[[package]]
-name = "sphinx"
-version = "8.2.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "alabaster" },
- { name = "babel" },
- { name = "colorama", marker = "sys_platform == 'win32'" },
- { name = "docutils" },
- { name = "imagesize" },
- { name = "jinja2" },
- { name = "packaging" },
- { name = "pygments" },
- { name = "requests" },
- { name = "roman-numerals-py" },
- { name = "snowballstemmer" },
- { name = "sphinxcontrib-applehelp" },
- { name = "sphinxcontrib-devhelp" },
- { name = "sphinxcontrib-htmlhelp" },
- { name = "sphinxcontrib-jsmath" },
- { name = "sphinxcontrib-qthelp" },
- { name = "sphinxcontrib-serializinghtml" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741 },
-]
-
-[[package]]
-name = "sphinx-rtd-theme"
-version = "3.0.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "docutils" },
- { name = "sphinx" },
- { name = "sphinxcontrib-jquery" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561 },
-]
-
-[[package]]
-name = "sphinxcontrib-applehelp"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 },
-]
-
-[[package]]
-name = "sphinxcontrib-devhelp"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 },
-]
-
-[[package]]
-name = "sphinxcontrib-htmlhelp"
-version = "2.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 },
-]
-
-[[package]]
-name = "sphinxcontrib-jquery"
-version = "4.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "sphinx" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104 },
-]
-
-[[package]]
-name = "sphinxcontrib-jsmath"
-version = "1.0.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 },
-]
-
-[[package]]
-name = "sphinxcontrib-qthelp"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 },
-]
-
-[[package]]
-name = "sphinxcontrib-serializinghtml"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 },
-]
-
[[package]]
name = "sqlalchemy"
version = "2.0.38"
@@ -4336,14 +4196,14 @@ wheels = [
[[package]]
name = "starlette"
-version = "0.46.0"
+version = "0.46.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/44/b6/fb9a32e3c5d59b1e383c357534c63c2d3caa6f25bf3c59dd89d296ecbaec/starlette-0.46.0.tar.gz", hash = "sha256:b359e4567456b28d473d0193f34c0de0ed49710d75ef183a74a5ce0499324f50", size = 2575568 }
+sdist = { url = "https://files.pythonhosted.org/packages/04/1b/52b27f2e13ceedc79a908e29eac426a63465a1a01248e5f24aa36a62aeb3/starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230", size = 2580102 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/41/94/8af675a62e3c91c2dee47cf92e602cfac86e8767b1a1ac3caf1b327c2ab0/starlette-0.46.0-py3-none-any.whl", hash = "sha256:913f0798bd90ba90a9156383bcf1350a17d6259451d0d8ee27fc0cf2db609038", size = 71991 },
+ { url = "https://files.pythonhosted.org/packages/a0/4b/528ccf7a982216885a1ff4908e886b8fb5f19862d1962f56a3fce2435a70/starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227", size = 71995 },
]
[[package]]
@@ -4618,14 +4478,14 @@ wheels = [
[[package]]
name = "types-networkx"
-version = "3.4.2.20250227"
+version = "3.4.2.20250304"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/d8/63/a6924a14d564bb7c7dd249007601b421a1d6f5e00e93cfd36eb8b6dce5fe/types_networkx-3.4.2.20250227.tar.gz", hash = "sha256:cf690e08ac91d40ab07983dd06928f2090b3b7f8ee99f53c865f77b605d8a690", size = 55016 }
+sdist = { url = "https://files.pythonhosted.org/packages/ec/40/6dd15ecf27303c4c645e6e6f5ee60fc0d4b8edb4e859e72ac1e300eec471/types_networkx-3.4.2.20250304.tar.gz", hash = "sha256:249c74deeb6d64a360ce94fcbc6e4077d1bfd433b9186596f89b1146327cec1f", size = 55100 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/97/f0/f35c82ab5136d5e64c2c9662977bafda63189d092454704e85b2e3d6b112/types_networkx-3.4.2.20250227-py3-none-any.whl", hash = "sha256:9ef12b5e74efc3150772300a5b6cba2deff0d17895d46d227939dc490ec7527f", size = 137428 },
+ { url = "https://files.pythonhosted.org/packages/d0/bf/c0b0edd702562de22994cd6643ae7c17250a2a666dc24f8b298ee3c1a43a/types_networkx-3.4.2.20250304-py3-none-any.whl", hash = "sha256:d578c3100d7cd066996c49da0274e8bd18a251cd0ae57cd2ca7bad0e9c41dc6a", size = 137452 },
]
[[package]]
@@ -4639,23 +4499,26 @@ wheels = [
[[package]]
name = "types-requests"
-version = "2.32.0.20250301"
+version = "2.32.0.20250306"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/87/88/365d6b46f1088ddeccbc89c26190c3180088ef6e7c8d162fc619496aab96/types_requests-2.32.0.20250301.tar.gz", hash = "sha256:3d909dc4eaab159c0d964ebe8bfa326a7afb4578d8706408d417e17d61b0c500", size = 22977 }
+sdist = { url = "https://files.pythonhosted.org/packages/09/1a/beaeff79ef9efd186566ba5f0d95b44ae21f6d31e9413bcfbef3489b6ae3/types_requests-2.32.0.20250306.tar.gz", hash = "sha256:0962352694ec5b2f95fda877ee60a159abdf84a0fc6fdace599f20acb41a03d1", size = 23012 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b9/c2/e44564e8995dbc1738c2acacb8009d59c8cb19327da95a1b5c5d9cb68364/types_requests-2.32.0.20250301-py3-none-any.whl", hash = "sha256:0003e0124e2cbefefb88222ff822b48616af40c74df83350f599a650c8de483b", size = 20671 },
+ { url = "https://files.pythonhosted.org/packages/99/26/645d89f56004aa0ba3b96fec27793e3c7e62b40982ee069e52568922b6db/types_requests-2.32.0.20250306-py3-none-any.whl", hash = "sha256:25f2cbb5c8710b2022f8bbee7b2b66f319ef14aeea2f35d80f18c9dbf3b60a0b", size = 20673 },
]
[[package]]
name = "types-setuptools"
-version = "75.8.2.20250301"
+version = "75.8.2.20250305"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f6/02/5f476d1a4f2bb23ba47c3aac6246cae1159d430937171e58860a9f1f47f8/types_setuptools-75.8.2.20250301.tar.gz", hash = "sha256:c900bceebfffc92a4abc3cfd4b3c39ead1a2298a73dae37e6bc09da7baf797a0", size = 48468 }
+dependencies = [
+ { name = "setuptools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4f/18/a996861f5225e7d533a8d8b6aa61bcc9183429a6b8bc93b850aa2e22974d/types_setuptools-75.8.2.20250305.tar.gz", hash = "sha256:a987269b49488f21961a1d99aa8d281b611625883def6392a93855b31544e405", size = 42609 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f3/d8/aba63d60951fbec2917a9d2c8673605a57fdbfc9134268802988c99c7a4c/types_setuptools-75.8.2.20250301-py3-none-any.whl", hash = "sha256:3cc3e751db9e84eddf1e6d4f8c46bef2c77e6c25b0cd096f729ffa57d3d6a83a", size = 71841 },
+ { url = "https://files.pythonhosted.org/packages/d9/5b/bb33f99239a6d54ed1d8220a088d96d2ccacac7abb317df0d68d2500f3be/types_setuptools-75.8.2.20250305-py3-none-any.whl", hash = "sha256:ba80953fd1f5f49e552285c024f75b5223096a38a5138a54d18ddd3fa8f6a2d4", size = 63727 },
]
[[package]]
@@ -4736,27 +4599,27 @@ wheels = [
[[package]]
name = "uv"
-version = "0.6.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/4e/31/8f354a0b1df7ef4cb42da118dfae046d49f2c57ae427eb948a48a236c37d/uv-0.6.3.tar.gz", hash = "sha256:73587a192f2ebb8a25431d01037fe19f713fa99ff3b9fdf6e7a121131c6c5649", size = 3081857 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bb/c2/5a4138f1c615c7702943ce94155349943b5813e51faa38b6876a2ab86033/uv-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:facfec798eaddd07615b3a52973e38f2c8862ceb1bc685a5091891cd6c0c2a21", size = 15524019 },
- { url = "https://files.pythonhosted.org/packages/02/1d/abf01aa5e02b0a066f77b69a4f2f771c2ccd5424cd553e218afb026c65b9/uv-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b261895497f3c55a8a8917db0a1daeba1a9988ba487b068198d6cc4e8c13e769", size = 15537243 },
- { url = "https://files.pythonhosted.org/packages/ea/ac/4c1d5e04868051874dce74333fbe98e1f61e40a1522a9258a998775f2fab/uv-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:08e3f71a39c76c5b9ab63f9341b433a4ab8a1cc4e29d34ce81bd3b6f5bd642d8", size = 14450283 },
- { url = "https://files.pythonhosted.org/packages/00/8b/6cdb9a8cb4a5579d8b22d632e98d01f7c3695066ce1a2e33036edba2413a/uv-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:ebd4d1012c5043fe507f1f4477e7a54ec81e939e2a6e0229f23abb242f1622f5", size = 14909401 },
- { url = "https://files.pythonhosted.org/packages/51/8e/4d8c31250c7440a4c3704e81dab39f7f75db046e8b23f5322c3e47549557/uv-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f63b659a5ccbbd8c0ca5200c83ada6d19e73c0f1cafb8f4d9a7ef32544beb06d", size = 15245520 },
- { url = "https://files.pythonhosted.org/packages/4b/29/52976b3f7a79e4293763823e59d4de3b77506a1b9d298df0285be4879026/uv-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c23948f242a6bcbd274fa18387a608a52b21a3dfed18d324641964e305c348e9", size = 15890146 },
- { url = "https://files.pythonhosted.org/packages/54/38/a3c37aaf02b890d908edfec32e7a9b86e0df819df6443837929e40ac8d7e/uv-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0445ce49229001cec0a0b1240c6135e2252a3b8017ae878b0559411688a3e12a", size = 16817703 },
- { url = "https://files.pythonhosted.org/packages/df/0b/cd75c692266eb1cdea6764f9fb14d88babfa8d8433c414ac18623777760d/uv-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95ab9e9194046f4fb50daec6293e471fc18b6e1d350dba4f5328d0f19f6ec183", size = 16509829 },
- { url = "https://files.pythonhosted.org/packages/1c/5c/35747d595bf13f5b495a29ec9bb6212fd2fad7d8c32324a7faaeb6a643d0/uv-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af417925d7af00be949ebcab1bf187540bea235e9454aa2193ffae5b7ecc75cf", size = 20477063 },
- { url = "https://files.pythonhosted.org/packages/23/c7/4ea3d3f23d24240c54deee0248766c320163eef8b0117310f0be168fe0f0/uv-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed2d4e3c6e041bc8b55f931a58d758220e46e828b983967fbb318a117d879351", size = 16190208 },
- { url = "https://files.pythonhosted.org/packages/83/f2/96d4981c3490fabc5ba787703951124969f5b6dc8e3166543e7534de2dea/uv-0.6.3-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:a936275590f3091b05c03ad3ce69e2f8a4c964e80ae44ce0cf13cc3b412352f1", size = 15145146 },
- { url = "https://files.pythonhosted.org/packages/2b/62/1be7fb8b97fd057460b733bbdf30e71e771dcfbfab27b7db552fa4e219e6/uv-0.6.3-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:e842e96b941832cd95cb2fce90c5626b33e477773f425005e9237f8fd9ef5696", size = 15245907 },
- { url = "https://files.pythonhosted.org/packages/e0/1b/5849046e11f8154567b235fc8097ebb6a0d6416b3ce317300d9b06470481/uv-0.6.3-py3-none-musllinux_1_1_i686.whl", hash = "sha256:cd51af332fb0f6362cc44e4cca22c2d12c31dd52352c6259cae0e3570ce79da4", size = 15504955 },
- { url = "https://files.pythonhosted.org/packages/ec/46/d4fa9bd06f84bb83e452f3f201b058cd13969cb979402ff000c2e4c77a1e/uv-0.6.3-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:328677a74c7d998b654e4bfd50ba4347d0f3deed85284dbd041004a184353806", size = 16317436 },
- { url = "https://files.pythonhosted.org/packages/0b/d9/f93e4522cf1de51ff1a985ead75df85523cd1b689128b1b033c9e31204b8/uv-0.6.3-py3-none-win32.whl", hash = "sha256:dc2d965481bba716a0cf9d0f81896a70c341a854f0e4273f1887f22e52e5c9fb", size = 15545377 },
- { url = "https://files.pythonhosted.org/packages/91/ea/27dd790ec0d1f8c4ced06e27a409522bd157ed295a1140b3fb6cac3cd39a/uv-0.6.3-py3-none-win_amd64.whl", hash = "sha256:8fc19471fd4cfde1b31a47c239591d7c6dc0a31213f206d3953c528f9f3b406c", size = 16860609 },
- { url = "https://files.pythonhosted.org/packages/97/0f/01e48493264d75cfac6c953809e11c8356c77fb6be32dfce831bcf481ab2/uv-0.6.3-py3-none-win_arm64.whl", hash = "sha256:94a9d59c05f22829388e51a62a9cfddef4000a112e1c561bb5bd5761d4d672f1", size = 15697009 },
+version = "0.6.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5f/3b/9a699194b132948b377272f06f2218d6453d440c8bae77275cd7d21e64dc/uv-0.6.5.tar.gz", hash = "sha256:70ad4cc5f2b636edbeeebb3aee0a7daa66b17457038088be870ac7adc5a9842d", size = 3093602 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/40/ac0b8050e145ae7dab029e8590046f9f96af4c6a36a4c4ee328a81e56062/uv-0.6.5-py3-none-linux_armv6l.whl", hash = "sha256:c5676fc7cdd088e2c3342593c1d2dc379bf86a83301af7b0dfe8d45801a50d85", size = 15517362 },
+ { url = "https://files.pythonhosted.org/packages/3c/f8/c0c2a2d5021904830d0d9fac4885819d731af2ed8e4ec11d80751420c646/uv-0.6.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6e82de1cb6a116f7736de9542430d78c210d152c80723db8beffc14e5b4e4b40", size = 15606625 },
+ { url = "https://files.pythonhosted.org/packages/c6/f7/1c5a44233ba80938b316eb67b6f3087a5cdc032882fbb86abfb7b8d14f3a/uv-0.6.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:442639a874f6bb6864279f099c97739287d7e244bc25d0f791345cc69f46c940", size = 14483413 },
+ { url = "https://files.pythonhosted.org/packages/c9/15/68beb9094e976c9403d8b79de76601f793250d0ecb84cb69d5940ba36729/uv-0.6.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:b5445a509f500bbf18faba4e7cf5cc9763617c335d58afaa5f3e5a6e388dd4ee", size = 14914536 },
+ { url = "https://files.pythonhosted.org/packages/1c/49/42d917ec3a6d79751d54862ac8d5170b1f509680bcad506d949f5d365aaa/uv-0.6.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c5683bccfc2b92cdc2f91e2904baa8ee2b5893b33ac8acac25e702ce7d3e5415", size = 15264210 },
+ { url = "https://files.pythonhosted.org/packages/ad/4c/446c039726dc6f04cd963f2a0813ec4e35c57d3566a9daf0272e2c5e311d/uv-0.6.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43847ef95d56c239de940339e5cfc2ade58249005e8ab97244fdb69fb9761572", size = 15974263 },
+ { url = "https://files.pythonhosted.org/packages/8b/c6/46f5334c73846bb9afd883ca9a1f41262d677a3ee0e3ff0063acef5a8a05/uv-0.6.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ef0b2f810d87aa9bbad15c3ab113e555871f14c9cd8ad2205338fb0358aaf52d", size = 16842142 },
+ { url = "https://files.pythonhosted.org/packages/a3/b4/b01cfa179b6e65aeb58eaf89bd3a6880082ec0fa391f93cc786db65ace03/uv-0.6.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b56fa88951fab3bc7164255d844de9ad048e6a04a95f1c2774637e06889efe6", size = 16539261 },
+ { url = "https://files.pythonhosted.org/packages/cb/cc/1e00721e749ecc4d2cf8d233a9f9585108afcd62e3da4a2784f15d1f3a65/uv-0.6.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f3b3f21b2385545f499f6cc21f44eac3bbb0f6cb98fbf9c6d3e58db186c8a41", size = 20699878 },
+ { url = "https://files.pythonhosted.org/packages/66/32/ad9944c9716360c82fb62516aca72bdeaedf7991483383f3a06734cb2cf4/uv-0.6.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15dae245979add192c4845947da1a9141f95c19403d1c0d75019182e6882e7d4", size = 16249288 },
+ { url = "https://files.pythonhosted.org/packages/80/7a/cad1a0382182b923f881ec9b592106abb0df55be42384bfbe3694fb5b243/uv-0.6.5-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:26a90e69d6438de2ec03ab452cc48d1cb375249c6b6980f4ed177f324a5ad8b3", size = 15156024 },
+ { url = "https://files.pythonhosted.org/packages/f5/f1/a9721cf48232ee4d0871c74dbc7ff5e2e90fb79aab4096c76f12eb3ba453/uv-0.6.5-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:776500595ff7cda1ffa5a76dd3ff9de3819f1e26c493938cbdc20c1ab766b2eb", size = 15213625 },
+ { url = "https://files.pythonhosted.org/packages/cc/a4/02a2e4eb1a09b87086c92ebeb9953dca427b54ec113be2e0445abc850b3c/uv-0.6.5-py3-none-musllinux_1_1_i686.whl", hash = "sha256:6210fe6ef6a0ae3dc618611fcc8ada4e620fea5172fb8a9c50d3a59b6915b023", size = 15558969 },
+ { url = "https://files.pythonhosted.org/packages/78/c1/5a3a0905a630a5b99b7b3cc1a400bcb65401e1a325bf43ced50e8bd007a2/uv-0.6.5-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d47b4adffcdbe30bd678c7670e63c671b8b34a667898501e588f2e7cbce34656", size = 16345448 },
+ { url = "https://files.pythonhosted.org/packages/36/80/721c0621f14071462bc8420b16c4cba3c9c066f5775eab7dc56d9b559c30/uv-0.6.5-py3-none-win32.whl", hash = "sha256:23aa8e8ca7795f54f6cf0f0fbd0aaf7b26bf4aae42f8c10643bcba6d42485a3f", size = 15657842 },
+ { url = "https://files.pythonhosted.org/packages/09/d1/751610f12b99ab6166887554cd98d376f22ffb6fdc69e57676735e781ccc/uv-0.6.5-py3-none-win_amd64.whl", hash = "sha256:5323e9219a519c6553111820a8c54588d426380404a208b23cf4c3265bc87ec6", size = 16958031 },
+ { url = "https://files.pythonhosted.org/packages/0d/63/0080e1618c936297001a3da462dd83f73391bacf7857ed7b327518d57f93/uv-0.6.5-py3-none-win_arm64.whl", hash = "sha256:a481254f63240023239ecec80cd690dec05875e248eb4b9d7f66957b017798b1", size = 15811982 },
]
[[package]]
@@ -4805,16 +4668,16 @@ wheels = [
[[package]]
name = "virtualenv"
-version = "20.29.2"
+version = "20.29.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
{ name = "filelock" },
{ name = "platformdirs" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f1/88/dacc875dd54a8acadb4bcbfd4e3e86df8be75527116c91d8f9784f5e9cab/virtualenv-20.29.2.tar.gz", hash = "sha256:fdaabebf6d03b5ba83ae0a02cfe96f48a716f4fae556461d180825866f75b728", size = 4320272 }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/9c/57d19fa093bcf5ac61a48087dd44d00655f85421d1aa9722f8befbf3f40a/virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac", size = 4320280 }
wheels = [
- { url = "https://files.pythonhosted.org/packages/93/fa/849483d56773ae29740ae70043ad88e068f98a6401aa819b5d6bee604683/virtualenv-20.29.2-py3-none-any.whl", hash = "sha256:febddfc3d1ea571bdb1dc0f98d7b45d24def7428214d4fb73cc486c9568cce6a", size = 4301478 },
+ { url = "https://files.pythonhosted.org/packages/c2/eb/c6db6e3001d58c6a9e67c74bb7b4206767caa3ccc28c6b9eaf4c23fb4e34/virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170", size = 4301458 },
]
[[package]]
@@ -4891,33 +4754,33 @@ wheels = [
[[package]]
name = "websockets"
-version = "15.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/2e/7a/8bc4d15af7ff30f7ba34f9a172063bfcee9f5001d7cef04bee800a658f33/websockets-15.0.tar.gz", hash = "sha256:ca36151289a15b39d8d683fd8b7abbe26fc50be311066c5f8dcf3cb8cee107ab", size = 175574 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/22/1e/92c4547d7b2a93f848aedaf37e9054111bc00dc11bff4385ca3f80dbb412/websockets-15.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cccc18077acd34c8072578394ec79563664b1c205f7a86a62e94fafc7b59001f", size = 174709 },
- { url = "https://files.pythonhosted.org/packages/9f/37/eae4830a28061ba552516d84478686b637cd9e57d6a90b45ad69e89cb0af/websockets-15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4c22992e24f12de340ca5f824121a5b3e1a37ad4360b4e1aaf15e9d1c42582d", size = 172372 },
- { url = "https://files.pythonhosted.org/packages/46/2f/b409f8b8aa9328d5a47f7a301a43319d540d70cf036d1e6443675978a988/websockets-15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1206432cc6c644f6fc03374b264c5ff805d980311563202ed7fef91a38906276", size = 172607 },
- { url = "https://files.pythonhosted.org/packages/d6/81/d7e2e4542d4b4df849b0110df1b1f94f2647b71ab4b65d672090931ad2bb/websockets-15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d3cc75ef3e17490042c47e0523aee1bcc4eacd2482796107fd59dd1100a44bc", size = 182422 },
- { url = "https://files.pythonhosted.org/packages/b6/91/3b303160938d123eea97f58be363f7dbec76e8c59d587e07b5bc257dd584/websockets-15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b89504227a5311610e4be16071465885a0a3d6b0e82e305ef46d9b064ce5fb72", size = 181362 },
- { url = "https://files.pythonhosted.org/packages/f2/8b/df6807f1ca339c567aba9a7ab03bfdb9a833f625e8d2b4fc7529e4c701de/websockets-15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56e3efe356416bc67a8e093607315951d76910f03d2b3ad49c4ade9207bf710d", size = 181787 },
- { url = "https://files.pythonhosted.org/packages/21/37/e6d3d5ebb0ebcaf98ae84904205c9dcaf3e0fe93e65000b9f08631ed7309/websockets-15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f2205cdb444a42a7919690238fb5979a05439b9dbb73dd47c863d39640d85ab", size = 182058 },
- { url = "https://files.pythonhosted.org/packages/c9/df/6aca296f2be4c638ad20908bb3d7c94ce7afc8d9b4b2b0780d1fc59b359c/websockets-15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aea01f40995fa0945c020228ab919b8dfc93fc8a9f2d3d705ab5b793f32d9e99", size = 181434 },
- { url = "https://files.pythonhosted.org/packages/88/f1/75717a982bab39bbe63c83f9df0e7753e5c98bab907eb4fb5d97fe5c8c11/websockets-15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9f8e33747b1332db11cf7fcf4a9512bef9748cb5eb4d3f7fbc8c30d75dc6ffc", size = 181431 },
- { url = "https://files.pythonhosted.org/packages/e7/15/cee9e63ed9ac5bfc1a3ae8fc6c02c41745023c21eed622eef142d8fdd749/websockets-15.0-cp312-cp312-win32.whl", hash = "sha256:32e02a2d83f4954aa8c17e03fe8ec6962432c39aca4be7e8ee346b05a3476904", size = 175678 },
- { url = "https://files.pythonhosted.org/packages/4e/00/993974c60f40faabb725d4dbae8b072ef73b4c4454bd261d3b1d34ace41f/websockets-15.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc02b159b65c05f2ed9ec176b715b66918a674bd4daed48a9a7a590dd4be1aa", size = 176119 },
- { url = "https://files.pythonhosted.org/packages/12/23/be28dc1023707ac51768f848d28a946443041a348ee3a54abdf9f6283372/websockets-15.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d2244d8ab24374bed366f9ff206e2619345f9cd7fe79aad5225f53faac28b6b1", size = 174714 },
- { url = "https://files.pythonhosted.org/packages/8f/ff/02b5e9fbb078e7666bf3d25c18c69b499747a12f3e7f2776063ef3fb7061/websockets-15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3a302241fbe825a3e4fe07666a2ab513edfdc6d43ce24b79691b45115273b5e7", size = 172374 },
- { url = "https://files.pythonhosted.org/packages/8e/61/901c8d4698e0477eff4c3c664d53f898b601fa83af4ce81946650ec2a4cb/websockets-15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:10552fed076757a70ba2c18edcbc601c7637b30cdfe8c24b65171e824c7d6081", size = 172605 },
- { url = "https://files.pythonhosted.org/packages/d2/4b/dc47601a80dff317aecf8da7b4ab278d11d3494b2c373b493e4887561f90/websockets-15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c53f97032b87a406044a1c33d1e9290cc38b117a8062e8a8b285175d7e2f99c9", size = 182380 },
- { url = "https://files.pythonhosted.org/packages/83/f7/b155d2b38f05ed47a0b8de1c9ea245fcd7fc625d89f35a37eccba34b42de/websockets-15.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1caf951110ca757b8ad9c4974f5cac7b8413004d2f29707e4d03a65d54cedf2b", size = 181325 },
- { url = "https://files.pythonhosted.org/packages/d3/ff/040a20c01c294695cac0e361caf86f33347acc38f164f6d2be1d3e007d9f/websockets-15.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bf1ab71f9f23b0a1d52ec1682a3907e0c208c12fef9c3e99d2b80166b17905f", size = 181763 },
- { url = "https://files.pythonhosted.org/packages/cb/6a/af23e93678fda8341ac8775e85123425e45c608389d3514863c702896ea5/websockets-15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bfcd3acc1a81f106abac6afd42327d2cf1e77ec905ae11dc1d9142a006a496b6", size = 182097 },
- { url = "https://files.pythonhosted.org/packages/7e/3e/1069e159c30129dc03c01513b5830237e576f47cedb888777dd885cae583/websockets-15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8c5c8e1bac05ef3c23722e591ef4f688f528235e2480f157a9cfe0a19081375", size = 181485 },
- { url = "https://files.pythonhosted.org/packages/9a/a7/c91c47103f1cd941b576bbc452601e9e01f67d5c9be3e0a9abe726491ab5/websockets-15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:86bfb52a9cfbcc09aba2b71388b0a20ea5c52b6517c0b2e316222435a8cdab72", size = 181466 },
- { url = "https://files.pythonhosted.org/packages/16/32/a4ca6e3d56c24aac46b0cf5c03b841379f6409d07fc2044b244f90f54105/websockets-15.0-cp313-cp313-win32.whl", hash = "sha256:26ba70fed190708551c19a360f9d7eca8e8c0f615d19a574292b7229e0ae324c", size = 175673 },
- { url = "https://files.pythonhosted.org/packages/c0/31/25a417a23e985b61ffa5544f9facfe4a118cb64d664c886f1244a8baeca5/websockets-15.0-cp313-cp313-win_amd64.whl", hash = "sha256:ae721bcc8e69846af00b7a77a220614d9b2ec57d25017a6bbde3a99473e41ce8", size = 176115 },
- { url = "https://files.pythonhosted.org/packages/e8/b2/31eec524b53f01cd8343f10a8e429730c52c1849941d1f530f8253b6d934/websockets-15.0-py3-none-any.whl", hash = "sha256:51ffd53c53c4442415b613497a34ba0aa7b99ac07f1e4a62db5dcd640ae6c3c3", size = 169023 },
+version = "15.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437 },
+ { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096 },
+ { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332 },
+ { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152 },
+ { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096 },
+ { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523 },
+ { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790 },
+ { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165 },
+ { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160 },
+ { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395 },
+ { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841 },
+ { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440 },
+ { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098 },
+ { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329 },
+ { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111 },
+ { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054 },
+ { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496 },
+ { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829 },
+ { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217 },
+ { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195 },
+ { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393 },
+ { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837 },
+ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 },
]
[[package]]