Directory rename (git mv, history preserved) plus rewrite of all references: absolute imports in tests, the zero-dep runner, docstrings, comments, and the README. No behavior change. Run: python3 -m pytest v2/tests/ -q ; python3 v2/run_tests.py ; python3 -m v2.examples
42 lines
1.1 KiB
Python
42 lines
1.1 KiB
Python
"""Structured cancellation (design_v3 §6.4, §12).
|
|
|
|
"Cancellation is common-path, not exceptional" — vibe-directing makes abandoning
|
|
in-flight work the *normal* user action. Cancel takes effect at the next loop step
|
|
boundary: the driver checks the scope between steps, drops queued work, releases
|
|
LoopState + cache handles, and reports ``cancelled``.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from enum import Enum
|
|
|
|
|
|
class CancelKind(str, Enum):
|
|
REQUEST = "request"
|
|
LOOP = "loop"
|
|
STREAM = "stream"
|
|
SESSION = "session"
|
|
|
|
|
|
class Cancelled(Exception):
|
|
"""Raised at a step boundary when a CancelScope is tripped."""
|
|
|
|
|
|
@dataclass
|
|
class CancelScope:
|
|
kind: CancelKind = CancelKind.REQUEST
|
|
target_id: str = ""
|
|
_flag: list[bool] = field(default_factory=lambda: [False]) # shared mutable cell
|
|
|
|
def cancel(self) -> None:
|
|
self._flag[0] = True
|
|
|
|
@property
|
|
def cancelled(self) -> bool:
|
|
return self._flag[0]
|
|
|
|
def check(self) -> None:
|
|
"""Called by the driver at each step boundary."""
|
|
if self._flag[0]:
|
|
raise Cancelled(f"{self.kind.value}:{self.target_id}")
|