Skip to content

feat: ee agent sandbox support#38528

Open
wylswz wants to merge 8 commits into
mainfrom
feat/ee-agent-sandbox
Open

feat: ee agent sandbox support#38528
wylswz wants to merge 8 commits into
mainfrom
feat/ee-agent-sandbox

Conversation

@wylswz

@wylswz wylswz commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Summary

Screenshots

Before After
... ...

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint && make type-check (backend) and cd web && pnpm exec vp staged (frontend) to appease the lint gods

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Pyrefly Type Coverage

Metric Base PR Delta
Type coverage 52.45% 52.45% 0.00%
Strict coverage 51.97% 51.97% 0.00%
Typed symbols 32,393 32,393 0
Untyped symbols 29,640 29,640 0
Modules 2982 2982 0

@dosubot

dosubot Bot commented Jul 8, 2026

Copy link
Copy Markdown

📄 Knowledge review

✏️ Suggested updates

1 page suggestion needs review.

Page Library Status
Dify Agent Server 模块分析 (Commit 55f95dbc) dify 🟡 Review
📝 Dify Agent Server 模块分析 (Commit 55f95db)
@@ -340,102 +340,94 @@
 
 #### Shell 适配器协议层
 
-**Shell 适配器架构**(`dify-agent/src/dify_agent/adapters/shell/`):引入了提供者无关的 shell 层抽象,支持当前的 shellctl 后端和未来的第三方 shell 提供者。
-
-**协议层次结构**(`protocols.py`):
-
-- **`ShellProvisionProtocol`**:创建、重新连接和销毁 shell 环境
-  - `provision() -> ShellHandle`:分配新的 shell 环境
-  - `reattach(descriptor: ShellEnvironmentDescriptor) -> ShellHandle`:从持久化的描述符重建活跃句柄而不重新分配
-  - `destroy(handle: ShellHandle) -> None`:拆除环境
-
-- **`ShellHandle`**:对已配置 shell 环境的活跃引用
-  - `descriptor() -> ShellEnvironmentDescriptor`:返回可序列化的工作区标识种子
-  - `get_executor() -> ShellExecutorProtocol`:返回命令执行器
-  - `get_file_transfer() -> ShellFileTransferProtocol`:返回文件传输处理器
-
-- **`ShellEnvironmentDescriptor`**:可序列化的工作区标识
-  - `workspace_cwd: str`:工作区目录路径
-  - `session_id: str`:会话标识符
-
-- **`ShellExecutorProtocol`**:在已配置环境内运行命令
-  - `execute(command, cwd, env) -> ShellExecutionHandle`:启动命令
-  - `wait(handle) -> ShellExecutionResult`:等待命令完成
-
-- **`ShellExecutionHandle`**:对已启动 shell 命令的不透明引用
-  - `job_id: str`:后端定义的作业标识符
-
-- **`ShellExecutionResult`**:已完成的 shell 命令结果
-  - `stdout() -> str`:标准输出
-  - `stderr() -> str`:标准错误
-  - `exit_code() -> int | None`:退出代码
-  - `truncated() -> bool`:输出是否被截断
-
-- **可选协议**:
-  - **`SupportsShellInput`**:`input(handle, text) -> ShellExecutionResult`
-  - **`SupportsShellInterrupt`**:`interrupt(handle) -> ShellExecutionResult`
+**Shell 适配器架构**(`dify-agent/src/dify_agent/adapters/shell/`):引入了提供者无关的 shell 层抽象,支持 shellctl 后端和 enterprise 沙箱后端。
+
+**核心协议**(`protocols.py`):
+
+- **`ShellProviderProtocol`**:统一的 shell 提供者接口
+  - `create() -> ShellResourceProtocol`:创建新沙箱
+  - `attach(sandbox_id) -> ShellResourceProtocol`:重新连接到现有沙箱
+
+- **`ShellResourceProtocol`**:活跃 shell 资源的统一接口
+  - `commands -> ShellCommandProtocol`:命令执行接口
+  - `files -> ShellFileTransferProtocol`:文件传输接口
+  - `sandbox_id -> str | None`:可选的沙箱标识符(用于持久化)
+  - `suspend() -> None`:暂停资源而不销毁沙箱
+  - `delete() -> None`:永久销毁沙箱
+
+- **`SandboxExpiredError`**:当 `attach()` 目标沙箱已过期时抛出
+
+- **`ShellCommandProtocol`**:命令执行接口
+  - `run(command, timeout, cwd, env) -> RemoteCommandResult`:同步执行命令
+  - 提供 `wait()`、`input()`、`interrupt()` 等可选操作
 
 - **`ShellFileTransferProtocol`**:文件传输操作
-  - `upload(content, remote_path) -> None`:上传字节到工作区
-  - `download(remote_path) -> bytes`:从工作区下载字节
+  - `upload(content, remote_path, cwd) -> None`:上传字节到工作区
+  - `download(remote_path, cwd) -> bytes`:从工作区下载字节
 
 **Shellctl 实现**(`shellctl.py`):
 
