Ctrl K
ComunidadGuías…

butler/gateway/wechat_scenario_sim/schema.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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)