Files
Artemis-Eapil/artemis/exploration/models.py
T

104 lines
2.9 KiB
Python

"""Shared Web/MCP/worker contracts for exploration."""
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator
from artemis.config.exploration import ExplorationConfig
ExplorationStatus = Literal[
"draft",
"queued",
"running",
"waiting_user",
"demonstrating",
"analyzing_demo",
"finalizing",
"paused",
"completed",
"cancelled",
]
DemonstrationSource = Literal["android", "computer", "both"]
RunKind = Literal["exploration", "validation"]
class ExplorationRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
request_id: str = Field(min_length=1, max_length=200)
@field_validator("request_id")
@classmethod
def nonblank_request(cls, value: str) -> str:
if not value.strip():
raise ValueError("request_id 不能为空")
return value
class CreateExploration(ExplorationRequest):
goal: str = Field(min_length=1, max_length=10000)
config: ExplorationConfig | None = None
# TaskOptions is validated at the service boundary, shared with ordinary tasks.
task_config: dict = Field(default_factory=dict)
@field_validator("goal")
@classmethod
def nonblank_goal(cls, value: str) -> str:
if not value.strip():
raise ValueError("请描述希望探索的测试流程")
return value.strip()
class ExplorationMessage(ExplorationRequest):
text: str = Field(min_length=1, max_length=10000)
@field_validator("text")
@classmethod
def nonblank_text(cls, value: str) -> str:
if not value.strip():
raise ValueError("消息不能为空")
return value.strip()
class DemonstrationRequest(ExplorationRequest):
source: DemonstrationSource | None = None
class ExtendDemonstration(ExplorationRequest):
seconds: int = Field(default=900, ge=60, le=86400)
class CaseDraft(BaseModel):
model_config = ConfigDict(extra="forbid")
name: str = Field(min_length=1, max_length=200)
preconditions: str = Field(default="", max_length=10000)
goal: str = Field(min_length=1, max_length=10000)
evidence: list[str] = Field(default_factory=list, max_length=100)
@field_validator("name", "goal")
@classmethod
def nonblank_case(cls, value: str) -> str:
if not value.strip():
raise ValueError("用例名称和提示词不能为空")
return value.strip()
class SaveCaseRequest(ExplorationRequest):
case: CaseDraft
expected_version: int = Field(ge=0)
class ValidateCaseRequest(ExplorationRequest):
version: int = Field(ge=1)
profile: Literal["flash", "pro"] = "flash"
task_config: dict = Field(default_factory=dict)
class GenerateCaseRequest(ExplorationRequest):
source_run_id: str = Field(min_length=1, max_length=100)
expected_version: int = Field(ge=0)
class CaseBatchRequest(ValidateCaseRequest):
name: str = Field(default="探索用例", min_length=1, max_length=200)