-- **`ShellctlProvisioner`**:实现 `ShellProvisionProtocol`,管理 shellctl 工作区
-  - 使用 `client_factory: ShellctlClientFactory` 为每个环境创建新客户端
-  - `provision()` 生成随机会话 ID 并创建 `~/workspace/<session_id>` 目录
-  - `reattach()` 为现有工作区构建新客户端(用于快照恢复)
-  - `destroy()` 运行 `rm -rf` 清理脚本并关闭客户端
-
-- **`ShellctlHandle`**:shellctl 工作区的活跃引用
-  - 持有 `client: ShellctlClientProtocol`、`workspace_cwd: str` 和 `session_id: str`
-  - `get_executor()` 返回绑定到该工作区的新 `ShellctlExecutor`
-  - `get_file_transfer()` 返回新 `ShellctlFileTransfer`
-
-- **`ShellctlExecutor`**:在 shellctl 工作区内执行命令
-  - 有状态:跟踪每个启动作业的分页偏移量和输出部分
-  - `execute()` 启动命令并记录初始结果
-  - `wait()` 排空输出窗口直到完成(最多 64 个窗口),然后删除作业
-  - 实现可选的 `input()` 和 `interrupt()` 功能
-
-- **`ShellctlExecutionResult`**:已完成的 shellctl 命令结果
-  - shellctl 将 stderr 合并到单个输出流中,因此 `stderr()` 始终为空
-  - `truncated()` 在最终窗口仍有未读输出时返回 `True`
-
-- **`ShellctlFileTransfer`**:基于 base64 的文件传输
-  - `upload()` 将 base64 编码的内容通过管道传输到 `base64 -d`
-  - `download()` 在帧标记之间发出文件的 base64 并提取有效负载
+- **`ShellctlProvider`**:实现 `ShellProviderProtocol`,管理 shellctl 会话
+  - `create()` 和 `attach()` 返回同一 `ShellctlResource` 实例
+  - shellctl 无独立沙箱生命周期,`sandbox_id` 为 shellctl entrypoint URL
+  - `suspend()` 和 `delete()` 仅关闭 HTTP 客户端,不影响 shellctl 服务器
+
+- **`ShellctlResource`**:shellctl 工作区的活跃引用
+  - 持有 `client: ShellctlClientProtocol`、`commands` 和 `files` 适配器
+  - `suspend()` 和 `delete()` 行为相同:关闭 HTTP 客户端
+  - 由于 shellctl 是长期运行进程,工作区和文件系统在客户端关闭后仍保留
+
+- **`ShellctlCommands`**:实现 `ShellCommandProtocol`,封装 shellctl 命令执行
+- **`ShellctlFileTransfer`**:实现 `ShellFileTransferProtocol`,基于 base64 的文件传输
+
+**Enterprise 实现**(`enterprise/enterprise.py`,PR #38528 新增):
+
+- **`EnterpriseGatewayClient`**:控制平面 HTTP 客户端
+  - `create_sandbox(tenant_id, template) -> {"sandboxId": ..., "status": ...}`:调用 `POST /v1/sandboxes` 创建新沙箱 pod
+  - `delete_sandbox(sandbox_id) -> None`:调用 `DELETE /v1/sandboxes/{sandboxId}` 销毁沙箱
+
+- **`EnterpriseShellProvider`**:实现 `ShellProviderProtocol`
+  - `create()` 通过 gateway 创建新沙箱,返回 `EnterpriseResource`
+  - `attach(sandbox_id)` 构建指向现有沙箱的资源,通过 gateway proxy 验证沙箱存活
+  - 若沙箱已过期(gateway 返回 404 或 "expired" 错误),抛出 `SandboxExpiredError`
+
+- **`EnterpriseResource`**:enterprise 沙箱的活跃引用
+  - 持有 `gateway`(控制平面)、`shellctl_client`(数据平面 proxy)和 `sandbox_id`
+  - `suspend()` 关闭 shellctl 和 gateway 客户端,沙箱 pod 保留
+  - `delete()` 调用 `gateway.delete_sandbox()` 销毁沙箱 pod,然后关闭客户端
+  - 数据平面通过 gateway 的 `/proxy/{sandboxId}` 路由访问沙箱内的 shellctl
 
 **工厂模式**(`factory.py`):
 
-- **`create_shell_provisioner(settings)`**:基于 `DIFY_AGENT_SHELL_PROVIDER` 选择提供者
-  - 当前仅支持 `"shellctl"` 提供者
-  - 要求为 shellctl 设置 `DIFY_AGENT_SHELLCTL_ENTRYPOINT`
-  - 返回 `ShellProvisionProtocol` 实现
+- **`create_shell_provider(settings)`**:基于 `DIFY_AGENT_SHELL_PROVIDER` 选择提供者
+  - `"shellctl"`:返回 `ShellctlProvider`,需设置 `DIFY_AGENT_SHELLCTL_ENTRYPOINT`
+  - `"enterprise"`:返回 `EnterpriseShellProvider`,需设置 `DIFY_AGENT_ENTERPRISE_SANDBOX_GATEWAY_ENDPOINT`
+  - 返回 `ShellProviderProtocol` 实现
 
 **配置**(`config.py`):
 
 - **`ShellAdapterSettings`**:shell 适配器环境变量
-  - `shell_provider: str`(默认 `"shellctl"`)
-  - `shellctl_entrypoint: str | None`
-  - `shellctl_auth_token: str | None`
-
-**DifyShellLayer 变更**:
-
-- 初始化:`from_config_with_settings` 现在接受单个 `shell_provisioner: ShellProvisionProtocol` 参数,而不是 `shellctl_entrypoint` 和 `shellctl_client_factory`
-- 层在 `resource_context()` 活跃时保持活跃的 `ShellctlHandle`(而不是原始的 `ShellctlClient`)
-- 工作区生命周期委托给 `ShellProvisionProtocol`:
-  - `on_context_create()` 调用 `provision()` 分配新工作区
-  - `on_context_resume()` 调用 `reattach()` 从描述符重建句柄
-  - `on_context_delete()` 调用 `destroy()` 拆除工作区
-- 内部工作区分配逻辑(`_allocate_workspace`、`_workspace_mkdir_script`、`_workspace_cleanup_script`)已移除
-- 会话 ID 验证放宽:现在仅拒绝 `/`、`..` 或单引号(不再要求精确的 5+2 十六进制格式)
-- 新增 `environment_descriptor()` 方法返回 `ShellEnvironmentDescriptor`,用于桥接到 shell 适配器
-
-**RemoteCommandResult 变更**:从数据类中移除了几个字段,因为它们是调用者不使用的内部 shellctl 分页详细信息:
-
-- **已移除**:`job_id`、`done`、`offset`、`output_path`
-- **保留**:`status`、`exit_code`、`output`、`truncated`
+  - `shell_provider: Literal["shellctl", "enterprise"]`(默认 `"shellctl"`)
+  - `shellctl_entrypoint: str | None`、`shellctl_auth_token: str | None`
+  - `enterprise_sandbox_gateway_endpoint: str | None`、`enterprise_sandbox_gateway_auth_token: str | None`
+  - `@model_validator` 验证:shellctl 提供者需 `shellctl_entrypoint`,enterprise 提供者需 `enterprise_sandbox_gateway_endpoint`
+
+**DifyShellLayer 沙箱生命周期(PR #38528 变更)**:
+
+- **runtime_state 扩展**:`DifyShellRuntimeState` 新增 `sandbox_id: str | None` 字段
+- **resource_context() 行为**:
+  - 首次运行(`sandbox_id` 为空):调用 `shell_provider.create()`,持久化返回的 `sandbox_id`
+  - 后续运行:调用 `shell_provider.attach(sandbox_id)` 重新连接
+  - 若 attach 抛出 `SandboxExpiredError`,错误传播给调用者(用户必须开始新会话)
+- **退出策略**:
+  - 默认(`suspend`):调用 `resource.suspend()`,沙箱保留
+  - 删除(`on_context_delete` 触发):调用 `resource.delete()`,沙箱永久销毁
+  - 层使用 `_resource_should_delete` 标志控制退出时调用哪个方法
+- **compositor_factory 变更**:
+  - `create_default_layer_providers()` 签名变化:
+    - **已移除**:`shellctl_entrypoint`、`shellctl_auth_token` 参数
+    - **新增**:`shell_provider: ShellProviderProtocol | None` 参数
+  - shell provider 现由运行时边界(`ServerSettings.build_shell_provider()`)构建并传入
 
 #### 8. Dify Drive Layer
 
@@ -1090,6 +1082,16 @@
 | `DIFY_AGENT_PLUGIN_DAEMON_MAX_KEEPALIVE_CONNECTIONS` | `20` | 最大空闲 Keep-Alive 连接数 |
 | `DIFY_AGENT_PLUGIN_DAEMON_KEEPALIVE_EXPIRY` | `30.0` | 空闲连接的 Keep-Alive 过期时间(秒) |
 
+#### Shell layer
+
+| 环境变量 | 默认值 | 说明 |
+|---|---|---|
+| `DIFY_AGENT_SHELL_PROVIDER` | `"shellctl"` | Shell 后端:`"shellctl"`(本地)或 `"enterprise"`(企业沙箱)|
+| `DIFY_AGENT_SHELLCTL_ENTRYPOINT` | `null` | shellctl 服务器基础 URL(当 `shell_provider` 为 `"shellctl"` 时必需)|
+| `DIFY_AGENT_SHELLCTL_AUTH_TOKEN` | `null` | 可选的 shellctl 服务器 bearer token |
+| `DIFY_AGENT_ENTERPRISE_SANDBOX_GATEWAY_ENDPOINT` | `null` | enterprise 沙箱 gateway 端点(当 `shell_provider` 为 `"enterprise"` 时必需)|
+| `DIFY_AGENT_ENTERPRISE_SANDBOX_GATEWAY_AUTH_TOKEN` | `null` | 可选的 `X-Inner-Api-Key` 认证令牌,发送给 enterprise gateway |
+
 #### Agent Stub 配置
 
 | 环境变量 | 默认值 | 说明 |

Accept · Edit · Decline


Leave Feedback Ask Dosu about dify

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-07-08 03:23:29.259110817 +0000
+++ /tmp/pyrefly_pr.txt	2026-07-08 03:23:20.485036757 +0000
@@ -558,34 +558,30 @@
    --> tests/integration_tests/model_runtime/__mock/plugin_model.py:235:9
 ERROR `unpatch` may be uninitialized [unbound-name]
   --> tests/integration_tests/plugin/__mock/http.py:67:9
-ERROR Argument `scoped_session[flask_sqlalchemy.session.Session]` is not assignable to parameter `session` with type `sqlalchemy.orm.session.Session` in function `services.plugin.plugin_permission_service.PluginPermissionService.change_permission` [bad-argument-type]
-  --> tests/integration_tests/services/plugin/test_plugin_lifecycle.py:50:21
-ERROR Argument `scoped_session[flask_sqlalchemy.session.Session]` is not assignable to parameter `session` with type `sqlalchemy.orm.session.Session` in function `services.plugin.plugin_permission_service.PluginPermissionService.change_permission` [bad-argument-type]
-  --> tests/integration_tests/services/plugin/test_plugin_lifecycle.py:64:21
-ERROR Argument `scoped_session[flask_sqlalchemy.session.Session]` is not assignable to parameter `session` with type `sqlalchemy.orm.session.Session` in function `services.plugin.plugin_permission_service.PluginPermissionService.change_permission` [bad-argument-type]
-  --> tests/integration_tests/services/plugin/test_plugin_lifecycle.py:70:21
 ERROR Argument `FakeArchiveStorage` is not assignable to parameter `storage` with type `ArchiveStorage | None` in function `services.retention.workflow_run.archive_paid_plan_workflow_run.WorkflowRunArchiver._archive_bundle` [bad-argument-type]
    --> tests/integration_tests/services/retention/test_workflow_run_archiver.py:412:56
 ERROR Argument `FakeArchiveStorage` is not assignable to parameter `storage` with type `ArchiveStorage | None` in function `services.retention.workflow_run.archive_paid_plan_workflow_run.WorkflowRunArchiver._archive_bundle` [bad-argument-type]
    --> tests/integration_tests/services/retention/test_workflow_run_archiver.py:437:60
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:261:59
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:231:59
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:288:59
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:257:59
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:298:59
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:267:59
+ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.snapshot_workflow_run` [bad-argument-type]
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:269:49
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:318:63
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:287:63
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:361:63
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:330:63
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:402:63
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:371:63
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:424:59
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:393:59
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:451:59
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:419:59
 ERROR Argument `_stub_resolver._Resolver` is not assignable to parameter `binding_resolver` with type `WorkflowAgentBindingResolver | None` in function `services.workflow.node_output_inspector_service.NodeOutputInspectorService.__init__` [bad-argument-type]
-   --> tests/integration_tests/services/test_node_output_inspector_service.py:501:63
+   --> tests/integration_tests/services/test_node_output_inspector_service.py:468:63
 ERROR Object of class `TestWorkflowDraftVariableServiceResetVariable` has no attribute `_test_user_id` [missing-attribute]
    --> tests/integration_tests/services/test_workflow_draft_variable_service.py:626:21
 ERROR Object of class `TestWorkflowDraftVariableServiceResetVariable` has no attribute `_test_user_id` [missing-attribute]
@@ -615,7 +611,7 @@
 ERROR Object of class `object` has no attribute `strip` [missing-attribute]
   --> tests/integration_tests/workflow/test_response_stream_filter_integration.py:75:37
 ERROR Argument value `Literal[0]` violates Pydantic `ge` constraint `Literal[1]` for field `page` [bad-argument-type]
-   --> tests/test_containers_integration_tests/controllers/console/app/test_app_apis.py:671:51
+   --> tests/test_containers_integration_tests/controllers/console/app/test_app_apis.py:667:51
 ERROR Object of class `RequestError` has no attribute `response` [missing-attribute]
    --> tests/test_containers_integration_tests/controllers/console/auth/test_oauth.py:247:9
 ERROR Object of class `RequestError` has no attribute `response` [missing-attribute]
@@ -631,19 +627,19 @@
 ERROR `in` is not supported between `Literal['webapp-logo']` and `None` [not-iterable]
    --> tests/test_containers_integration_tests/controllers/web/test_site.py:136:16
 ERROR Argument `SimpleNamespace` is not assignable to parameter `webapp_settings` with type `WebAppSettings | None` in function `controllers.web.wraps._validate_user_accessibility` [bad-argument-type]
-  --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:77:33
+  --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:75:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `webapp_settings` with type `WebAppSettings | None` in function `controllers.web.wraps._validate_user_accessibility` [bad-argument-type]
-   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:100:33
+  --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:98:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `webapp_settings` with type `WebAppSettings | None` in function `controllers.web.wraps._validate_user_accessibility` [bad-argument-type]
-   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:112:33
+   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:110:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `webapp_settings` with type `WebAppSettings | None` in function `controllers.web.wraps._validate_user_accessibility` [bad-argument-type]
-   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:130:33
+   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:128:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `webapp_settings` with type `WebAppSettings | None` in function `controllers.web.wraps._validate_user_accessibility` [bad-argument-type]
-   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:148:33
+   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:146:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `webapp_settings` with type `WebAppSettings | None` in function `controllers.web.wraps._validate_user_accessibility` [bad-argument-type]
-   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:165:29
+   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:163:29
 ERROR Argument `SimpleNamespace` is not assignable to parameter `webapp_settings` with type `WebAppSettings | None` in function `controllers.web.wraps._validate_user_accessibility` [bad-argument-type]
-   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:182:33
+   --> tests/test_containers_integration_tests/controllers/web/test_wraps.py:180:33
 ERROR Attribute `file_service` of class `TestPauseStatePersistenceLayerTestContainers` is a read-only descriptor with no `__set__` and cannot be set [read-only]
    --> tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py:156:9
 ERROR Attribute `workflow_run_service` of class `TestPauseStatePersistenceLayerTestContainers` is a read-only descriptor with no `__set__` and cannot be set [read-only]
@@ -781,7 +777,7 @@
 ERROR Generator function should return `Generator` [bad-return]
   --> tests/test_containers_integration_tests/repositories/test_workflow_run_repository.py:89:56
 ERROR `None` is not subscriptable [unsupported-operation]
-   --> tests/test_containers_integration_tests/services/auth/test_api_key_auth_service.py:202:16
+   --> tests/test_containers_integration_tests/services/auth/test_api_key_auth_service.py:196:16
 ERROR Could not find name `Session` [unknown-name]
   --> tests/test_containers_integration_tests/services/plugin/test_plugin_parameter_service.py:54:37
 ERROR Could not find name `Session` [unknown-name]
@@ -793,25 +789,25 @@
 ERROR Object of class `NoneType` has no attribute `open_id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_account_service.py:558:16
 ERROR Object of class `Tenant` has no attribute `role` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:1503:16
+    --> tests/test_containers_integration_tests/services/test_account_service.py:1501:16
 ERROR Argument `list[str]` is not assignable to parameter `roles` with type `list[TenantAccountRole]` in function `services.account_service.TenantService.has_roles` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:1700:45
+    --> tests/test_containers_integration_tests/services/test_account_service.py:1698:45
 ERROR Object of class `NoneType` has no attribute `role` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2072:16
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2070:16
 ERROR Object of class `NoneType` has no attribute `role` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2130:16
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2128:16
 ERROR Object of class `NoneType` has no attribute `role` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2131:16
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2129:16
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2285:16
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2283:16
 ERROR Argument `dict[str, str | dict[str, bool]]` is not assignable to parameter `value` with type `TenantCustomConfigDict` in function `models.account.Tenant.custom_config_dict` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2463:37
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2461:37
 ERROR TypedDict `TenantCustomConfigDict` does not have key `theme` [bad-typed-dict-key]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2471:33
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2469:33
 ERROR TypedDict `TenantCustomConfigDict` does not have key `language` [bad-typed-dict-key]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2472:33
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2470:33
 ERROR TypedDict `TenantCustomConfigDict` does not have key `feature_flags` [bad-typed-dict-key]
-    --> tests/test_containers_integration_tests/services/test_account_service.py:2473:33
+    --> tests/test_containers_integration_tests/services/test_account_service.py:2471:33
 ERROR Argument `dict[str, AppMode | str] | dict[str, str]` is not assignable to parameter `args` with type `AdvancedPromptTemplateArgs` in function `services.advanced_prompt_template_service.AdvancedPromptTemplateService.get_prompt` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/test_advanced_prompt_template_service.py:718:63
 ERROR Argument `dict[str, AppMode | str]` is not assignable to parameter `args` with type `AdvancedPromptTemplateArgs` in function `services.advanced_prompt_template_service.AdvancedPromptTemplateService.get_prompt` [bad-argument-type]
@@ -833,45 +829,57 @@
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_annotation_service.py:107:81
 ERROR Argument `dict[str, str | Unknown | None]` is not assignable to parameter `args` with type `InsertAnnotationArgs` in function `services.annotation_service.AppAnnotationService.insert_app_annotation_directly` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_annotation_service.py:247:17
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:244:65
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.annotation_service.AppAnnotationService.update_app_annotation_directly` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:292:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.annotation_service.AppAnnotationService.delete_app_annotation` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:580:94
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.annotation_service.AppAnnotationService.delete_app_annotation` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:613:65
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.annotation_service.AppAnnotationService.delete_app_annotation` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:629:17
 ERROR Object of class `str` has no attribute `decode` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_annotation_service.py:762:33
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:708:33
 ERROR Object of class `int` has no attribute `lower` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_annotation_service.py:996:27
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:927:27
 ERROR Object of class `int` has no attribute `lower` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1044:27
+   --> tests/test_containers_integration_tests/services/test_annotation_service.py:973:27
 ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `id` [bad-typed-dict-key]
-    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1086:23
+    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1015:23
 ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `score_threshold` [bad-typed-dict-key]
-    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1087:23
+    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1016:23
 ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `embedding_model` [bad-typed-dict-key]
-    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1088:23
+    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1017:23
 ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `embedding_model` [bad-typed-dict-key]
-    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1089:23
+    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1018:23
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.annotation_service.AppAnnotationService.update_app_annotation_directly` [bad-argument-type]
+    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1251:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.annotation_service.AppAnnotationService.delete_app_annotation` [bad-argument-type]
+    --> tests/test_containers_integration_tests/services/test_annotation_service.py:1322:94
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:226:17
+   --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:226:45
 ERROR Argument `None` is not assignable to parameter `value` with type `SQLCoreOperations[str] | str` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:424:39
 ERROR Argument `None` is not assignable to parameter `value` with type `SQLCoreOperations[str] | str` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:431:34
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:448:72
+   --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:448:100
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:535:17
+   --> tests/test_containers_integration_tests/services/test_api_based_extension_service.py:534:85
 ERROR Argument `Literal['app']` is not assignable to parameter `value` with type `ApiTokenType | SQLCoreOperations[ApiTokenType]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
   --> tests/test_containers_integration_tests/services/test_api_token_service.py:28:26
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:165:42
 ERROR Argument `Literal['simple']` is not assignable to parameter `prompt_type` with type `PromptType | SQLCoreOperations[PromptType]` in function `models.model.AppModelConfig.__init__` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:931:25
+   --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:929:25
 ERROR Argument `Literal['workflow']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:954:20
+   --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:952:20
 ERROR Argument `Literal['workflow']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:989:20
+   --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:987:20
 ERROR Argument `Literal['workflow']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:1032:20
+    --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:1028:20
 ERROR Argument `list[SimpleNamespace]` is not assignable to parameter `dsl_dependencies` with type `list[PluginDependency]` in function `services.app_dsl_service.AppDslService.get_leaked_dependencies` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:1326:73
+    --> tests/test_containers_integration_tests/services/test_app_dsl_service.py:1314:73
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_app_generate_service.py:190:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
@@ -879,15 +887,15 @@
 ERROR Argument `Literal['invalid_mode']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/test_app_generate_service.py:568:20
 ERROR Argument `dict[str, dict[str, str]]` is not assignable to parameter `args` with type `LoopNodeRunPayload` in function `services.app_generate_service.AppGenerateService.generate_single_loop` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:829:18
+   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:811:64
 ERROR Argument `dict[str, dict[str, str]]` is not assignable to parameter `args` with type `LoopNodeRunPayload` in function `services.app_generate_service.AppGenerateService.generate_single_loop` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:861:18
+   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:838:64
 ERROR Argument `dict[str, dict[str, str]]` is not assignable to parameter `args` with type `LoopNodeRunPayload` in function `services.app_generate_service.AppGenerateService.generate_single_loop` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:892:22
+   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:864:68
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:944:23
+   --> tests/test_containers_integration_tests/services/test_app_generate_service.py:914:23
 ERROR Argument `Literal['agent-chat']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_app_generate_service.py:1080:20
+    --> tests/test_containers_integration_tests/services/test_app_generate_service.py:1050:20
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
   --> tests/test_containers_integration_tests/services/test_app_service.py:87:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
@@ -904,134 +912,172 @@
    --> tests/test_containers_integration_tests/services/test_app_service.py:237:36
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_app_service.py:242:68
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:242:87
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_app_service.py:252:37
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_app_service.py:277:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:283:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:282:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:289:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:287:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:307:25
+   --> tests/test_containers_integration_tests/services/test_app_service.py:304:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:304:82
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:318:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:315:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:317:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:331:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:328:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:330:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:365:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:362:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:371:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:367:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:387:25
+   --> tests/test_containers_integration_tests/services/test_app_service.py:382:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:382:82
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:398:25
+   --> tests/test_containers_integration_tests/services/test_app_service.py:393:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:393:82
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:427:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:422:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:433:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:427:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:439:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:432:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:445:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:437:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:468:25
+   --> tests/test_containers_integration_tests/services/test_app_service.py:459:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_starred_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:459:89
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:481:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:472:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_starred_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:474:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:494:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:485:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_starred_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:487:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:547:43
+   --> tests/test_containers_integration_tests/services/test_app_service.py:538:43
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:549:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:539:49
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:554:25
+   --> tests/test_containers_integration_tests/services/test_app_service.py:543:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:543:82
 ERROR Object of class `NoneType` has no attribute `items` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:556:20
+   --> tests/test_containers_integration_tests/services/test_app_service.py:545:20
 ERROR Cannot index into `object` [bad-index]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:557:16
+   --> tests/test_containers_integration_tests/services/test_app_service.py:546:16
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:561:25
+   --> tests/test_containers_integration_tests/services/test_app_service.py:550:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:550:95
 ERROR Object of class `NoneType` has no attribute `items` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:563:20
+   --> tests/test_containers_integration_tests/services/test_app_service.py:552:20
 ERROR Cannot index into `object` [bad-index]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:564:26
+   --> tests/test_containers_integration_tests/services/test_app_service.py:553:26
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:569:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:558:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:560:13
 ERROR Object of class `NoneType` has no attribute `items` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:573:20
+   --> tests/test_containers_integration_tests/services/test_app_service.py:562:20
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:613:32
+   --> tests/test_containers_integration_tests/services/test_app_service.py:602:32
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:622:32
+   --> tests/test_containers_integration_tests/services/test_app_service.py:611:32
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:626:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:615:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:617:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:668:38
+   --> tests/test_containers_integration_tests/services/test_app_service.py:657:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:677:72
+   --> tests/test_containers_integration_tests/services/test_app_service.py:666:72
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:666:91
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:681:24
+   --> tests/test_containers_integration_tests/services/test_app_service.py:670:24
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:695:72
+   --> tests/test_containers_integration_tests/services/test_app_service.py:684:72
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+   --> tests/test_containers_integration_tests/services/test_app_service.py:684:91
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:731:38
+   --> tests/test_containers_integration_tests/services/test_app_service.py:720:38
 ERROR Argument `dict[str, bool | str]` is not assignable to parameter `args` with type `AppService.ArgsDict` in function `services.app_service.AppService.update_app` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:755:55
+   --> tests/test_containers_integration_tests/services/test_app_service.py:744:55
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:792:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:781:13
 ERROR Missing required key `max_active_requests` for TypedDict `ArgsDict` [bad-typed-dict-key]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:812:17
+   --> tests/test_containers_integration_tests/services/test_app_service.py:800:17
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:847:13
+   --> tests/test_containers_integration_tests/services/test_app_service.py:834:13
 ERROR Missing required key `max_active_requests` for TypedDict `ArgsDict` [bad-typed-dict-key]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:868:21
+   --> tests/test_containers_integration_tests/services/test_app_service.py:854:21
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:910:38
+   --> tests/test_containers_integration_tests/services/test_app_service.py:895:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_app_service.py:964:38
+   --> tests/test_containers_integration_tests/services/test_app_service.py:949:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1027:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1010:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1087:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1070:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1147:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1130:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1198:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1181:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1211:70
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1194:70
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1250:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1233:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1273:70
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1256:70
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1310:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1293:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1349:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1332:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1389:38
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1372:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1470:13
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1453:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1486:13
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1468:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1502:13
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1483:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1519:13
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1499:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1536:25
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1515:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1515:94
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1546:13
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1525:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1527:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1558:13
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1537:13
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1539:13
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1569:25
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1548:25
+ERROR Argument `Session` is not assignable to parameter `session` with type `scoped_session[Unknown]` in function `services.app_service.AppService.get_paginate_apps` [bad-argument-type]
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1548:94
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `services.app_service.AppService.get_app_meta` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1606:41
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1585:41
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `services.app_service.AppService.get_app_meta` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_app_service.py:1620:41
+    --> tests/test_containers_integration_tests/services/test_app_service.py:1599:41
 ERROR Argument `Literal['owner']` is not assignable to parameter `role` with type `SQLCoreOperations[TenantAccountRole] | TenantAccountRole` in function `models.account.TenantAccountJoin.__init__` [bad-argument-type]
-  --> tests/test_containers_integration_tests/services/test_conversation_service_variables.py:46:18
+  --> tests/test_containers_integration_tests/services/test_conversation_service_variables.py:47:18
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
   --> tests/test_containers_integration_tests/services/test_dataset_permission_service.py:39:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
@@ -1161,7 +1207,7 @@
 ERROR Argument `Literal['llm']` is not assignable to parameter `model_type` with type `ModelType | SQLCoreOperations[ModelType]` in function `models.provider.LoadBalancingModelConfig.__init__` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/test_model_load_balancing_service.py:301:24
 ERROR Argument `Literal['llm']` is not assignable to parameter `model_type` with type `ModelType | SQLCoreOperations[ModelType]` in function `models.provider.LoadBalancingModelConfig.__init__` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/test_model_load_balancing_service.py:428:24
+   --> tests/test_containers_integration_tests/services/test_model_load_balancing_service.py:420:24
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
   --> tests/test_containers_integration_tests/services/test_model_provider_service.py:55:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
@@ -1177,7 +1223,7 @@
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
   --> tests/test_containers_integration_tests/services/test_ops_service.py:60:13
 ERROR Argument `dict[str, Any] | dict[Unknown, Unknown] | object | None` is not assignable to parameter `tracing_config` with type `SQLCoreOperations[dict[str, Any] | None] | dict[str, Any] | None` in function `models.model.TraceAppConfig.__init__` [bad-argument-type]
-  --> tests/test_containers_integration_tests/services/test_ops_service.py:86:28
+  --> tests/test_containers_integration_tests/services/test_ops_service.py:85:28
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
   --> tests/test_containers_integration_tests/services/test_saved_message_service.py:89:38
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
@@ -1235,7 +1281,7 @@
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
   --> tests/test_containers_integration_tests/services/test_webhook_service_relationships.py:40:72
 ERROR Class `WebhookServiceRelationshipFactory` has no class attribute `_read_cache` [missing-attribute]
-   --> tests/test_containers_integration_tests/services/test_webhook_service_relationships.py:517:26
+   --> tests/test_containers_integration_tests/services/test_webhook_service_relationships.py:516:26
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_workflow_app_service.py:102:38
 ERROR Argument `SimpleNamespace` is not assignable to parameter `log` with type `WorkflowAppLog` in function `services.workflow_app_service.LogView.__init__` [bad-argument-type]
@@ -1279,9 +1325,9 @@
 ERROR Argument `Literal['succeeded']` is not assignable to parameter `value` with type `SQLCoreOperations[WorkflowNodeExecutionStatus] | WorkflowNodeExecutionStatus` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/test_workflow_service.py:174:33
 ERROR Argument `Literal['invalid_mode']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_workflow_service.py:1302:20
+    --> tests/test_containers_integration_tests/services/test_workflow_service.py:1293:20
 ERROR Argument `dict[str, int]` is not assignable to parameter `metadata` with type `Mapping[WorkflowNodeExecutionMetadataKey, Any]` in function `graphon.node_events.base.NodeRunResult.__init__` [bad-argument-type]
-    --> tests/test_containers_integration_tests/services/test_workflow_service.py:1656:26
+    --> tests/test_containers_integration_tests/services/test_workflow_service.py:1647:26
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
   --> tests/test_containers_integration_tests/services/test_workspace_service.py:53:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
@@ -1465,11 +1511,11 @@
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
    --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:116:20
 ERROR Argument `AppModelConfig | None` is not assignable to parameter `app_model_config` with type `AppModelConfig` in function `services.workflow.workflow_converter.WorkflowConverter.convert_app_model_config_to_workflow` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:328:30
+   --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:326:30
 ERROR `None` is not subscriptable [unsupported-operation]
-   --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:651:16
+   --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:646:16
 ERROR `None` is not subscriptable [unsupported-operation]
-   --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:659:16
+   --> tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py:654:16
 ERROR Argument `Literal['owner']` is not assignable to parameter `role` with type `SQLCoreOperations[TenantAccountRole] | TenantAccountRole` in function `models.account.TenantAccountJoin.__init__` [bad-argument-type]
   --> tests/test_containers_integration_tests/services/workflow/test_workflow_deletion.py:38:18
 ERROR Cannot instantiate `DifyAPISQLAlchemyWorkflowNodeExecutionRepository` because the following members are abstract: `save`, `save_execution_data`, `get_by_workflow_execution` [bad-instantiation]
@@ -1885,87 +1931,87 @@
 ERROR No attribute `MethodView` in module `builtins` [missing-attribute]
  --> tests/unit_tests/controllers/common/test_fields.py:8:5
 ERROR Cannot index into `object` [bad-index]
-   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:715:12
+   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:703:12
 ERROR Cannot index into `object` [bad-index]
-   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:716:12
+   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:704:12
 ERROR Cannot index into `object` [bad-index]
-   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:717:12
+   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:705:12
 ERROR Cannot index into `object` [bad-index]
-   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:718:12
+   --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:706:12
 ERROR `in` is not supported between `Literal['Incorrect API key provided']` and `None` [not-iterable]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1471:12
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1458:12
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account` in function `controllers.console.app.completion._create_build_chat_finalization_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1557:26
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1544:26
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.completion._create_build_chat_finalization_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1558:23
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1545:23
 ERROR Argument `test_drain_streaming_generate_response_returns_on_message_end.ClosableResponse` is not assignable to parameter `response` with type `Generator[str] | RateLimitGenerator` in function `controllers.console.app.completion._drain_streaming_generate_response` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1605:69
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1592:69
 ERROR Argument `Iterator[Any]` is not assignable to parameter `response` with type `Generator[str] | RateLimitGenerator` in function `controllers.console.app.completion._drain_streaming_generate_response` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1613:66
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1600:66
 ERROR Argument `Iterator[Any]` is not assignable to parameter `response` with type `Generator[str] | RateLimitGenerator` in function `controllers.console.app.completion._drain_streaming_generate_response` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1620:66
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1607:66
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account` in function `controllers.console.app.completion._create_chat_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1651:26
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1638:26
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.completion._create_chat_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1652:23
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1639:23
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account` in function `controllers.console.app.completion._create_chat_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1691:30
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1678:30
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.completion._create_chat_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1692:27
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1679:27
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account` in function `controllers.console.app.completion._resolve_current_user_agent_debug_conversation_id` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1720:22
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1707:22
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.completion._resolve_current_user_agent_debug_conversation_id` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1721:19
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1708:19
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account` in function `controllers.console.app.completion._resolve_current_user_agent_debug_conversation_id` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1726:22
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1713:22
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.completion._resolve_current_user_agent_debug_conversation_id` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1727:19
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1714:19
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account` in function `controllers.console.app.completion._create_chat_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1778:30
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1765:30
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.completion._create_chat_message` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1779:27
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1766:27
 ERROR Object of class `object` has no attribute `data` [missing-attribute]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1862:50
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1849:50
 ERROR Object of class `object` has no attribute `limit` [missing-attribute]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1863:30
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1850:30
 ERROR Object of class `object` has no attribute `has_more` [missing-attribute]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1864:33
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1851:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.message._list_chat_messages` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1876:67
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1863:67
 ERROR Object of class `object` has no attribute `data` [missing-attribute]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1902:50
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1889:50
 ERROR Object of class `object` has no attribute `limit` [missing-attribute]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1903:30
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1890:30
 ERROR Object of class `object` has no attribute `has_more` [missing-attribute]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1904:33
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1891:33
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.message._list_chat_messages` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1928:67
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1905:67
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account | None` in function `controllers.console.app.message._list_chat_messages` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1928:91
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1905:91
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.message._list_chat_messages` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1949:27
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1925:27
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account | None` in function `controllers.console.app.message._list_chat_messages` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1950:30
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1926:30
 ERROR Argument `SimpleNamespace` is not assignable to parameter `current_user` with type `Account` in function `controllers.console.app.message._update_message_feedback` [bad-argument-type]
-    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1965:30
+    --> tests/unit_tests/controllers/console/agent/test_agent_controllers.py:1941:30
 ERROR Argument `SimpleNamespace` is not assignable to parameter `app_model` with type `App` in function `controllers.console.app.message._update_message_feedback` [bad-argument-type]
-    --> tests/unit_tests/contr\n\n... (truncated) ...

@wylswz wylswz changed the title Feat/ee agent sandbox feat: ee agent sandbox support Jul 8, 2026
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.32%. Comparing base (dbd3316) to head (90d3611).
⚠️ Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
api/core/app/apps/agent_app/app_runner.py 33.33% 1 Missing and 1 partial ⚠️
.../app/task_pipeline/based_generate_task_pipeline.py 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #38528      +/-   ##
==========================================
- Coverage   85.33%   85.32%   -0.01%     
==========================================
  Files        5005     5006       +1     
  Lines      265359   265564     +205     
  Branches    50458    50492      +34     
==========================================
+ Hits       226450   226600     +150     
- Misses      34462    34513      +51     
- Partials     4447     4451       +4     
Flag Coverage Δ
api 85.58% <50.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@wylswz wylswz changed the base branch from main to feat/agent-v2 July 8, 2026 03:40
@wylswz wylswz requested a review from Copilot July 8, 2026 05:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds enterprise sandbox support to the dify-agent shell layer by introducing an enterprise-backed ShellProvider with sandbox lifecycle management (create/attach/suspend/delete), wiring provider selection through server settings, and surfacing “sandbox expired” failures end-to-end (agent runtime → API).

Changes:

  • Introduces an enterprise shell provider and updates shell protocols/resources to support sandbox_id, attach(), suspend(), and delete().
  • Moves shell provider construction to the server/settings boundary and injects the resolved provider into runtime layer providers.
  • Propagates a sandbox_expired failure reason through agent runtime events and maps it to a user-facing API error.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
dify-agent/tests/local/dify_agent/server/test_settings.py Adds tests for ServerSettings.build_shell_provider() across providers and validation cases.
dify-agent/tests/local/dify_agent/runtime/test_compositor_factory.py Updates compositor factory tests to accept an injected shell provider instance.
dify-agent/tests/local/dify_agent/layers/shell/test_layer.py Expands shell layer tests for attach/suspend/delete lifecycle and sandbox ID persistence/errors.
dify-agent/tests/local/dify_agent/adapters/shell/test_shellctl.py Updates shellctl tests for new resource lifecycle methods and validation behavior.
dify-agent/tests/local/dify_agent/adapters/shell/test_config.py Adds focused tests for provider-specific settings validation and URL checking.
dify-agent/src/dify_agent/server/settings.py Adds shell provider selection + enterprise gateway settings and builds provider at the server boundary.
dify-agent/src/dify_agent/server/app.py Injects the resolved shell provider into layer providers and gates sandbox file service on provider presence.
dify-agent/src/dify_agent/runtime/runner.py Emits sandbox_expired as a structured failure reason when the sandbox expiration exception occurs.
dify-agent/src/dify_agent/runtime/compositor_factory.py Changes default layer provider factory to accept an already-constructed shell provider.
dify-agent/src/dify_agent/layers/shell/layer.py Persists sandbox_id in runtime state and changes cleanup semantics to suspend vs delete.
dify-agent/src/dify_agent/layers/shell/configs.py Introduces enterprise sandbox config type for shell layer configuration.
dify-agent/src/dify_agent/adapters/shell/shellctl.py Implements sandbox lifecycle semantics for shellctl resources/providers (sandbox_id, attach, suspend, delete).
dify-agent/src/dify_agent/adapters/shell/protocols.py Extends protocols with sandbox lifecycle, sandbox_id, and SandboxExpiredError.
dify-agent/src/dify_agent/adapters/shell/factory.py Adds enterprise provider selection and relies on validated settings for provider choice.
dify-agent/src/dify_agent/adapters/shell/enterprise/enterprise.py Adds enterprise gateway client + provider/resource implementation with attach-time sandbox liveness validation.
dify-agent/src/dify_agent/adapters/shell/enterprise/init.py Exposes EnterpriseShellProvider.
dify-agent/src/dify_agent/adapters/shell/config.py Adds provider-specific settings validation and URL validation for shell providers.
dify-agent/.example.env Documents and adds env vars for selecting shell provider and configuring enterprise gateway.
api/core/app/task_pipeline/based_generate_task_pipeline.py Treats agent-backend errors as invoke-level errors in the task pipeline error handler.
api/core/app/apps/base_app_generate_response_converter.py Maps agent-backend errors to standard completion request error responses.
api/core/app/apps/agent_app/app_runner.py Converts sandbox_expired terminal failures into a user-facing “start a new conversation” error.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dify-agent/src/dify_agent/adapters/shell/config.py
Comment on lines 64 to 73
def create_default_layer_providers(
*,
plugin_daemon_url: str = "http://localhost:5002",
plugin_daemon_api_key: str = "",
inner_api_url: str = "http://localhost:5001",
inner_api_key: str = "",
shellctl_entrypoint: str | None = None,
shellctl_auth_token: str | None = None,
shell_provider: ShellProviderProtocol | None = None,
agent_stub_api_base_url: str | None = None,
agent_stub_token_factory: ShellAgentStubTokenFactory | None = None,
) -> tuple[DifyAgentLayerProvider, ...]:
wylswz and others added 2 commits July 8, 2026 14:57
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
crazywoola
crazywoola previously approved these changes Jul 8, 2026
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 8, 2026
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jul 8, 2026
Base automatically changed from feat/agent-v2 to main July 8, 2026 12:20
@lyzno1 lyzno1 dismissed crazywoola’s stale review July 8, 2026 12:20

The base branch was changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants