arkitekt-runtime 4.2.0__tar.gz → 4.3.0__tar.gz
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.
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/PKG-INFO +3 -3
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/types.py +1 -1
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/base.py +61 -2
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/state/observable.py +0 -4
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/actor.py +9 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/shrink.py +6 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/task.py +5 -1
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/pyproject.toml +2 -2
- arkitekt_runtime-4.2.0/arkitekt_runtime/agents/connection.py +0 -19
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/.gitignore +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/README.md +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/actify.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/base.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/build.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/debug.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/dependency.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/errors.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/functional.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/actors/helper.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/backend.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/dataclasses.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/hooks/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/hooks/background.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/hooks/materialize.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/hooks/shutdown.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/hooks/startup.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/journal.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/lock.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/policy.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/transport/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/transport/base.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/transport/types.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/calls.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/constants.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/invoke.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/messages.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/postmans/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/postmans/errors.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/postmans/types.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/qt/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/qt/builders.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/state/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/state/gate.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/state/readonly.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/state/shrink.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/state/write.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/__init__.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/batching.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/context.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/expand.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/memory.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/port_errors.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/postman.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/predication.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/task_scope.py +0 -0
- {arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/types.py +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: arkitekt-runtime
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.0
|
|
4
4
|
Summary: the execution core of an Arkitekt app: agent, actors, tasks, journal, state and structure serialization, shared by every runtime
|
|
5
5
|
Author-email: jhnnsrs <jhnnsrs@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Requires-Python: >=3.11
|
|
8
|
-
Requires-Dist: arkitekt-spec>=
|
|
8
|
+
Requires-Dist: arkitekt-spec>=3.4
|
|
9
9
|
Requires-Dist: janus>=2.0.0
|
|
10
10
|
Requires-Dist: jsonpatch>=1.33
|
|
11
|
-
Requires-Dist: koil>=3.3.
|
|
11
|
+
Requires-Dist: koil>=3.3.6
|
|
12
12
|
Requires-Dist: pydantic>=2.11
|
|
13
13
|
Provides-Extra: qt
|
|
14
14
|
Requires-Dist: qtpy>=2.4; extra == 'qt'
|
|
@@ -22,7 +22,7 @@ from collections.abc import Sequence
|
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
24
|
from arkitekt_spec.declare.app import AppRegistry
|
|
25
|
-
from
|
|
25
|
+
from arkitekt_spec.declare.agents.connection import ConnectionListener
|
|
26
26
|
from arkitekt_runtime.agents.lock import TaskLock
|
|
27
27
|
|
|
28
28
|
|
|
@@ -56,7 +56,13 @@ from arkitekt_runtime.agents.journal import (
|
|
|
56
56
|
)
|
|
57
57
|
from arkitekt_runtime.task_scope import current_task_id, task_id_scope
|
|
58
58
|
from arkitekt_spec.declare.agents.types import AppContext, T
|
|
59
|
-
from
|
|
59
|
+
from arkitekt_spec.declare.agents.connection import (
|
|
60
|
+
ConnectionListener,
|
|
61
|
+
ConnectionState,
|
|
62
|
+
TaskEvent,
|
|
63
|
+
TaskEventKind,
|
|
64
|
+
TaskListener,
|
|
65
|
+
)
|
|
60
66
|
from arkitekt_runtime.agents.policy import ConnectionPolicy
|
|
61
67
|
from arkitekt_spec.declare.agents.hooks.registry import (
|
|
62
68
|
ShutdownHook,
|
|
@@ -220,7 +226,13 @@ class BaseAgent(KoiledModel):
|
|
|
220
226
|
connection_listener: ConnectionListener | None = Field(
|
|
221
227
|
default=None,
|
|
222
228
|
exclude=True,
|
|
223
|
-
description="Told when the backend acknowledges the agent and when the link drops (see
|
|
229
|
+
description="Told when the backend acknowledges the agent and when the link drops (see arkitekt_spec.declare.agents.connection). Settable per run, like force; None reports to nobody.",
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
task_listener: TaskListener | None = Field(
|
|
233
|
+
default=None,
|
|
234
|
+
exclude=True,
|
|
235
|
+
description="Told what happens to each task this agent runs: assigned (with its arguments), progress, yielded, done, failed, cancelled. Settable per run; None reports to nobody.",
|
|
224
236
|
)
|
|
225
237
|
|
|
226
238
|
contexts: dict[str, Any] = Field(
|
|
@@ -968,6 +980,14 @@ class BaseAgent(KoiledModel):
|
|
|
968
980
|
# From here on the task can end, and after its end nothing more is recorded
|
|
969
981
|
# for it: its reports and state changes enter this gate.
|
|
970
982
|
self._task_gates[message.task] = TaskGate()
|
|
983
|
+
await self._anotify_task(
|
|
984
|
+
TaskEvent(
|
|
985
|
+
task_id=message.task,
|
|
986
|
+
action=message.interface,
|
|
987
|
+
kind=TaskEventKind.ASSIGNED,
|
|
988
|
+
arguments=dict(message.args),
|
|
989
|
+
)
|
|
990
|
+
)
|
|
971
991
|
# ...and it is this process's: numbered by step (unless it is a probe).
|
|
972
992
|
self._journal.begin_task(message.task)
|
|
973
993
|
if message.resume is not None:
|
|
@@ -1206,6 +1226,41 @@ class BaseAgent(KoiledModel):
|
|
|
1206
1226
|
except Exception:
|
|
1207
1227
|
logger.warning("The connection listener failed on %s", state.value, exc_info=True)
|
|
1208
1228
|
|
|
1229
|
+
def _task_event_of(self, message: messages.FromAgentMessage) -> TaskEvent | None:
|
|
1230
|
+
"""What a task's report means to a task listener; ``None`` for anything else."""
|
|
1231
|
+
if isinstance(message, messages.Progress):
|
|
1232
|
+
kind, details = TaskEventKind.PROGRESS, {
|
|
1233
|
+
"progress": message.progress,
|
|
1234
|
+
"message": message.message,
|
|
1235
|
+
}
|
|
1236
|
+
elif isinstance(message, messages.Yield):
|
|
1237
|
+
kind, details = TaskEventKind.YIELDED, {}
|
|
1238
|
+
elif isinstance(message, messages.Completed):
|
|
1239
|
+
kind, details = TaskEventKind.DONE, {}
|
|
1240
|
+
elif isinstance(message, (messages.Failed, messages.Critical)):
|
|
1241
|
+
kind, details = TaskEventKind.FAILED, {"error": message.error}
|
|
1242
|
+
elif isinstance(message, (messages.Cancelled, messages.Interrupted)):
|
|
1243
|
+
kind, details = TaskEventKind.CANCELLED, {}
|
|
1244
|
+
else:
|
|
1245
|
+
return None
|
|
1246
|
+
return TaskEvent(
|
|
1247
|
+
task_id=message.task,
|
|
1248
|
+
action=self._action_key_for(message) or message.task,
|
|
1249
|
+
kind=kind,
|
|
1250
|
+
**details,
|
|
1251
|
+
)
|
|
1252
|
+
|
|
1253
|
+
async def _anotify_task(self, event: TaskEvent) -> None:
|
|
1254
|
+
"""Tell the task listener, if there is one."""
|
|
1255
|
+
if self.task_listener is None:
|
|
1256
|
+
return
|
|
1257
|
+
try:
|
|
1258
|
+
await self.task_listener(event)
|
|
1259
|
+
except Exception:
|
|
1260
|
+
logger.warning(
|
|
1261
|
+
"The task listener failed on %s of %s", event.kind.value, event.task_id, exc_info=True
|
|
1262
|
+
)
|
|
1263
|
+
|
|
1209
1264
|
def _start_disconnect_watchdog(self) -> None:
|
|
1210
1265
|
"""Begin counting down the grace periods of disconnect-sensitive actors."""
|
|
1211
1266
|
if (
|
|
@@ -1400,6 +1455,10 @@ class BaseAgent(KoiledModel):
|
|
|
1400
1455
|
)
|
|
1401
1456
|
self._retain_emitted(message, entry)
|
|
1402
1457
|
await self._adeliver(message, entry)
|
|
1458
|
+
if self.task_listener is not None:
|
|
1459
|
+
event = self._task_event_of(message)
|
|
1460
|
+
if event is not None:
|
|
1461
|
+
await self._anotify_task(event)
|
|
1403
1462
|
if isinstance(message, messages.TERMINAL_REPORTS):
|
|
1404
1463
|
# The task is done, so it is no longer running on any actor, and no
|
|
1405
1464
|
# longer an assignment this agent is managing. Nothing used to pop
|
|
@@ -70,9 +70,6 @@ class StateConfig:
|
|
|
70
70
|
|
|
71
71
|
state_name: str
|
|
72
72
|
definition: StateDefinitionInput
|
|
73
|
-
publish_interval: float = (
|
|
74
|
-
0.1 # Optional: Minimum interval between patches to prevent flooding
|
|
75
|
-
)
|
|
76
73
|
required_locks: list[str] = dataclasses.field(default_factory=list)
|
|
77
74
|
publisher: StateHolder | None = dataclasses.field(default=None, compare=False)
|
|
78
75
|
"""Where patches go: the agent that adopted the state. None until then."""
|
|
@@ -91,7 +88,6 @@ class StateConfig:
|
|
|
91
88
|
return cls(
|
|
92
89
|
state_name=declaration.interface,
|
|
93
90
|
definition=declaration.definition,
|
|
94
|
-
publish_interval=declaration.publish_interval,
|
|
95
91
|
required_locks=list(declaration.required_locks),
|
|
96
92
|
)
|
|
97
93
|
|
{arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/structures/serialization/actor.py
RENAMED
|
@@ -660,6 +660,15 @@ async def _shrink_structure(
|
|
|
660
660
|
"Port is structure but does not have identifier. Please report this to the developers.",
|
|
661
661
|
)
|
|
662
662
|
fstruc = ctx.registry.get_fullfilled_structure(port.identifier)
|
|
663
|
+
other = ctx.registry.declared_as_another(value, port.identifier)
|
|
664
|
+
if other is not None:
|
|
665
|
+
raise _shrink_error(
|
|
666
|
+
port,
|
|
667
|
+
value,
|
|
668
|
+
ctx,
|
|
669
|
+
f"A {type(value).__name__} ({other.identifier}) was returned where "
|
|
670
|
+
f"{port.identifier} is declared; its id would be sent as the wrong structure.",
|
|
671
|
+
)
|
|
663
672
|
try:
|
|
664
673
|
shrunk = await fstruc.shrink(value)
|
|
665
674
|
except Exception as e:
|
|
@@ -166,6 +166,12 @@ async def _structure(
|
|
|
166
166
|
# A bare string is taken as a reference to a global structure.
|
|
167
167
|
return value
|
|
168
168
|
fstruc = ctx.registry.get_fullfilled_structure(port.identifier)
|
|
169
|
+
other = ctx.registry.declared_as_another(value, port.identifier)
|
|
170
|
+
if other is not None:
|
|
171
|
+
raise StructureShrinkingError(
|
|
172
|
+
f"A {type(value).__name__} ({other.identifier}) was given where "
|
|
173
|
+
f"{port.identifier} is declared; its id would be sent as the wrong structure."
|
|
174
|
+
)
|
|
169
175
|
try:
|
|
170
176
|
shrunk = await fstruc.shrink(value)
|
|
171
177
|
except Exception:
|
|
@@ -29,7 +29,7 @@ import secrets
|
|
|
29
29
|
import time
|
|
30
30
|
from typing import TYPE_CHECKING, Any, ClassVar
|
|
31
31
|
|
|
32
|
-
from koil import unkoil, unkoil_gen
|
|
32
|
+
from koil import check_cancelled, unkoil, unkoil_gen
|
|
33
33
|
|
|
34
34
|
from arkitekt_spec.actions import Execution
|
|
35
35
|
from arkitekt_spec.declare.agents.errors import NoCallerError
|
|
@@ -141,6 +141,10 @@ class Task:
|
|
|
141
141
|
"""Pause here if the task was asked to."""
|
|
142
142
|
unkoil(self.apausepoint)
|
|
143
143
|
|
|
144
|
+
def check_cancelled(self) -> None:
|
|
145
|
+
"""Stop here if the task was cancelled: the cancellation point of a sync action."""
|
|
146
|
+
check_cancelled()
|
|
147
|
+
|
|
144
148
|
# -- effects ---------------------------------------------------------- #
|
|
145
149
|
# Values the task takes from outside itself, each recorded as an ``EFFECT`` under a
|
|
146
150
|
# key. A resumed workflow gets the recorded value back instead of taking a new one.
|
|
@@ -10,9 +10,9 @@ license = "MIT"
|
|
|
10
10
|
# server) executes actions the same way, so this is what they share. It carries no
|
|
11
11
|
# transport and no client: no websockets, no rath, no graphql-core.
|
|
12
12
|
dependencies = [
|
|
13
|
-
"arkitekt-spec>=
|
|
13
|
+
"arkitekt-spec>=3.4",
|
|
14
14
|
"pydantic>=2.11",
|
|
15
|
-
"koil>=3.3.
|
|
15
|
+
"koil>=3.3.6",
|
|
16
16
|
"janus>=2.0.0",
|
|
17
17
|
"jsonpatch>=1.33",
|
|
18
18
|
]
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"""What an agent tells whoever runs it about its connection to the backend."""
|
|
2
|
-
|
|
3
|
-
from collections.abc import Awaitable, Callable
|
|
4
|
-
from enum import Enum
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ConnectionState(str, Enum):
|
|
8
|
-
"""Where the agent's connection to the backend stands."""
|
|
9
|
-
|
|
10
|
-
REGISTERED = "registered"
|
|
11
|
-
"""The backend acknowledged the agent's registration (an ``Init``). Reported on
|
|
12
|
-
the first connection and again whenever a dropped one is back."""
|
|
13
|
-
DISCONNECTED = "disconnected"
|
|
14
|
-
"""The link dropped and the transport is trying to get it back."""
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
ConnectionListener = Callable[[ConnectionState], Awaitable[None]]
|
|
18
|
-
"""Called with each change of the agent's connection. It only reports: what it
|
|
19
|
-
raises is logged and dropped, never the agent's problem."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/hooks/background.py
RENAMED
|
File without changes
|
{arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/hooks/materialize.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/transport/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{arkitekt_runtime-4.2.0 → arkitekt_runtime-4.3.0}/arkitekt_runtime/agents/transport/types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|