File size: 3,116 Bytes
6ec7f56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""Flash-offer: a discount code that rotates on a fixed wall-clock schedule,
independent of anything the agent does. Tests whether the agent re-perceives
the *current* on-screen value right before acting, rather than trusting a
value it read a few steps earlier — the exogenous-time analogue of the
list-reflow-after-own-action failure `email-triage` already found in
practice (see ../../ui-tars-example/testing/README.md). Because grading is
tied to real elapsed time, this task's pass/fail is not seed-pure the way
the other tasks are — same-seed re-resets get the same *code set* but not
the same *currently-valid code* at an arbitrary later instant, so it's kept
out of the fully-generic determinism tests and given its own in
tests/test_environment.py. Known v0 limitation: only 4 candidate codes
cycle, so an agent could pass by unwitting sequential guessing within the
step budget rather than genuine perception; not a design goal to close here."""

from __future__ import annotations

import json
import time
from typing import Any

from ..seeding import rng

CODE_POOL = ["NOVA", "ZEST", "GLOW", "FLUX", "PEAK", "SPARK", "ECHO", "BOLT"]
CYCLE_SECONDS = 8


class FlashOffer:
    id = "flash-offer"
    title = "Flash Sale"
    template = "flash_offer.html"

    def generate(self, seed: int) -> dict[str, Any]:
        r = rng(self.id, seed)
        codes = r.sample(CODE_POOL, 4)
        return {
            "codes": codes,
            "start_ts": time.time(),
            "redeemed": False,
            "redeemed_code": None,
            "redeemed_code_correct": None,
        }

    def instruction(self, state: dict[str, Any]) -> str:
        return (
            "A flash-sale discount code is shown on the page and rotates every "
            "few seconds. Read whichever code is CURRENTLY displayed — not one "
            "you saw earlier — type it into the box, and click Redeem."
        )

    def view(self, state: dict[str, Any]) -> dict[str, Any]:
        return {
            "codes_json": json.dumps(state["codes"]),
            "start_ts_ms": int(state["start_ts"] * 1000),
            "cycle_seconds": CYCLE_SECONDS,
        }

    def _current_code(self, state: dict[str, Any]) -> str:
        elapsed = time.time() - state["start_ts"]
        idx = int(elapsed // CYCLE_SECONDS) % len(state["codes"])
        return state["codes"][idx]

    def handle_action(self, state: dict[str, Any], payload: dict[str, Any]) -> dict[str, Any]:
        if payload.get("op") != "redeem":
            return {"ok": False, "error": f"unknown op '{payload.get('op')}'"}
        code = str(payload.get("code", "")).strip().upper()
        current = self._current_code(state)
        state["redeemed"] = True
        state["redeemed_code"] = code
        state["redeemed_code_correct"] = code == current
        return {"ok": True, "correct": state["redeemed_code_correct"]}

    def verify(self, state: dict[str, Any]) -> dict[str, bool]:
        return {
            "redeemed": state["redeemed"] is True,
            "code_matched_live_value": state["redeemed_code_correct"] is True,
        }