feat(core): 支持任务执行中只跳过或停止当前任务

This commit is contained in:
XcantloadX 2025-07-26 13:26:01 +08:00
parent ceaaed7896
commit a167cbfbe1
2 changed files with 15 additions and 7 deletions

View File

@ -12,6 +12,7 @@ from kotonebot.client import Device
from kotonebot.client.host.protocol import Instance from kotonebot.client.host.protocol import Instance
from kotonebot.backend.context import init_context, vars from kotonebot.backend.context import init_context, vars
from kotonebot.backend.context import task_registry, action_registry, Task, Action from kotonebot.backend.context import task_registry, action_registry, Task, Action
from kotonebot.errors import StopCurrentTask
log_stream = io.StringIO() log_stream = io.StringIO()
stream_handler = logging.StreamHandler(log_stream) stream_handler = logging.StreamHandler(log_stream)
@ -19,10 +20,11 @@ stream_handler.setFormatter(logging.Formatter('[%(asctime)s] [%(levelname)s] [%(
logging.getLogger('kotonebot').addHandler(stream_handler) logging.getLogger('kotonebot').addHandler(stream_handler)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
TaskStatusValue = Literal['pending', 'running', 'finished', 'error', 'cancelled', 'stopped']
@dataclass @dataclass
class TaskStatus: class TaskStatus:
task: Task task: Task
status: Literal['pending', 'running', 'finished', 'error', 'cancelled'] status: TaskStatusValue
@dataclass @dataclass
class RunStatus: class RunStatus:
@ -73,7 +75,7 @@ class Event(Generic[Params, Return]):
class KotoneBotEvents: class KotoneBotEvents:
def __init__(self): def __init__(self):
self.task_status_changed = Event[ self.task_status_changed = Event[
[Task, Literal['pending', 'running', 'finished', 'error', 'cancelled']], None [Task, TaskStatusValue], None
]() ]()
self.task_error = Event[ self.task_error = Event[
[Task, Exception], None [Task, Exception], None
@ -186,6 +188,9 @@ class KotoneBot:
try: try:
task.func() task.func()
self.events.task_status_changed.trigger(task, 'finished') self.events.task_status_changed.trigger(task, 'finished')
except StopCurrentTask:
logger.info(f'Task skipped/stopped: {task.name}')
self.events.task_status_changed.trigger(task, 'stopped')
# 用户中止 # 用户中止
except KeyboardInterrupt as e: except KeyboardInterrupt as e:
logger.exception('Keyboard interrupt detected.') logger.exception('Keyboard interrupt detected.')
@ -205,8 +210,8 @@ class KotoneBot:
for task1 in tasks[tasks.index(task)+1:]: for task1 in tasks[tasks.index(task)+1:]:
self.events.task_status_changed.trigger(task1, 'cancelled') self.events.task_status_changed.trigger(task1, 'cancelled')
break break
logger.info(f'Task finished: {task.name}') logger.info(f'Task ended: {task.name}')
logger.info('All tasks finished.') logger.info('All tasks ended.')
self.events.finished.trigger() self.events.finished.trigger()
def run_all(self) -> None: def run_all(self) -> None:
@ -228,7 +233,7 @@ class KotoneBot:
self.events.finished -= _on_finished self.events.finished -= _on_finished
self.events.task_status_changed -= _on_task_status_changed self.events.task_status_changed -= _on_task_status_changed
def _on_task_status_changed(task: Task, status: Literal['pending', 'running', 'finished', 'error', 'cancelled']): def _on_task_status_changed(task: Task, status: TaskStatusValue):
def _find(task: Task) -> TaskStatus: def _find(task: Task) -> TaskStatus:
for task_status in run_status.tasks: for task_status in run_status.tasks:
if task_status.task == task: if task_status.task == task:

View File

@ -35,3 +35,6 @@ class UnscalableResolutionError(KotonebotError):
class ContextNotInitializedError(KotonebotError): class ContextNotInitializedError(KotonebotError):
def __init__(self, msg: str = 'Context not initialized'): def __init__(self, msg: str = 'Context not initialized'):
super().__init__(msg) super().__init__(msg)
class StopCurrentTask(KotonebotError):
pass