diff --git a/docs/multi-tenant/cloud-v2-pending-verification.md b/docs/multi-tenant/cloud-v2-pending-verification.md index 908005ba4..7b90856b5 100644 --- a/docs/multi-tenant/cloud-v2-pending-verification.md +++ b/docs/multi-tenant/cloud-v2-pending-verification.md @@ -28,7 +28,7 @@ - PostgreSQL 16 + RLS 的 1,000 Workspace 真实启动测试,以及 5,000 Workspace 三代替换合成探针已通过。 - Core 已精确钉住 Plugin SDK 提交 - `87d903e9b7c4e518ce066c89f65bbde4de825fc5`。最终验证必须使用包含该提交的 + `1d65ed301a6afc52150a998043f73cd6032c8162`。最终验证必须使用包含该提交的 Core、Plugin Runtime 和 Box Runtime 镜像,不能混用旧 SDK。 - 独立资源复核已经移除 Cloud MCP 每会话 5 秒查询执行绑定的轮询,改由签名目录 投影提交后向一个合并回收任务发布代次变化;工具与资源调用前后仍使用数据库 diff --git a/docs/multi-tenant/runtime-resource-audit-2026-07-28.md b/docs/multi-tenant/runtime-resource-audit-2026-07-28.md index 81a59229a..cbf9fc8f2 100644 --- a/docs/multi-tenant/runtime-resource-audit-2026-07-28.md +++ b/docs/multi-tenant/runtime-resource-audit-2026-07-28.md @@ -17,7 +17,7 @@ 1. 在最终 Cloud 部署权限和 cgroup 拓扑下重复 nsjail、namespace 和 delegated cgroup v2 的 CPU、内存、swap、PID、文件句柄验证。本轮一次性 Linux 容器已经证明代码路径可工作,但普通容器和仅 `--privileged` 的 private cgroup namespace 都不满足条件。 2. 为 Cloud Box 提供并验证硬文件系统 quota provider。普通 nsjail bind mount 不能证明总字节数和 inode 硬配额,当前严格 readiness 按设计会失败关闭。 3. 使用最终生产配置分布继续做容量测试,并据此确定单实例 Workspace placement 上限。本轮真实 PostgreSQL 16 + RLS 启动测试已经覆盖 1,000 个各带 Provider、三类 Model、Bot、Pipeline、KnowledgeBase、MCP 和 Plugin setting 的 Workspace,启动加载耗时和 SQL 次数保持线性;5,000 Workspace 的合成三代替换探针也证明旧运行时会释放。仓库已新增可同时采集 Core/Plugin/Box HTTP、进程树和 cgroup v2 的 24 小时门禁工具,并在受 CPU、memory、swap、PID 硬限制的 Linux 容器中完成短时自检;但最终生产候选拓扑的 24 小时运行仍未执行。测试中的 fake adapter/requester/Plugin handler 仍不能替代真实平台 SDK、外部连接池和插件进程的容量数据;合法活跃租户本身仍会线性占用内存。 -SDK 已先行发布到分支提交 `87d903e9b7c4e518ce066c89f65bbde4de825fc5`,本提交集中的 LangBot +SDK 已先行发布到分支提交 `1d65ed301a6afc52150a998043f73cd6032c8162`,本提交集中的 LangBot `pyproject.toml` 和 `uv.lock` 已精确钉住该提交。最终镜像仍需按待验证清单记录并核对实际安装版本。 ## 覆盖范围 diff --git a/pyproject.toml b/pyproject.toml index fee880288..d1e588fa8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,7 @@ dependencies = [ "chromadb>=1.0.0,<2.0.0", "qdrant-client (>=1.15.1,<2.0.0)", "pyseekdb==1.1.0.post3", - "langbot-plugin @ git+https://github.com/langbot-app/langbot-plugin-sdk.git@87d903e9b7c4e518ce066c89f65bbde4de825fc5", + "langbot-plugin @ git+https://github.com/langbot-app/langbot-plugin-sdk.git@1d65ed301a6afc52150a998043f73cd6032c8162", "asyncpg>=0.30.0", "line-bot-sdk>=3.19.0", "matrix-nio>=0.25.2", diff --git a/tests/unit_tests/workspace/test_workspace_collaboration.py b/tests/unit_tests/workspace/test_workspace_collaboration.py index b11f1975c..a9a79c42b 100644 --- a/tests/unit_tests/workspace/test_workspace_collaboration.py +++ b/tests/unit_tests/workspace/test_workspace_collaboration.py @@ -163,9 +163,7 @@ async def test_invitation_rejects_owner_role_and_email_mismatch(collaboration_co async def test_expired_invitation_is_inspectable_before_periodic_cleanup_deletes_it(collaboration_context): service, _, session_factory, _, workspace, owner_membership = collaboration_context - created = await service.create_invitation( - workspace.uuid, owner_membership, 'expired@example.com', 'viewer' - ) + created = await service.create_invitation(workspace.uuid, owner_membership, 'expired@example.com', 'viewer') async with session_factory.begin() as session: invitation = await session.get(WorkspaceInvitation, created.invitation.uuid) invitation.expires_at = service._utcnow() - datetime.timedelta(minutes=1) @@ -245,18 +243,14 @@ async def test_cloud_member_listing_opens_workspace_uow_when_request_scope_has_c mode=SimpleNamespace(value='cloud_runtime'), current_session=lambda: None, tenant_uow=tenant_uow, - require_current_session=lambda: (_ for _ in ()).throw( - AssertionError('list_members must open a Workspace UoW') - ), + require_current_session=lambda: (_ for _ in ()).throw(AssertionError('list_members must open a Workspace UoW')), get_db_engine=lambda: session_factory.kw['bind'], ) members = await service.list_members(workspace.uuid, owner_membership) assert entered_workspaces == [workspace.uuid] - assert [(member.email, member.membership.role) for member in members] == [ - ('owner@example.com', 'owner') - ] + assert [(member.email, member.membership.role) for member in members] == [('owner@example.com', 'owner')] async def test_cloud_directory_requires_explicit_selector_and_allows_core_membership_management( diff --git a/uv.lock b/uv.lock index 2c4bdb5c0..a23277e25 100644 --- a/uv.lock +++ b/uv.lock @@ -2116,7 +2116,7 @@ requires-dist = [ { name = "ebooklib", specifier = ">=0.18" }, { name = "gewechat-client", specifier = ">=0.1.5" }, { name = "html2text", specifier = ">=2024.2.26" }, - { name = "langbot-plugin", git = "https://github.com/langbot-app/langbot-plugin-sdk.git?rev=87d903e9b7c4e518ce066c89f65bbde4de825fc5" }, + { name = "langbot-plugin", git = "https://github.com/langbot-app/langbot-plugin-sdk.git?rev=1d65ed301a6afc52150a998043f73cd6032c8162" }, { name = "langchain", specifier = ">=1.3.9" }, { name = "langchain-core", specifier = ">=1.3.3" }, { name = "langchain-text-splitters", specifier = ">=1.1.2" }, @@ -2183,7 +2183,7 @@ dev = [ [[package]] name = "langbot-plugin" version = "0.4.18" -source = { git = "https://github.com/langbot-app/langbot-plugin-sdk.git?rev=87d903e9b7c4e518ce066c89f65bbde4de825fc5#87d903e9b7c4e518ce066c89f65bbde4de825fc5" } +source = { git = "https://github.com/langbot-app/langbot-plugin-sdk.git?rev=1d65ed301a6afc52150a998043f73cd6032c8162#1d65ed301a6afc52150a998043f73cd6032c8162" } dependencies = [ { name = "aiofiles" }, { name = "aiohttp" },