From b21d150c4c9bd4f3eec4ef2b8183523fa2066510 Mon Sep 17 00:00:00 2001 From: huanghuoguoguo <60681390+huanghuoguoguo@users.noreply.github.com> Date: Wed, 28 Oct 2026 20:31:31 +0800 Subject: [PATCH] fix(localagent): test against the latest stable SDK --- .../workflows/plugins-local-agent-tests.yml | 8 ++++---- .github/workflows/plugins-runner-tests.yml | 8 ++++---- ARCHITECTURE.md | 4 ++-- plugins/RELEASING.md | 9 ++++++--- plugins/Runner/LocalAgent/README.md | 8 ++++---- plugins/Runner/LocalAgent/pyproject.toml | 2 +- plugins/Runner/LocalAgent/requirements.txt | 2 +- .../tests/test_sdk_dependency_contract.py | 18 +++++++++++++----- plugins/Runner/LocalAgent/uv.lock | 8 ++++---- 9 files changed, 39 insertions(+), 28 deletions(-) diff --git a/.github/workflows/plugins-local-agent-tests.yml b/.github/workflows/plugins-local-agent-tests.yml index 52e3e525f..dd14a31d6 100644 --- a/.github/workflows/plugins-local-agent-tests.yml +++ b/.github/workflows/plugins-local-agent-tests.yml @@ -38,12 +38,12 @@ jobs: run: | printf 'UV_PROJECT_ENVIRONMENT=%s/local-agent-venv\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" - - name: Install dependencies - run: uv sync --locked --extra dev + - name: Install dependencies with the latest stable SDK + run: uv sync --extra dev --upgrade-package langbot-plugin working-directory: plugins/Runner/LocalAgent - - name: Verify explicit-export SDK contract - run: uv run --no-sync python -c 'from inspect import signature; from langbot_plugin.api.entities.builtin.runner.context import RunnerContext; assert "paths" in signature(RunnerContext.export_box_files).parameters' + - name: Report SDK version and verify explicit-export contract + run: uv run --no-sync python -c 'from importlib.metadata import version; print("langbot-plugin", version("langbot-plugin")); from inspect import signature; from langbot_plugin.api.entities.builtin.runner.context import RunnerContext; assert "paths" in signature(RunnerContext.export_box_files).parameters' working-directory: plugins/Runner/LocalAgent - name: Ruff check diff --git a/.github/workflows/plugins-runner-tests.yml b/.github/workflows/plugins-runner-tests.yml index 35638f39e..fb1042934 100644 --- a/.github/workflows/plugins-runner-tests.yml +++ b/.github/workflows/plugins-runner-tests.yml @@ -51,11 +51,11 @@ jobs: -r acp-agent-runner/requirements.txt -r claude-code-agent/requirements.txt -r codex-agent/requirements.txt pytest pyyaml packaging "$RUNNER_TEMP/coding-074/bin/python" -c 'from importlib.metadata import version; assert version("langbot-plugin") == "0.7.4"' printf 'CODING_RUNNER_TEST_PYTHON=%s/coding-074/bin/python\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" - - name: Prepare isolated LocalAgent explicit-export SDK environment + - name: Prepare isolated LocalAgent environment with the latest stable SDK run: | - UV_PROJECT_ENVIRONMENT="$RUNNER_TEMP/localagent-074" uv sync --project LocalAgent --locked --extra dev - "$RUNNER_TEMP/localagent-074/bin/python" -c 'from inspect import signature; from langbot_plugin.api.entities.builtin.runner.context import RunnerContext; assert "paths" in signature(RunnerContext.export_box_files).parameters' - printf 'LOCALAGENT_TEST_PYTHON=%s/localagent-074/bin/python\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" + UV_PROJECT_ENVIRONMENT="$RUNNER_TEMP/localagent-latest" uv sync --project LocalAgent --extra dev --upgrade-package langbot-plugin + "$RUNNER_TEMP/localagent-latest/bin/python" -c 'from importlib.metadata import version; print("langbot-plugin", version("langbot-plugin")); from inspect import signature; from langbot_plugin.api.entities.builtin.runner.context import RunnerContext; assert "paths" in signature(RunnerContext.export_box_files).parameters' + printf 'LOCALAGENT_TEST_PYTHON=%s/localagent-latest/bin/python\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" # Preserve the external Runner lint scope; LocalAgent has its own Ruff config. # RunnerDemo did not have a Ruff gate before consolidation. - name: Ruff check diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index d90d83e51..02b59f1ea 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -189,8 +189,8 @@ the run. Output export requires explicit normalized absolute sandbox file paths opaque handles scoped to that run. The selected files are validated as one batch before registration; successful export removes only those files, and cleanup failure is a warning with accepted handles retained. Writing an outbox file alone -does not deliver it. Core and LocalAgent currently pin SDK PR #180's exact commit -until a release includes the selected-path API. +does not deliver it. Core and Plugin Runtime must provide the selected-path API; +LocalAgent CI verifies this contract against the latest stable published SDK. `message.completed.file_ids` attaches explicitly exported files to Pipeline output; Agents send them explicitly with `ctx.reply_files()`, subject to event reply permission. The Pipeline wrapper never scans a Box. Binding ends with the run; the reusable Box diff --git a/plugins/RELEASING.md b/plugins/RELEASING.md index 5e7e5e931..de50ae53d 100644 --- a/plugins/RELEASING.md +++ b/plugins/RELEASING.md @@ -8,9 +8,12 @@ or use a Core release event to publish plugins. Choose one plugin from [catalog.json](catalog.json). Run its tests in its own environment following its README. CI entrypoints are the five `plugins-*-tests` -workflows and the catalog workflow in `../.github/workflows/`; they preserve the existing -published SDK baselines and independent interpreters. LocalAgent and the Runner -test harness intentionally use different SDK pins. Do not merge their lockfiles. +workflows and the catalog workflow in `../.github/workflows/`, using independent +interpreters. LocalAgent requires `langbot-plugin>=0.7.18`; its CI installs the +latest stable PyPI SDK with `uv sync --extra dev --upgrade-package langbot-plugin` +and reports the installed version before checking contracts and tests. Its lockfile +is a resolution snapshot. The other Runner tests retain their published SDK pins; +keep these environments and lockfiles separate. From the repository root: diff --git a/plugins/Runner/LocalAgent/README.md b/plugins/Runner/LocalAgent/README.md index fae574ec5..075920106 100644 --- a/plugins/Runner/LocalAgent/README.md +++ b/plugins/Runner/LocalAgent/README.md @@ -8,7 +8,7 @@ Local Agent 是 LangBot 官方的进程内运行器。它在 LangBot 插件进 ## SDK 兼容性 -LocalAgent 0.2.3 使用 `langbot-plugin>=0.7.18,<0.8.0`,允许同一 0.7 系列的稳定补丁更新,不再精确锁定单个 SDK 版本。测试环境的 `uv.lock` 仍固定已验证版本以保证可复现;插件包的 `requirements.txt` 与项目声明使用相同的兼容范围。跨 0.8 系列升级需要单独验证。 +LocalAgent 要求 `langbot-plugin>=0.7.18`,不设版本上限。插件包与项目声明保持一致;CI 每次安装 PyPI 最新稳定版 SDK,记录实际版本并验证契约和测试。`uv.lock` 保存最近一次解析结果,CI 会更新其中的 SDK 选择。 ## 主要能力 @@ -87,12 +87,12 @@ Local Agent 不按固定对话轮数截断历史,而是按最终 provider 消 ## 开发与测试 ```bash -uv sync --dev +uv sync --extra dev --upgrade-package langbot-plugin uv run --no-sync pytest -q uv run --no-sync ruff check . ``` -本地联调需要使用包含 Runner Protocol v1 的 LangBot Plugin SDK。若 LangBot 固定的 PyPI 版本缺少新实体,请先安装工作区中的本地 SDK,并使用 `uv run --no-sync` 启动,避免同步过程覆盖 editable 安装。 +测试使用已发布的 SDK。若导入或契约检查失败,先核对实际安装版本和 PyPI 发布内容;不要用本地 SDK 源码替代发布包掩盖兼容问题。 ## 文件交付 @@ -100,7 +100,7 @@ uv run --no-sync ruff check . 清理警告不代表导出失败,不应因此重复交付。Core 接收后的平台发送失败会终止运行,避免重新生成或重发可能已经送达的文件。流式文字已发出时不会被撤回。 -此分支配合 LangBot #2641 和 SDK #180,开发与 CI 用 `uv.lock` 固定 SDK 提交 `b300830b0e5339e7989be237efa811bedf761d55`。已发布的 SDK 0.7.4/0.7.13 不包含新的路径参数;Core 和 Plugin Runtime 必须使用配套版本,插件会在旧 SDK 上明确拒绝准备文件工具。待对应 SDK 发布后,由维护者统一更新发布版本依赖。 +最低 SDK 版本已包含显式路径导出 API。Core 和 Plugin Runtime 也须提供配套契约;缺少 `export_box_files(paths)` 时,插件会明确拒绝准备文件工具。 ## 当前边界 diff --git a/plugins/Runner/LocalAgent/pyproject.toml b/plugins/Runner/LocalAgent/pyproject.toml index 67c1041e0..9c8bc0653 100644 --- a/plugins/Runner/LocalAgent/pyproject.toml +++ b/plugins/Runner/LocalAgent/pyproject.toml @@ -5,7 +5,7 @@ description = "Built-in agent with model fallback, tools, and knowledge retrieva requires-python = ">=3.11,<4.0" dependencies = [ "pydantic>=2.0.0", - "langbot-plugin>=0.7.18,<0.8.0", + "langbot-plugin>=0.7.18", ] [project.optional-dependencies] diff --git a/plugins/Runner/LocalAgent/requirements.txt b/plugins/Runner/LocalAgent/requirements.txt index 1130156db..4aa78f3b2 100644 --- a/plugins/Runner/LocalAgent/requirements.txt +++ b/plugins/Runner/LocalAgent/requirements.txt @@ -1,2 +1,2 @@ -langbot-plugin>=0.7.18,<0.8.0 +langbot-plugin>=0.7.18 pydantic>=2.0.0 diff --git a/plugins/Runner/LocalAgent/tests/test_sdk_dependency_contract.py b/plugins/Runner/LocalAgent/tests/test_sdk_dependency_contract.py index b7a5cd282..24912c52a 100644 --- a/plugins/Runner/LocalAgent/tests/test_sdk_dependency_contract.py +++ b/plugins/Runner/LocalAgent/tests/test_sdk_dependency_contract.py @@ -1,9 +1,11 @@ import tomllib +from importlib.metadata import version from pathlib import Path import pytest import yaml from packaging.requirements import Requirement +from packaging.version import Version PLUGIN_ROOT = Path(__file__).resolve().parents[1] @@ -20,19 +22,25 @@ def _sdk_requirements(): def test_project_and_packaged_sdk_constraints_match(): project, packaged = _sdk_requirements() assert project.specifier == packaged.specifier - assert str(project.specifier) == "<0.8.0,>=0.7.18" + assert str(project.specifier) == ">=0.7.18" -@pytest.mark.parametrize("version", ["0.7.18", "0.7.19", "0.7.99"]) -def test_sdk_constraints_accept_compatible_stable_patches(version): +@pytest.mark.parametrize("version", ["0.7.18", "0.7.19", "0.8.0", "1.0.0"]) +def test_sdk_constraints_accept_stable_releases_from_minimum(version): assert all(requirement.specifier.contains(version) for requirement in _sdk_requirements()) -@pytest.mark.parametrize("version", ["0.7.16", "0.7.17", "0.8.0", "1.0.0"]) -def test_sdk_constraints_reject_unverified_versions(version): +@pytest.mark.parametrize("version", ["0.7.16", "0.7.17"]) +def test_sdk_constraints_reject_older_releases(version): assert not any(requirement.specifier.contains(version) for requirement in _sdk_requirements()) +def test_installed_sdk_is_a_stable_release_matching_requirements(): + installed = Version(version("langbot-plugin")) + assert not installed.is_prerelease + assert all(requirement.specifier.contains(installed) for requirement in _sdk_requirements()) + + def test_manifest_and_project_versions_match(): project = tomllib.loads((PLUGIN_ROOT / "pyproject.toml").read_text()) manifest = yaml.safe_load((PLUGIN_ROOT / "manifest.yaml").read_text()) diff --git a/plugins/Runner/LocalAgent/uv.lock b/plugins/Runner/LocalAgent/uv.lock index 4163b0818..e64af540c 100644 --- a/plugins/Runner/LocalAgent/uv.lock +++ b/plugins/Runner/LocalAgent/uv.lock @@ -472,7 +472,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "langbot-plugin", specifier = ">=0.7.18,<0.8.0" }, + { name = "langbot-plugin", specifier = ">=0.7.18" }, { name = "pydantic", specifier = ">=2.0.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, @@ -482,7 +482,7 @@ provides-extras = ["dev"] [[package]] name = "langbot-plugin" -version = "0.7.18" +version = "0.7.19" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiofiles" }, @@ -503,9 +503,9 @@ dependencies = [ { name = "watchdog" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/da/aee1601e50d2c584357356b1abe502f529b66a0b155cab63b3e4cbde0839/langbot_plugin-0.7.18.tar.gz", hash = "sha256:71b8fda2c6836e107341cdf9dbb519ef9ba7b4625d88480058b5d794f6e3e256", size = 725344, upload-time = "2026-10-26T03:52:09.718Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/23/ffce65a9c333a6545b47d8364bbd5083f6517292b95bdfffc7ac87b702c3/langbot_plugin-0.7.19.tar.gz", hash = "sha256:62a972592e2160dee963ecbfc4276719e43178e137273ea29af1a43152b8353e", size = 749638, upload-time = "2026-10-28T10:52:04.63Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/5e/98b4daa0a84ba5cb80374b4b323946f62263ceec3e580b459f261abe29a7/langbot_plugin-0.7.18-py3-none-any.whl", hash = "sha256:897c1f5b291bd36acd9716e951a8cd70601e266d17f88c8b66a21426c9602f01", size = 460608, upload-time = "2026-10-26T03:52:07.673Z" }, + { url = "https://files.pythonhosted.org/packages/4c/99/e32e004c6869a40e63276440de3b31a8d22bf89a22a1ae1133f0233e55e3/langbot_plugin-0.7.19-py3-none-any.whl", hash = "sha256:a94037c766e0f4bc2f108edfa0e1c075fc28d480217b6794a652d2532be5ca1f", size = 474676, upload-time = "2026-10-28T10:52:02.788Z" }, ] [[package]]