Skip to content

Fix core dependency constraint blocking compatible plugin upgrades#6422

Open
he-yufeng wants to merge 2 commits intoAstrBotDevs:masterfrom
he-yufeng:fix/core-constraint-allow-upgrade
Open

Fix core dependency constraint blocking compatible plugin upgrades#6422
he-yufeng wants to merge 2 commits intoAstrBotDevs:masterfrom
he-yufeng:fix/core-constraint-allow-upgrade

Conversation

@he-yufeng
Copy link
Copy Markdown
Contributor

@he-yufeng he-yufeng commented Mar 16, 2026

Problem

The core dependency protection mechanism pins dependencies to the exact installed version using ==:

constraints.append(f"{name}=={installed[name]}")  # e.g. aiosqlite==0.21.0

This prevents plugins from installing newer compatible versions. For example, a plugin requiring aiosqlite>=0.22.1 fails with:

DependencyConflictError: 检测到核心依赖版本保护冲突。
冲突详情: aiosqlite>=0.22.1 vs (constraint) aiosqlite==0.21.0

Even though 0.22.1 >= 0.21.0 and is backward-compatible.

Fix

Change == to >= in the constraint generation:

constraints.append(f"{name}>={installed[name]}")  # e.g. aiosqlite>=0.21.0

This preserves the protection against downgrades (plugins can't install older versions than what's running) while allowing compatible upgrades.

Fixes #6420

Summary by Sourcery

Bug Fixes:

  • Allow plugins to install newer compatible versions of core dependencies by changing exact version pinning to a minimum-version constraint.

The core constraints mechanism pins dependencies to the exact installed
version (e.g. aiosqlite==0.21.0), which prevents plugins from pulling
in newer compatible versions. A plugin requiring aiosqlite>=0.22.1
fails even though 0.22.1 is backward-compatible with the core's
>=0.21.0 requirement.

Change the constraint from == to >= so that:
- Downgrades below the installed version are still blocked (protection)
- Plugins can require newer versions when compatible (flexibility)

Fixes AstrBotDevs#6420
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@auto-assign auto-assign bot requested review from Fridemn and Soulter March 16, 2026 05:32
@dosubot dosubot bot added the size:XS This PR changes 0-9 lines, ignoring generated files. label Mar 16, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Changing == to >= broadens the allowed range considerably; consider whether you also need an upper bound (e.g. < next major) or another mechanism to guard against potentially breaking future major versions being pulled in by plugins.
  • The bare except Exception: continue around constraint generation can hide unexpected issues; if feasible, narrow the exception type or at least log the exception so that silent failures in constraint building are observable.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Changing `==` to `>=` broadens the allowed range considerably; consider whether you also need an upper bound (e.g. `<` next major) or another mechanism to guard against potentially breaking future major versions being pulled in by plugins.
- The bare `except Exception: continue` around constraint generation can hide unexpected issues; if feasible, narrow the exception type or at least log the exception so that silent failures in constraint building are observable.

## Individual Comments

### Comment 1
<location path="astrbot/core/utils/core_constraints.py" line_range="83-85" />
<code_context>
             name = canonicalize_distribution_name(req.name)
             if name in installed:
-                constraints.append(f"{name}=={installed[name]}")
+                # Use >= instead of == so plugins can pull in newer compatible
+                # versions while still preventing downgrades below what's installed.
+                constraints.append(f"{name}>={installed[name]}")
         except Exception:
             continue
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Relaxing from == to >= may undermine reproducibility and allow incompatible major upgrades.

Switching from an exact pin to a lower bound means different environments may resolve to different versions over time, which weakens reproducibility and can allow breaking major upgrades (e.g., `1.5` installed but `>=1.5` allows `2.x`). If the goal is to avoid downgrades while allowing safe upgrades, consider either a bounded range like `>=installed,<next_major` or keeping strict pins here and letting plugins declare more permissive requirements. Also verify whether this change is consistent with any expectations of deterministic resolution for this function.

Suggested implementation:

```python
            if name in installed:
                # Use a bounded range (>=installed,<next_major) so that:
                # - we prevent downgrades below the currently installed version
                # - we avoid unbounded major upgrades that may be incompatible
                installed_version = installed[name]
                try:
                    major = int(str(installed_version).split(".")[0])
                except (ValueError, TypeError):
                    # If we cannot parse a simple major version, fall back to
                    # an exact pin to preserve deterministic behavior.
                    constraints.append(f"{name}=={installed_version}")
                else:
                    next_major = major + 1
                    constraints.append(f"{name}>={installed_version},<{next_major}")

```

Depending on the rest of the codebase, you may also want to:
1. Update or add tests that assert the constraint format, e.g. installed `1.5.2` leads to `>=1.5.2,<2`.
2. Ensure any documentation or comments describing this function’s determinism/reproducibility are updated to reflect the bounded-range behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/utils/core_constraints.py Outdated
@dosubot dosubot bot added area:core The bug / feature is about astrbot's core, backend feature:plugin The bug / feature is about AstrBot plugin system. labels Mar 16, 2026
@LIghtJUNction
Copy link
Copy Markdown
Member

测试了吗

Instead of unbounded >=, use >=installed,<next_major so plugins
can upgrade within the same major version but won't accidentally
pull in breaking major releases (e.g. 1.5 installed won't allow 2.x).
Falls back to exact pin if major version can't be parsed.
@he-yufeng
Copy link
Copy Markdown
Contributor Author

Tested locally — here's what I verified:

from packaging.requirements import Requirement

# simulate installed versions
installed = {"aiohttp": "3.9.1", "pydantic": "2.5.0", "numpy": "0.9.3"}

for ver in installed.values():
    try:
        next_major = int(str(ver).split(".")[0]) + 1
    except (ValueError, TypeError):
        print(f"==fallback")
    else:
        print(f">={ver},<{next_major}")

# Output:
# >=3.9.1,<4
# >=2.5.0,<3
# >=0.9.3,<1

Also updated to use bounded >=installed,<next_major instead of plain >= — see latest commit. This way plugins can still upgrade within the same major but won't pull in breaking 2.x when 1.x is installed.

@Soulter Soulter force-pushed the master branch 2 times, most recently from faf411f to 0068960 Compare April 19, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend feature:plugin The bug / feature is about AstrBot plugin system. size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 核心依赖版本保护机制过于严格,导致插件依赖冲突

2 participants