butler/gateway/wechat_scenario_sim/schema.py
Rama main · réplica de lectura del repositorio original.
from __future__ import annotations
from dataclasses import dataclass, field
from pathlib import Path
from typing import Literal
SessionMode = Literal["shared", "fresh"]
Tier = Literal["fast", "standard", "slow"]
@dataclass(frozen=True)
class ScenarioCase:
name: str
user_text: str
expect_reply_any: tuple[str, ...] = ()
reject_reply_any: tuple[str, ...] = ()
expect_tools_any: tuple[str, ...] = ()
prefer_tools_any: tuple[str, ...] = ()
forbid_tools: tuple[str, ...] = ()
tier: Tier = "standard"
max_seconds: float = 120.0
requires_mcp: bool = False
skip_in_quick: bool = False
fresh_session: bool = False
soft: bool = False
verify_files_exist: tuple[str, ...] = ()
verify_files_missing: tuple[str, ...] = ()
verify_file_contains: tuple["FileContainsSpec", ...] = ()
prompt_hint: str = ""
require_tools: bool = False
simulate_wechat_outbound: bool = False
expect_outbound_any: tuple[str, ...] = ()
min_outbound_messages: int = 0
@dataclass(frozen=True)
class FileContainsSpec:
path: str
substrings: tuple[str, ...] = ()
@dataclass(frozen=True)
class ScenarioTrack:
id: str
title: str
session_mode: SessionMode = "shared"
quick: bool = True
requires_mcp: bool = False
setup: tuple[str, ...] = ()
cleanup_globs: tuple[str, ...] = ()
cases: tuple[ScenarioCase, ...] = ()
simulate_wechat_outbound: bool = False
@dataclass(frozen=True)
class ScenarioManifest:
title: str
path: Path
default_project: str = "灵文1号"
verify_phrases: tuple[str, ...] = ()
tracks: tuple[ScenarioTrack, ...] = ()
@dataclass
class ScenarioCaseResult:
name: str
track_id: str
ok: bool
reply_preview: str = ""
tools: list[str] = field(default_factory=list)
elapsed_seconds: float = 0.0
errors: list[str] = field(default_factory=list)
warnings: list[str] = field(default_factory=list)
skipped: bool = False
skip_reason: str = ""
outbound_preview: str = ""
outbound_count: int = 0
@dataclass
class ScenarioSimReport:
ok: bool = True
tracks_run: int = 0
cases_run: int = 0
cases_passed: int = 0
cases_skipped: int = 0
errors: list[str] = field(default_factory=list)
warnings: list[str] = field(default_factory=list)
cases: list[ScenarioCaseResult] = field(default_factory=list)