104 lines
2.9 KiB
Python
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)
|