28 KiB
Docker Pod 信息接口设计文档
文档版本: v1.0.1
创建日期: 2024-12-16
更新日期: 2024-12-16
状态: 草案
相关模块:crates/rcoder/src/router.rs,crates/docker_manager,crates/shared_types
1. 需求概述
1.1 背景
RCoder 系统采用动态容器管理模式,可以根据 user_id 和 project_id 创建和管理 Docker 容器(特别是 ComputerAgentRunner 类型的容器)。为了便于系统监控和前端用户使用 noVNC 远程虚拟桌面,需要新增三个接口:
- 获取当前容器数量接口 - 用于监控系统中已创建的容器总数
- 启动容器接口 - 根据
user_id和project_id启动(或获取已存在的)容器,仅启动容器本身,不启动 Agent 服务,以便用户可以通过 noVNC 访问远程虚拟桌面 - 容器保活接口 - 刷新容器的最后活动时间,防止容器被定时清理任务销毁
Important
所有接口响应统一使用
shared_types::HttpResult<T>结构进行包装,保持与系统其他 API 的一致性。
1.2 目标
| 目标 | 描述 |
|---|---|
| 监控能力 | 提供容器数量统计,便于系统运维监控 |
| 用户体验 | 简化容器启动流程,自动化处理容器存在性检查 |
| 简洁响应 | 响应只包含容器基本信息,VNC 访问通过独立接口获取 |
| 轻量启动 | 仅启动容器,不启动 Agent 服务,减少资源占用 |
| 容器保活 | 支持刷新容器活动时间,防止被自动清理 |
2. HttpResult 响应包装
2.1 HttpResult 结构 (来自 shared_types)
所有接口响应均使用 HttpResult<T> 包装:
// 来自 crates/shared_types/src/model/http_result.rs
#[derive(Debug, Deserialize, ToSchema)]
pub struct HttpResult<T> {
/// 响应码: "0000" 表示成功
pub code: String,
/// 响应消息
pub message: String,
/// 响应数据 (成功时有值)
pub data: Option<T>,
/// OpenTelemetry Trace ID (用于链路追踪)
pub tid: Option<String>,
/// 是否成功 (code == "0000")
#[serde(skip)]
pub success: bool,
}
impl<T> HttpResult<T> {
/// 创建成功响应
pub fn success(data: T) -> Self;
/// 创建错误响应
pub fn error(code: &str, message: &str) -> Self;
/// 创建内部错误响应 (code: "5000")
pub fn internal_error(message: &str) -> Self;
}
2.2 响应格式示例
成功响应:
{
"code": "0000",
"message": "成功",
"data": { ... },
"tid": "abc123def456...",
"success": true
}
错误响应:
{
"code": "5000",
"message": "获取 DockerManager 失败",
"data": null,
"tid": "abc123def456...",
"success": false
}
3. 接口设计
3.1 接口一:获取当前容器数量
3.1.1 接口规格
| 属性 | 值 |
|---|---|
| 路径 | GET /computer/pod/count |
| 方法 | GET |
| 入参 | 无 |
| 响应类型 | HttpResult<PodCountResponse> |
| 标签 | pod (Pod 容器管理接口) |
3.1.2 请求示例
curl -X GET http://localhost:8087/computer/pod/count
3.1.3 响应数据结构 (data 字段)
/// 容器数量响应结构
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PodCountResponse {
/// 当前运行的容器总数
#[schema(example = 5)]
pub total_count: u32,
/// 按服务类型分类的容器数量
pub by_service_type: PodCountByServiceType,
/// 统计时间戳 (Unix 毫秒)
#[schema(example = 1702700000000)]
pub timestamp: u64,
}
/// 按服务类型分类的容器数量
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PodCountByServiceType {
/// RCoder 类型容器数量
#[schema(example = 2)]
pub rcoder: u32,
/// ComputerAgentRunner 类型容器数量
#[schema(example = 3)]
pub computer_agent_runner: u32,
}
3.1.4 完整响应示例
{
"code": "0000",
"message": "成功",
"data": {
"total_count": 5,
"by_service_type": {
"rcoder": 2,
"computer_agent_runner": 3
},
"timestamp": 1702700000000
},
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": true
}
3.2 接口二:启动容器 (Ensure Container)
3.2.1 接口规格
| 属性 | 值 |
|---|---|
| 路径 | POST /computer/pod/ensure |
| 方法 | POST |
| 入参 | user_id (必填), project_id (必填) |
| 响应类型 | HttpResult<EnsurePodResponse> |
| 标签 | pod (Pod 容器管理接口) |
Note
此接口采用 幂等设计:如果对应的容器已经存在且处于运行状态,则直接返回现有容器信息,不会创建新容器。
Important
此接口仅启动容器,不启动 Agent 服务。 容器启动后,用户可直接通过 noVNC 访问虚拟桌面,无需等待 Agent 服务初始化。如需使用 AI Agent 功能,请调用
/computer/chat接口。
3.2.2 请求结构
/// 启动容器请求结构
#[derive(Debug, Clone, Deserialize, ToSchema)]
pub struct EnsurePodRequest {
/// 用户唯一标识符
#[schema(example = "user_123")]
pub user_id: String,
/// 项目唯一标识符
#[schema(example = "proj_456")]
pub project_id: String,
/// 可选的资源限制配置
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_limits: Option<PodResourceLimits>,
}
/// Pod 资源限制配置
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
pub struct PodResourceLimits {
/// 内存限制 (bytes), 例如 4GB = 4294967296
#[schema(example = 4294967296)]
pub memory: Option<u64>,
/// CPU 份额 (1024 = 1 核)
#[schema(example = 2048)]
pub cpu_shares: Option<u64>,
}
3.2.3 请求示例
curl -X POST http://localhost:8087/computer/pod/ensure \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_123",
"project_id": "proj_456"
}'
3.2.4 响应数据结构 (data 字段)
/// 启动容器响应结构
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct EnsurePodResponse {
/// 容器是否为新创建 (false 表示已存在)
pub created: bool,
/// 容器基本信息
pub container_info: PodContainerInfo,
/// 提示消息
#[schema(example = "容器已就绪")]
pub message: String,
}
/// 容器基本信息
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct PodContainerInfo {
/// 容器 ID
#[schema(example = "abc123def456")]
pub container_id: String,
/// 容器名称
#[schema(example = "computer-agent-runner-user_123")]
pub container_name: String,
/// 容器 IP 地址 (内部网络)
#[schema(example = "172.17.0.5")]
pub container_ip: String,
/// 服务 URL
#[schema(example = "http://172.17.0.5:8086")]
pub service_url: String,
/// 容器状态
#[schema(example = "running")]
pub status: String,
}
3.2.5 完整响应示例
成功响应(新创建容器):
{
"code": "0000",
"message": "成功",
"data": {
"created": true,
"container_info": {
"container_id": "abc123def456...",
"container_name": "computer-agent-runner-user_123",
"container_ip": "172.17.0.5",
"service_url": "http://172.17.0.5:8086",
"status": "running"
},
"message": "容器创建成功(Agent 服务未启动)"
},
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": true
}
成功响应(容器已存在):
{
"code": "0000",
"message": "成功",
"data": {
"created": false,
"container_info": {
"container_id": "abc123def456...",
"container_name": "computer-agent-runner-user_123",
"container_ip": "172.17.0.5",
"service_url": "http://172.17.0.5:8086",
"status": "running"
},
"message": "容器已存在"
},
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": true
}
错误响应:
{
"code": "5000",
"message": "启动容器失败: Docker 连接超时",
"data": null,
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": false
}
3.3 接口三:容器保活 (Keepalive)
3.3.1 接口规格
| 属性 | 值 |
|---|---|
| 路径 | POST /computer/pod/keepalive |
| 方法 | POST |
| 入参 | user_id (必填), project_id (必填) |
| 响应类型 | HttpResult<KeepalivePodResponse> |
| 标签 | pod (Pod 容器管理接口) |
Note
此接口用于防止容器被定时清理任务销毁。系统会定期(默认每 5 分钟)检查容器的最后活动时间,闲置超过 30 分钟的容器将被自动清理。
Tip
使用场景:前端在用户使用 noVNC 远程桌面时,应定期调用此接口(建议每 5-10 分钟一次)来保持容器活跃状态。
3.3.2 请求结构
/// 容器保活请求结构
#[derive(Debug, Clone, Deserialize, ToSchema)]
pub struct KeepalivePodRequest {
/// 用户唯一标识符
#[schema(example = "user_123")]
pub user_id: String,
/// 项目唯一标识符
#[schema(example = "proj_456")]
pub project_id: String,
}
3.3.3 请求示例
curl -X POST http://localhost:8087/computer/pod/keepalive \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_123",
"project_id": "proj_456"
}'
3.3.4 响应数据结构 (data 字段)
/// 容器保活响应结构
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct KeepalivePodResponse {
/// 容器是否存在 (true=已存在, false=新创建)
pub existed: bool,
/// 容器是否为新创建 (当 existed=false 时为 true)
pub created: bool,
/// 容器基本信息
pub container_info: PodContainerInfo,
/// 上次活动时间 (Unix 毫秒时间戳, 更新前)
#[schema(example = 1702700000000)]
pub previous_activity_time: u64,
/// 当前活动时间 (Unix 毫秒时间戳, 更新后)
#[schema(example = 1702700600000)]
pub current_activity_time: u64,
/// 距离下次清理的剩余时间 (秒)
/// 基于默认 30 分钟闲置超时计算
#[schema(example = 1800)]
pub time_until_cleanup: u64,
/// 提示消息
#[schema(example = "容器活动时间已刷新")]
pub message: String,
}
3.3.5 完整响应示例
成功响应(容器已存在,刷新活动时间):
{
"code": "0000",
"message": "成功",
"data": {
"existed": true,
"created": false,
"container_info": {
"container_id": "abc123def456...",
"container_name": "computer-agent-runner-user_123",
"container_ip": "172.17.0.5",
"service_url": "http://172.17.0.5:8086",
"status": "running"
},
"previous_activity_time": 1702700000000,
"current_activity_time": 1702700600000,
"time_until_cleanup": 1800,
"message": "容器活动时间已刷新,距离自动清理还有 30 分钟"
},
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": true
}
成功响应(容器不存在,自动创建):
{
"code": "0000",
"message": "成功",
"data": {
"existed": false,
"created": true,
"container_info": {
"container_id": "xyz789...",
"container_name": "computer-agent-runner-user_123",
"container_ip": "172.17.0.6",
"service_url": "http://172.17.0.6:8086",
"status": "running"
},
"previous_activity_time": 0,
"current_activity_time": 1702700600000,
"time_until_cleanup": 1800,
"message": "容器已自动创建,距离自动清理还有 30 分钟"
},
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": true
}
错误响应:
{
"code": "5000",
"message": "刷新活动时间失败: 容器状态异常",
"data": null,
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": false
}
4. 架构设计
4.1 整体架构
┌─────────────────────────────────────────────────────────────────┐
│ 外部客户端 │
└────────────────────────────┬────────────────────────────────────┘
│ HTTP
▼
┌─────────────────────────────────────────────────────────────────┐
│ rcoder (主服务) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ router.rs │ │
│ │ /computer/pod/count ─────▶ pod_count_handler │ │
│ │ /computer/pod/ensure ─────▶ pod_ensure_handler │ │
│ │ /computer/pod/keepalive─────▶ pod_keepalive_handler │ │
│ └───────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼─────────────────────────────┐ │
│ │ service/pod_service.rs │ │
│ │ ┌─────────────────┐ ┌──────────────────────────────┐ │ │
│ │ │ PodService │ │ PodServiceTrait (trait) │ │ │
│ │ │ - get_count() │ │ - get_pod_count() │ │ │
│ │ │ - ensure_pod() │ │ - ensure_pod() │ │ │
│ │ └─────────────────┘ └──────────────────────────────┘ │ │
│ └───────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼─────────────────────────────┐ │
│ │ docker_manager (crate) │ │
│ │ DockerManager │ │
│ │ - list_containers() │ │
│ │ - get_agent_info() │ │
│ │ - start_agent_container() │ │
│ └───────────────────────────┬─────────────────────────────┘ │
└──────────────────────────────┼──────────────────────────────────┘
│ Docker API
▼
┌─────────────────────────────────────────────────────────────────┐
│ Docker Daemon │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ container-1 │ │ container-2 │ │ container-3 │ │
│ │ (user_123) │ │ (user_456) │ │ (project_xyz) │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
4.2 模块职责
| 模块 | 职责 |
|---|---|
handler/pod_handler.rs |
处理 HTTP 请求,参数解析与验证 |
service/pod_service.rs |
核心业务逻辑,调用 DockerManager |
docker_manager |
Docker API 交互,容器生命周期管理 |
5. Trait 与结构体定义
5.1 Service Trait
// crates/rcoder/src/service/pod_service.rs
use async_trait::async_trait;
use crate::AppError;
/// Pod 服务 Trait
///
/// 定义 Pod 容器管理的核心能力接口
#[async_trait]
pub trait PodServiceTrait: Send + Sync {
/// 获取当前容器数量统计
///
/// # 返回
/// 容器数量统计信息
async fn get_pod_count(&self) -> Result<PodCountResponse, AppError>;
/// 确保容器存在(幂等操作)
///
/// 如果容器已存在则返回现有容器信息,否则创建新容器
/// 仅启动容器,不启动 Agent 服务
///
/// # 参数
/// - `request`: 启动容器请求
///
/// # 返回
/// 容器信息和 VNC 访问信息
async fn ensure_pod(&self, request: EnsurePodRequest) -> Result<EnsurePodResponse, AppError>;
/// 容器保活(刷新活动时间)
///
/// 如果容器已存在则刷新其最后活动时间,防止被清理任务销毁
/// 如果容器不存在则自动创建
///
/// # 参数
/// - `request`: 保活请求(包含 user_id 和 project_id)
///
/// # 返回
/// 保活结果,包含活动时间信息和距离清理的剩余时间
async fn keepalive_pod(&self, request: KeepalivePodRequest) -> Result<KeepalivePodResponse, AppError>;
}
5.2 请求/响应结构体
// crates/rcoder/src/handler/pod_handler.rs
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
// ============================================================================
// 接口一:获取容器数量
// ============================================================================
/// 容器数量响应
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PodCountResponse {
/// 当前运行的容器总数
pub total_count: u32,
/// 按服务类型分类的容器数量
pub by_service_type: PodCountByServiceType,
/// 统计时间戳 (Unix 毫秒)
pub timestamp: u64,
}
/// 按服务类型分类的容器数量
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PodCountByServiceType {
/// RCoder 类型容器数量
pub rcoder: u32,
/// ComputerAgentRunner 类型容器数量
pub computer_agent_runner: u32,
}
// ============================================================================
// 接口二:启动容器
// ============================================================================
/// 启动容器请求
#[derive(Debug, Clone, Deserialize, ToSchema)]
pub struct EnsurePodRequest {
/// 用户唯一标识符 (必填)
#[schema(example = "user_123")]
pub user_id: String,
/// 项目唯一标识符 (必填)
#[schema(example = "proj_456")]
pub project_id: String,
/// 可选的资源限制配置
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_limits: Option<PodResourceLimits>,
}
/// Pod 资源限制配置
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
pub struct PodResourceLimits {
/// 内存限制 (bytes)
pub memory: Option<u64>,
/// CPU 份额
pub cpu_shares: Option<u64>,
}
/// 启动容器响应
///
/// 注意: 此结构体作为 HttpResult<EnsurePodResponse> 的 data 字段返回
/// 成功状态由外层 HttpResult 的 code 字段表示
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct EnsurePodResponse {
/// 容器是否为新创建 (false 表示已存在)
pub created: bool,
/// 容器基本信息
pub container_info: PodContainerInfo,
/// 提示消息
pub message: String,
}
/// 容器基本信息
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct PodContainerInfo {
/// 容器 ID
pub container_id: String,
/// 容器名称
pub container_name: String,
/// 容器 IP 地址
pub container_ip: String,
/// 服务 URL
pub service_url: String,
/// 容器状态
pub status: String,
}
// ============================================================================
// 接口三:容器保活
// ============================================================================
/// 容器保活请求
#[derive(Debug, Clone, Deserialize, ToSchema)]
pub struct KeepalivePodRequest {
/// 用户唯一标识符
#[schema(example = "user_123")]
pub user_id: String,
/// 项目唯一标识符
#[schema(example = "proj_456")]
pub project_id: String,
}
/// 容器保活响应
///
/// 注意: 此结构体作为 HttpResult<KeepalivePodResponse> 的 data 字段返回
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct KeepalivePodResponse {
/// 容器是否已存在
pub existed: bool,
/// 容器是否为新创建 (当 existed=false 时为 true)
pub created: bool,
/// 容器基本信息
pub container_info: PodContainerInfo,
/// 上次活动时间 (Unix 毫秒时间戳, 更新前)
pub previous_activity_time: u64,
/// 当前活动时间 (Unix 毫秒时间戳, 更新后)
pub current_activity_time: u64,
/// 距离下次清理的剩余时间 (秒)
pub time_until_cleanup: u64,
/// 提示消息
pub message: String,
}
5.3 Service 实现结构
// crates/rcoder/src/service/pod_service.rs
use std::sync::Arc;
/// Pod 服务实现
///
/// 封装 Docker 容器管理的业务逻辑
pub struct PodService {
/// Docker 管理器
docker_manager: Arc<docker_manager::DockerManager>,
}
impl PodService {
/// 创建 PodService 实例
pub fn new(docker_manager: Arc<docker_manager::DockerManager>) -> Self {
Self { docker_manager }
}
}
#[async_trait]
impl PodServiceTrait for PodService {
async fn get_pod_count(&self) -> Result<PodCountResponse, AppError> {
// 具体实现...
todo!()
}
async fn ensure_pod(&self, request: EnsurePodRequest) -> Result<EnsurePodResponse, AppError> {
// 具体实现...
todo!()
}
async fn keepalive_pod(&self, request: KeepalivePodRequest) -> Result<KeepalivePodResponse, AppError> {
// 具体实现...
// 1. 查询容器是否存在
// 2. 不存在则创建容器
// 3. 存在则刷新 last_activity 时间
// 4. 计算距离清理的剩余时间
todo!()
}
}
6. 路由配置
6.1 新增路由
在 crates/rcoder/src/router.rs 中添加以下路由:
// 在 create_router 函数中添加
// Pod 容器管理路由 (统一使用 /computer 前缀)
.route("/computer/pod/count", get(handler::pod_count))
.route("/computer/pod/ensure", post(handler::pod_ensure))
.route("/computer/pod/keepalive", post(handler::pod_keepalive))
6.2 OpenAPI 配置更新
// 在 ApiDoc 结构体中添加
#[openapi(
paths(
// ... 现有路径
handler::pod_count,
handler::pod_ensure,
handler::pod_keepalive,
),
components(
schemas(
// ... 现有 schemas
handler::PodCountResponse,
handler::PodCountByServiceType,
handler::EnsurePodRequest,
handler::PodResourceLimits,
handler::EnsurePodResponse,
handler::PodContainerInfo,
handler::KeepalivePodRequest,
handler::KeepalivePodResponse,
)
),
tags(
// ... 现有 tags
(name = "pod", description = "Pod 容器管理接口,支持容器监控和启动"),
),
)]
7. 错误处理
7.1 错误类型
| 错误码 | HTTP 状态码 | 描述 |
|---|---|---|
DOCKER_MANAGER_ERROR |
500 | Docker Manager 获取失败 |
CONTAINER_CREATE_FAILED |
500 | 容器创建失败 |
CONTAINER_NOT_FOUND |
404 | 容器未找到(仅查询场景) |
INVALID_REQUEST |
400 | 请求参数无效 |
7.2 错误响应结构(HttpResult 统一格式)
错误响应统一使用 HttpResult<T> 格式,data 字段为 null:
{
"code": "5000",
"message": "启动容器失败: Docker 连接超时",
"data": null,
"tid": "4bf92f3577b34da6a3ce929d0e0e4736",
"success": false
}
8. 与现有功能的关系
8.1 复用现有组件
| 组件 | 复用方式 |
|---|---|
docker_manager::global::get_global_docker_manager() |
获取全局 Docker 管理器实例 |
ComputerContainerManager |
复用用户容器创建逻辑 |
ContainerBasicInfo |
复用容器信息结构 |
8.2 与 noVNC 集成
VNC 访问信息通过独立接口获取:
- VNC 桌面访问接口:
GET /computer/desktop/{user_id}/{project_id}
Pingora 已配置路由规则 /computer/vnc/{user_id}/{project_id}/{*path},会自动代理到对应容器的 6080 端口。
9. 实现清单
9.1 新增文件
| 文件路径 | 描述 |
|---|---|
crates/rcoder/src/handler/pod_handler.rs |
Pod 相关 HTTP 处理器 |
crates/rcoder/src/service/pod_service.rs |
Pod 服务业务逻辑 |
9.2 修改文件
| 文件路径 | 修改内容 |
|---|---|
crates/rcoder/src/router.rs |
添加 /computer/pod/* 路由 |
crates/rcoder/src/handler/mod.rs |
导出 pod_handler 模块 |
crates/rcoder/src/service/mod.rs |
导出 pod_service 模块 |
10. 验证计划
10.1 自动化测试
# 1. 编译检查
cargo build --workspace
# 2. 单元测试
cargo test --workspace
# 3. Clippy 检查
cargo clippy --workspace --all-targets
10.2 手动验证
# 1. 启动服务
make dev-restart
# 2. 测试获取容器数量
curl -X GET http://localhost:8087/computer/pod/count | jq
# 3. 测试启动容器
curl -X POST http://localhost:8087/computer/pod/ensure \
-H "Content-Type: application/json" \
-d '{"user_id": "test_user", "project_id": "test_project"}' | jq
# 4. 验证 VNC 访问
# 使用返回的 proxy_vnc_url 在浏览器中访问
10.3 OpenAPI 文档验证
启动服务后访问 Swagger UI:http://localhost:8087/swagger-ui/ 确认新接口已正确注册。
11. 附录
11.1 参考文件
- computer_container_manager.rs - 用户容器管理逻辑
- computer_desktop_handler.rs - VNC 桌面处理器
- docker_manager/manager.rs - Docker 容器管理核心
11.2 相关接口
| 接口 | 描述 |
|---|---|
GET /computer/desktop/{user_id}/{project_id} |
获取 VNC 桌面访问信息 |
POST /computer/chat |
Computer Agent 聊天接口 |
/computer/vnc/{user_id}/{project_id}/* |
Pingora VNC 代理路由 |
12. 变更记录
| 日期 | 版本 | 变更内容 | 作者 |
|---|---|---|---|
| 2024-12-16 | v1.0.0 | 初始版本 | AI Assistant |
| 2024-12-16 | v1.0.1 | 使用 HttpResult 包装响应;明确不启动 Agent 服务 | AI Assistant |
| 2024-12-16 | v1.1.0 | 新增容器保活接口 (keepalive),支持刷新容器活动时间防止被自动清理 | AI Assistant |