aethergraph 0.1.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aethergraph/__init__.py +49 -0
- aethergraph/config/__init__.py +0 -0
- aethergraph/config/config.py +121 -0
- aethergraph/config/context.py +16 -0
- aethergraph/config/llm.py +26 -0
- aethergraph/config/loader.py +60 -0
- aethergraph/config/runtime.py +9 -0
- aethergraph/contracts/errors/errors.py +44 -0
- aethergraph/contracts/services/artifacts.py +142 -0
- aethergraph/contracts/services/channel.py +72 -0
- aethergraph/contracts/services/continuations.py +23 -0
- aethergraph/contracts/services/eventbus.py +12 -0
- aethergraph/contracts/services/kv.py +24 -0
- aethergraph/contracts/services/llm.py +17 -0
- aethergraph/contracts/services/mcp.py +22 -0
- aethergraph/contracts/services/memory.py +108 -0
- aethergraph/contracts/services/resume.py +28 -0
- aethergraph/contracts/services/state_stores.py +33 -0
- aethergraph/contracts/services/wakeup.py +28 -0
- aethergraph/core/execution/base_scheduler.py +77 -0
- aethergraph/core/execution/forward_scheduler.py +777 -0
- aethergraph/core/execution/global_scheduler.py +634 -0
- aethergraph/core/execution/retry_policy.py +22 -0
- aethergraph/core/execution/step_forward.py +411 -0
- aethergraph/core/execution/step_result.py +18 -0
- aethergraph/core/execution/wait_types.py +72 -0
- aethergraph/core/graph/graph_builder.py +192 -0
- aethergraph/core/graph/graph_fn.py +219 -0
- aethergraph/core/graph/graph_io.py +67 -0
- aethergraph/core/graph/graph_refs.py +154 -0
- aethergraph/core/graph/graph_spec.py +115 -0
- aethergraph/core/graph/graph_state.py +59 -0
- aethergraph/core/graph/graphify.py +128 -0
- aethergraph/core/graph/interpreter.py +145 -0
- aethergraph/core/graph/node_handle.py +33 -0
- aethergraph/core/graph/node_spec.py +46 -0
- aethergraph/core/graph/node_state.py +63 -0
- aethergraph/core/graph/task_graph.py +747 -0
- aethergraph/core/graph/task_node.py +82 -0
- aethergraph/core/graph/utils.py +37 -0
- aethergraph/core/graph/visualize.py +239 -0
- aethergraph/core/runtime/ad_hoc_context.py +61 -0
- aethergraph/core/runtime/base_service.py +153 -0
- aethergraph/core/runtime/bind_adapter.py +42 -0
- aethergraph/core/runtime/bound_memory.py +69 -0
- aethergraph/core/runtime/execution_context.py +220 -0
- aethergraph/core/runtime/graph_runner.py +349 -0
- aethergraph/core/runtime/lifecycle.py +26 -0
- aethergraph/core/runtime/node_context.py +203 -0
- aethergraph/core/runtime/node_services.py +30 -0
- aethergraph/core/runtime/recovery.py +159 -0
- aethergraph/core/runtime/run_registration.py +33 -0
- aethergraph/core/runtime/runtime_env.py +157 -0
- aethergraph/core/runtime/runtime_registry.py +32 -0
- aethergraph/core/runtime/runtime_services.py +224 -0
- aethergraph/core/runtime/wakeup_watcher.py +40 -0
- aethergraph/core/tools/__init__.py +10 -0
- aethergraph/core/tools/builtins/channel_tools.py +194 -0
- aethergraph/core/tools/builtins/toolset.py +134 -0
- aethergraph/core/tools/toolkit.py +510 -0
- aethergraph/core/tools/waitable.py +109 -0
- aethergraph/plugins/channel/__init__.py +0 -0
- aethergraph/plugins/channel/adapters/__init__.py +0 -0
- aethergraph/plugins/channel/adapters/console.py +106 -0
- aethergraph/plugins/channel/adapters/file.py +102 -0
- aethergraph/plugins/channel/adapters/slack.py +285 -0
- aethergraph/plugins/channel/adapters/telegram.py +302 -0
- aethergraph/plugins/channel/adapters/webhook.py +104 -0
- aethergraph/plugins/channel/adapters/webui.py +134 -0
- aethergraph/plugins/channel/routes/__init__.py +0 -0
- aethergraph/plugins/channel/routes/console_routes.py +86 -0
- aethergraph/plugins/channel/routes/slack_routes.py +49 -0
- aethergraph/plugins/channel/routes/telegram_routes.py +26 -0
- aethergraph/plugins/channel/routes/webui_routes.py +136 -0
- aethergraph/plugins/channel/utils/__init__.py +0 -0
- aethergraph/plugins/channel/utils/slack_utils.py +278 -0
- aethergraph/plugins/channel/utils/telegram_utils.py +324 -0
- aethergraph/plugins/channel/websockets/slack_ws.py +68 -0
- aethergraph/plugins/channel/websockets/telegram_polling.py +151 -0
- aethergraph/plugins/mcp/fs_server.py +128 -0
- aethergraph/plugins/mcp/http_server.py +101 -0
- aethergraph/plugins/mcp/ws_server.py +180 -0
- aethergraph/plugins/net/http.py +10 -0
- aethergraph/plugins/utils/data_io.py +359 -0
- aethergraph/runner/__init__.py +5 -0
- aethergraph/runtime/__init__.py +62 -0
- aethergraph/server/__init__.py +3 -0
- aethergraph/server/app_factory.py +84 -0
- aethergraph/server/start.py +122 -0
- aethergraph/services/__init__.py +10 -0
- aethergraph/services/artifacts/facade.py +284 -0
- aethergraph/services/artifacts/factory.py +35 -0
- aethergraph/services/artifacts/fs_store.py +656 -0
- aethergraph/services/artifacts/jsonl_index.py +123 -0
- aethergraph/services/artifacts/paths.py +23 -0
- aethergraph/services/artifacts/sqlite_index.py +209 -0
- aethergraph/services/artifacts/utils.py +124 -0
- aethergraph/services/auth/dev.py +16 -0
- aethergraph/services/channel/channel_bus.py +293 -0
- aethergraph/services/channel/factory.py +44 -0
- aethergraph/services/channel/session.py +511 -0
- aethergraph/services/channel/wait_helpers.py +57 -0
- aethergraph/services/clock/clock.py +9 -0
- aethergraph/services/container/default_container.py +320 -0
- aethergraph/services/continuations/continuation.py +56 -0
- aethergraph/services/continuations/factory.py +34 -0
- aethergraph/services/continuations/stores/fs_store.py +264 -0
- aethergraph/services/continuations/stores/inmem_store.py +95 -0
- aethergraph/services/eventbus/inmem.py +21 -0
- aethergraph/services/features/static.py +10 -0
- aethergraph/services/kv/ephemeral.py +90 -0
- aethergraph/services/kv/factory.py +27 -0
- aethergraph/services/kv/layered.py +41 -0
- aethergraph/services/kv/sqlite_kv.py +128 -0
- aethergraph/services/llm/factory.py +157 -0
- aethergraph/services/llm/generic_client.py +542 -0
- aethergraph/services/llm/providers.py +3 -0
- aethergraph/services/llm/service.py +105 -0
- aethergraph/services/logger/base.py +36 -0
- aethergraph/services/logger/compat.py +50 -0
- aethergraph/services/logger/formatters.py +106 -0
- aethergraph/services/logger/std.py +203 -0
- aethergraph/services/mcp/helpers.py +23 -0
- aethergraph/services/mcp/http_client.py +70 -0
- aethergraph/services/mcp/mcp_tools.py +21 -0
- aethergraph/services/mcp/registry.py +14 -0
- aethergraph/services/mcp/service.py +100 -0
- aethergraph/services/mcp/stdio_client.py +70 -0
- aethergraph/services/mcp/ws_client.py +115 -0
- aethergraph/services/memory/bound.py +106 -0
- aethergraph/services/memory/distillers/episode.py +116 -0
- aethergraph/services/memory/distillers/rolling.py +74 -0
- aethergraph/services/memory/facade.py +633 -0
- aethergraph/services/memory/factory.py +78 -0
- aethergraph/services/memory/hotlog_kv.py +27 -0
- aethergraph/services/memory/indices.py +74 -0
- aethergraph/services/memory/io_helpers.py +72 -0
- aethergraph/services/memory/persist_fs.py +40 -0
- aethergraph/services/memory/resolver.py +152 -0
- aethergraph/services/metering/noop.py +4 -0
- aethergraph/services/prompts/file_store.py +41 -0
- aethergraph/services/rag/chunker.py +29 -0
- aethergraph/services/rag/facade.py +593 -0
- aethergraph/services/rag/index/base.py +27 -0
- aethergraph/services/rag/index/faiss_index.py +121 -0
- aethergraph/services/rag/index/sqlite_index.py +134 -0
- aethergraph/services/rag/index_factory.py +52 -0
- aethergraph/services/rag/parsers/md.py +7 -0
- aethergraph/services/rag/parsers/pdf.py +14 -0
- aethergraph/services/rag/parsers/txt.py +7 -0
- aethergraph/services/rag/utils/hybrid.py +39 -0
- aethergraph/services/rag/utils/make_fs_key.py +62 -0
- aethergraph/services/redactor/simple.py +16 -0
- aethergraph/services/registry/key_parsing.py +44 -0
- aethergraph/services/registry/registry_key.py +19 -0
- aethergraph/services/registry/unified_registry.py +185 -0
- aethergraph/services/resume/multi_scheduler_resume_bus.py +65 -0
- aethergraph/services/resume/router.py +73 -0
- aethergraph/services/schedulers/registry.py +41 -0
- aethergraph/services/secrets/base.py +7 -0
- aethergraph/services/secrets/env.py +8 -0
- aethergraph/services/state_stores/externalize.py +135 -0
- aethergraph/services/state_stores/graph_observer.py +131 -0
- aethergraph/services/state_stores/json_store.py +67 -0
- aethergraph/services/state_stores/resume_policy.py +119 -0
- aethergraph/services/state_stores/serialize.py +249 -0
- aethergraph/services/state_stores/utils.py +91 -0
- aethergraph/services/state_stores/validate.py +78 -0
- aethergraph/services/tracing/noop.py +18 -0
- aethergraph/services/waits/wait_registry.py +91 -0
- aethergraph/services/wakeup/memory_queue.py +57 -0
- aethergraph/services/wakeup/scanner_producer.py +56 -0
- aethergraph/services/wakeup/worker.py +31 -0
- aethergraph/tools/__init__.py +25 -0
- aethergraph/utils/optdeps.py +8 -0
- aethergraph-0.1.0a1.dist-info/METADATA +410 -0
- aethergraph-0.1.0a1.dist-info/RECORD +182 -0
- aethergraph-0.1.0a1.dist-info/WHEEL +5 -0
- aethergraph-0.1.0a1.dist-info/entry_points.txt +2 -0
- aethergraph-0.1.0a1.dist-info/licenses/LICENSE +176 -0
- aethergraph-0.1.0a1.dist-info/licenses/NOTICE +31 -0
- aethergraph-0.1.0a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Literal, Protocol, TypedDict
|
|
5
|
+
|
|
6
|
+
EventKind = Literal[
|
|
7
|
+
"user_msg",
|
|
8
|
+
"assistant_msg",
|
|
9
|
+
"tool_start",
|
|
10
|
+
"tool_result",
|
|
11
|
+
"error",
|
|
12
|
+
"checkpoint",
|
|
13
|
+
"run_summary",
|
|
14
|
+
"rolling_summary",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class Event:
|
|
20
|
+
event_id: str
|
|
21
|
+
ts: str
|
|
22
|
+
run_id: str
|
|
23
|
+
graph_id: str | None = None
|
|
24
|
+
node_id: str | None = None
|
|
25
|
+
agent_id: str | None = None
|
|
26
|
+
tool: str | None = None # now used for tool topic: TODO: rename to topic in future
|
|
27
|
+
kind: EventKind = "tool_result"
|
|
28
|
+
stage: str | None = None
|
|
29
|
+
severity: int = 2
|
|
30
|
+
signal: float = 0.0
|
|
31
|
+
tags: list[str] | None = None
|
|
32
|
+
entities: list[str] | None = None
|
|
33
|
+
inputs: list[Value] | None = None
|
|
34
|
+
outputs: list[Value] | None = None
|
|
35
|
+
inputs_ref: dict[str, Any] | None = None
|
|
36
|
+
outputs_ref: dict[str, Any] | None = None
|
|
37
|
+
metrics: dict[str, float] | None = None
|
|
38
|
+
text: str | None = None
|
|
39
|
+
embedding: list[float] | None = None
|
|
40
|
+
pii_flags: dict[str, bool] | None = None
|
|
41
|
+
sources: list[str] | None = None
|
|
42
|
+
version: int = 1 # for schema evolution
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class HotLog(Protocol):
|
|
46
|
+
async def append(self, run_id: str, evt: Event, *, ttl_s: int, limit: int) -> None: ...
|
|
47
|
+
async def recent(
|
|
48
|
+
self, run_id: str, *, kinds: list[str] | None = None, limit: int = 50
|
|
49
|
+
) -> list[Event]: ...
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Persistence(Protocol):
|
|
53
|
+
async def append_event(self, run_id: str, evt: Event) -> None: ...
|
|
54
|
+
async def save_json(self, uri: str, obj: dict[str, Any]) -> None: ...
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Indices(Protocol):
|
|
58
|
+
async def update(self, run_id: str, evt: Event) -> None: ...
|
|
59
|
+
async def last_by_name(self, run_id: str, name: str) -> dict[str, Any] | None: ...
|
|
60
|
+
async def latest_refs_by_kind(
|
|
61
|
+
self, run_id: str, kind: str, *, limit: int = 50
|
|
62
|
+
) -> list[dict[str, Any]]: ...
|
|
63
|
+
async def last_outputs_by_topic(self, run_id: str, topic: str) -> dict[str, Any] | None: ...
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Distiller(Protocol):
|
|
67
|
+
async def distill(
|
|
68
|
+
self, run_id: str, *, hotlog: HotLog, persistence: Persistence, indices: Indices, **kw
|
|
69
|
+
) -> dict[str, Any]: ...
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------- Vector Index and Embeddings Client Protocols ----------
|
|
73
|
+
class VectorIndex(Protocol):
|
|
74
|
+
async def upsert(self, *, id: str, vector: list[float], metadata: dict) -> None: ...
|
|
75
|
+
async def delete(self, *, id: str) -> None: ...
|
|
76
|
+
async def query(
|
|
77
|
+
self, *, vector: list[float], k: int = 8, filter: dict | None = None
|
|
78
|
+
) -> list[dict]: ...
|
|
79
|
+
async def flush(self) -> None: ...
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class EmbeddingsClient(Protocol):
|
|
83
|
+
async def embed_text(self, text: str, *, model: str | None = None) -> list[float]: ...
|
|
84
|
+
async def embed_texts(
|
|
85
|
+
self, texts: list[str], *, model: str | None = None
|
|
86
|
+
) -> list[list[float]]: ...
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ---------- I/O Value and Ref schemas ----------
|
|
90
|
+
class Ref(TypedDict, total=False):
|
|
91
|
+
"""A resolvable refernece to an external artifact or data."""
|
|
92
|
+
|
|
93
|
+
kind: str # e.g. "spec", "design", "output", "tool_result"
|
|
94
|
+
uri: str # e.g. "file://...", "mem://...", "db://..."
|
|
95
|
+
title: str | None # optional human-readable title
|
|
96
|
+
mime: str | None # optional MIME type, e.g. "image/png"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Value(TypedDict, total=False):
|
|
100
|
+
"""
|
|
101
|
+
A named I/O slot that can hold any JSON-serializable value, including a Ref.
|
|
102
|
+
vtype declares the JSON type; if vtype == "ref", value must be a Ref dict.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
name: str
|
|
106
|
+
vtype: Literal["ref", "number", "string", "boolean", "object", "array", "null"]
|
|
107
|
+
value: Any # actual value; type depends on vtype
|
|
108
|
+
meta: dict[str, Any] | None # optional metadata dictionary
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ResumeBus(Protocol):
|
|
7
|
+
"""
|
|
8
|
+
Abstract transport for resuming a waiting node.
|
|
9
|
+
Implementations may be:
|
|
10
|
+
- InProcessResumeBus: directly calls the in-memory scheduler
|
|
11
|
+
- HttpResumeBus: POSTs to a remote scheduler service (not shown here)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
async def enqueue_resume(self, *, run_id: str, node_id: str, token: str, payload: dict) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Verify the continuation/token (or let the backend do it), then
|
|
18
|
+
trigger a resume for (run_id, node_id) with the given payload.
|
|
19
|
+
Should be idempotent and safe to call multiple times.
|
|
20
|
+
"""
|
|
21
|
+
raise NotImplementedError
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class ResumeEvent:
|
|
26
|
+
run_id: str
|
|
27
|
+
node_id: str
|
|
28
|
+
payload: dict
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# aethergraph/persist/interfaces.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, Protocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class GraphSnapshot:
|
|
10
|
+
run_id: str
|
|
11
|
+
graph_id: str
|
|
12
|
+
rev: int
|
|
13
|
+
created_at: float # epoch seconds
|
|
14
|
+
spec_hash: str # detect spec drift
|
|
15
|
+
state: dict[str, Any] # JSON-serializable TaskGraphState
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class StateEvent:
|
|
20
|
+
run_id: str
|
|
21
|
+
graph_id: str
|
|
22
|
+
rev: int
|
|
23
|
+
ts: float
|
|
24
|
+
kind: str # "STATUS" | "OUTPUT" | "INPUTS_BOUND" | "PATCH"
|
|
25
|
+
payload: dict[str, Any]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GraphStateStore(Protocol):
|
|
29
|
+
async def save_snapshot(self, snap: GraphSnapshot) -> None: ...
|
|
30
|
+
async def load_latest_snapshot(self, run_id: str) -> GraphSnapshot | None: ...
|
|
31
|
+
async def append_event(self, ev: StateEvent) -> None: ...
|
|
32
|
+
async def load_events_since(self, run_id: str, from_rev: int) -> list[StateEvent]: ...
|
|
33
|
+
async def list_run_ids(self, graph_id: str | None = None) -> list[str]: ...
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# core/contracts/wakeup.py
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, Protocol
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class WakeLease(Protocol):
|
|
7
|
+
"""Lease handle for a wakeup message."""
|
|
8
|
+
|
|
9
|
+
id: str
|
|
10
|
+
msg: dict[str, Any] # {run_id, node_id, token, payload, ...}
|
|
11
|
+
visibility_deadline: float
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WakeupQueue(Protocol):
|
|
15
|
+
"""Protocol for a wakeup queue service."""
|
|
16
|
+
|
|
17
|
+
async def enqueue(self, topic: str, msg: dict[str, Any], delay_s: float = 0) -> str: ...
|
|
18
|
+
async def lease(self, topic: str, max_items: int = 1, lease_s: int = 60) -> list[WakeLease]: ...
|
|
19
|
+
async def extend(self, lease: WakeLease, lease_s: int) -> None: ...
|
|
20
|
+
async def ack(self, lease: WakeLease) -> None: ...
|
|
21
|
+
async def nack(
|
|
22
|
+
self, lease: WakeLease, requeue_delay_s: float = 5
|
|
23
|
+
) -> None: ... # re-enqueue the message
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class WakeupEvent:
|
|
28
|
+
node_id: str
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from aethergraph.core.graph.task_node import TaskNodeRuntime
|
|
5
|
+
|
|
6
|
+
# from aethergraph.logging_config import logger
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
ExecutionMode = Literal["forward", "backward"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseScheduler:
|
|
13
|
+
def __init__(self, graph, mode: ExecutionMode):
|
|
14
|
+
self.graph = graph
|
|
15
|
+
self.mode = mode
|
|
16
|
+
self._pause_event = asyncio.Event()
|
|
17
|
+
self._pause_event.set()
|
|
18
|
+
self._terminated = False
|
|
19
|
+
self.running_tasks = {} # Dictionary to track currently running tasks
|
|
20
|
+
|
|
21
|
+
self._nodes_to_pause = [] # Nodes that are requested to be paused
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def status(self) -> str:
|
|
25
|
+
if self._terminated:
|
|
26
|
+
return "terminated"
|
|
27
|
+
if not self._pause_event.is_set():
|
|
28
|
+
return "paused"
|
|
29
|
+
if self.get_running_task_node_ids():
|
|
30
|
+
return "running"
|
|
31
|
+
return "idle"
|
|
32
|
+
|
|
33
|
+
def reset_status(self):
|
|
34
|
+
"""
|
|
35
|
+
Reset the scheduler's status to idle.
|
|
36
|
+
"""
|
|
37
|
+
self._terminated = False
|
|
38
|
+
self._pause_event.set()
|
|
39
|
+
self.running_tasks.clear()
|
|
40
|
+
# logger.info(f"🔄 Scheduler status reset for graph `{self.graph.id}`")
|
|
41
|
+
|
|
42
|
+
def set_mode(self, mode: ExecutionMode):
|
|
43
|
+
"""
|
|
44
|
+
Set the execution mode for this scheduler.
|
|
45
|
+
"""
|
|
46
|
+
if mode not in ["forward", "backward"]:
|
|
47
|
+
raise ValueError(f"❌ Invalid execution mode: {mode}")
|
|
48
|
+
self.mode = mode
|
|
49
|
+
# logger.info(f"🔄 Execution mode set to {self.mode}")
|
|
50
|
+
|
|
51
|
+
def get_running_task_node_ids(self) -> list[str]:
|
|
52
|
+
"""
|
|
53
|
+
Get a list of currently running task node IDs.
|
|
54
|
+
"""
|
|
55
|
+
return [nid for nid, task in self.running_tasks.items() if not task.done()]
|
|
56
|
+
|
|
57
|
+
async def run(self):
|
|
58
|
+
raise NotImplementedError
|
|
59
|
+
|
|
60
|
+
async def run_from(self, node_ids: list[str]):
|
|
61
|
+
raise NotImplementedError("run_from() must be implemented in subclass")
|
|
62
|
+
|
|
63
|
+
async def pause(self):
|
|
64
|
+
self._pause_event.clear()
|
|
65
|
+
|
|
66
|
+
async def resume(self):
|
|
67
|
+
self._pause_event.set()
|
|
68
|
+
|
|
69
|
+
async def terminate(self):
|
|
70
|
+
self._terminated = True
|
|
71
|
+
raise NotImplementedError("terminate() must be implemented in subclass")
|
|
72
|
+
|
|
73
|
+
async def run_node(self, node: TaskNodeRuntime):
|
|
74
|
+
raise NotImplementedError("run_node() must be implemented in subclass")
|
|
75
|
+
|
|
76
|
+
async def step_next(self):
|
|
77
|
+
raise NotImplementedError("step_next() must be implemented in subclass")
|