fix(localagent): test against the latest stable SDK

This commit is contained in:
huanghuoguoguo
2026-10-28 20:31:31 +08:00
parent 0608408352
commit b21d150c4c
9 changed files with 39 additions and 28 deletions
@@ -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
+4 -4
View File
@@ -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
+2 -2
View File
@@ -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
+6 -3
View File
@@ -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:
+4 -4
View File
@@ -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)` 时,插件会明确拒绝准备文件工具。
## 当前边界
+1 -1
View File
@@ -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]
+1 -1
View File
@@ -1,2 +1,2 @@
langbot-plugin>=0.7.18,<0.8.0
langbot-plugin>=0.7.18
pydantic>=2.0.0
@@ -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())
+4 -4
View File
@@ -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]]