Source code for agentscope_runtime.sandbox.model.container
# -*- coding: utf-8 -*-
import copy
import time
from enum import Enum
from typing import List, Optional, Dict
from pydantic import BaseModel, Field, ConfigDict, model_validator
[docs]
class ContainerState(str, Enum):
WARM = "warm"
RUNNING = "running"
RECYCLED = "recycled"
ERROR = "error"
RELEASED = "released"
[docs]
class ContainerModel(BaseModel):
model_config = ConfigDict(extra="allow")
session_id: str = Field(
...,
description="Unique identifier for the session",
)
container_id: str = Field(
...,
description="Unique identifier for the container instance",
)
container_name: str = Field(
...,
description="Human-readable name for the container",
)
url: str = Field(
...,
description="URL for accessing the container",
)
ports: List[int | str] = Field(
...,
description="List of occupied port numbers",
)
mount_dir: str | None = Field(
None,
description="The mount directory of workspace.",
)
storage_path: str | None = Field(
None,
description="The oss_path of workspace.",
)
runtime_token: str | None = Field(
None,
description="Runtime token used for authentication or secure "
"communication",
)
version: str | None = Field(
None,
description="Image version of the container",
)
meta: Optional[Dict] = Field(default_factory=dict)
timeout: Optional[int] = Field(
None,
description="Timeout in seconds for container operations",
ge=0,
)
sandbox_type: Optional[str] = Field(
default=None,
description="Sandbox type (e.g. base/browser/...). Usually "
"SandboxType.value.",
)
state: ContainerState = Field(
default=ContainerState.RUNNING,
description="Lifecycle state",
)
# Pull session_ctx_id up from meta for easier indexing/logic
session_ctx_id: Optional[str] = Field(
default=None,
description="Bound session context id "
"(copied from meta['session_ctx_id'] for compatibility)",
)
# Heartbeat timestamp (unix seconds)
last_active_at: Optional[float] = Field(
default=None,
description="Last activity timestamp (unix seconds)",
)
# Recycle/release timestamps
recycled_at: Optional[float] = Field(
default=None,
description="Recycled timestamp (unix seconds)",
)
released_at: Optional[float] = Field(
default=None,
description="Released timestamp (unix seconds)",
)
updated_at: Optional[float] = Field(
default=None,
description="Last model update timestamp (unix seconds)",
)
recycle_reason: Optional[str] = Field(
default=None,
description="Reason for recycle",
)
@model_validator(mode="after")
def _compat_and_defaults(self):
"""Compatibility layer for ContainerModel.
This validator ensures backward compatibility and default value
population:
- Reads session_ctx_id from meta if not provided
- Writes session_ctx_id back to meta for old code compatibility
- Ensures updated_at is always populated
Returns:
`ContainerModel`:
The validated model instance
"""
# normalize meta
if self.meta is None:
self.meta = {}
# meta -> session_ctx_id
if not self.session_ctx_id:
v = self.meta.get("session_ctx_id")
if v:
self.session_ctx_id = v
# session_ctx_id -> meta
if self.session_ctx_id:
self.meta["session_ctx_id"] = copy.deepcopy(self.session_ctx_id)
# default updated_at
if self.updated_at is None:
self.updated_at = time.time()
return self