edda-framework 0.9.1__py3-none-any.whl → 0.11.0__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.
- edda/app.py +419 -26
- edda/integrations/mirascope/__init__.py +78 -0
- edda/integrations/mirascope/agent.py +467 -0
- edda/integrations/mirascope/call.py +166 -0
- edda/integrations/mirascope/decorator.py +163 -0
- edda/integrations/mirascope/types.py +268 -0
- edda/outbox/relayer.py +21 -2
- edda/storage/__init__.py +8 -0
- edda/storage/notify_base.py +162 -0
- edda/storage/pg_notify.py +325 -0
- edda/storage/protocol.py +9 -1
- edda/storage/sqlalchemy_storage.py +193 -13
- edda/viewer_ui/app.py +26 -0
- edda/viewer_ui/data_service.py +4 -0
- {edda_framework-0.9.1.dist-info → edda_framework-0.11.0.dist-info}/METADATA +17 -1
- {edda_framework-0.9.1.dist-info → edda_framework-0.11.0.dist-info}/RECORD +19 -12
- {edda_framework-0.9.1.dist-info → edda_framework-0.11.0.dist-info}/WHEEL +0 -0
- {edda_framework-0.9.1.dist-info → edda_framework-0.11.0.dist-info}/entry_points.txt +0 -0
- {edda_framework-0.9.1.dist-info → edda_framework-0.11.0.dist-info}/licenses/LICENSE +0 -0
edda/viewer_ui/app.py
CHANGED
|
@@ -1296,6 +1296,8 @@ def start_viewer(edda_app: EddaApp, port: int = 8080, reload: bool = False) -> N
|
|
|
1296
1296
|
"search_query": "",
|
|
1297
1297
|
"started_after": None,
|
|
1298
1298
|
"started_before": None,
|
|
1299
|
+
"input_filter_key": "",
|
|
1300
|
+
"input_filter_value": "",
|
|
1299
1301
|
"instances": [],
|
|
1300
1302
|
"next_page_token": None,
|
|
1301
1303
|
"has_more": False,
|
|
@@ -1352,6 +1354,17 @@ def start_viewer(edda_app: EddaApp, port: int = 8080, reload: bool = False) -> N
|
|
|
1352
1354
|
"click", lambda m=date_to_menu: m.open()
|
|
1353
1355
|
)
|
|
1354
1356
|
|
|
1357
|
+
# Input data filter fields
|
|
1358
|
+
input_key = ui.input(
|
|
1359
|
+
label="Input Key",
|
|
1360
|
+
placeholder="e.g., input.order_id",
|
|
1361
|
+
).classes("w-40")
|
|
1362
|
+
|
|
1363
|
+
input_value = ui.input(
|
|
1364
|
+
label="Input Value",
|
|
1365
|
+
placeholder="e.g., ORD-123",
|
|
1366
|
+
).classes("w-36")
|
|
1367
|
+
|
|
1355
1368
|
# Refresh button
|
|
1356
1369
|
async def handle_refresh() -> None:
|
|
1357
1370
|
"""Handle refresh button click."""
|
|
@@ -1360,6 +1373,11 @@ def start_viewer(edda_app: EddaApp, port: int = 8080, reload: bool = False) -> N
|
|
|
1360
1373
|
pagination_state["page_size"] = page_size_select.value
|
|
1361
1374
|
pagination_state["started_after"] = date_from.value
|
|
1362
1375
|
pagination_state["started_before"] = date_to.value
|
|
1376
|
+
pagination_state["input_filter_key"] = input_key.value
|
|
1377
|
+
pagination_state["input_filter_value"] = input_value.value
|
|
1378
|
+
# Debug output
|
|
1379
|
+
print(f"DEBUG: input_key.value = '{input_key.value}'")
|
|
1380
|
+
print(f"DEBUG: input_value.value = '{input_value.value}'")
|
|
1363
1381
|
# Reset to first page
|
|
1364
1382
|
pagination_state["current_token"] = None
|
|
1365
1383
|
pagination_state["token_stack"] = []
|
|
@@ -1389,6 +1407,13 @@ def start_viewer(edda_app: EddaApp, port: int = 8080, reload: bool = False) -> N
|
|
|
1389
1407
|
pagination_state["started_before"] + "T23:59:59"
|
|
1390
1408
|
)
|
|
1391
1409
|
|
|
1410
|
+
# Build input_filters if key is provided
|
|
1411
|
+
input_filters = None
|
|
1412
|
+
if pagination_state["input_filter_key"]:
|
|
1413
|
+
input_filters = {
|
|
1414
|
+
pagination_state["input_filter_key"]: pagination_state["input_filter_value"]
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1392
1417
|
result = await service.get_instances_paginated(
|
|
1393
1418
|
page_size=pagination_state["page_size"],
|
|
1394
1419
|
page_token=pagination_state["current_token"],
|
|
@@ -1396,6 +1421,7 @@ def start_viewer(edda_app: EddaApp, port: int = 8080, reload: bool = False) -> N
|
|
|
1396
1421
|
search_query=pagination_state["search_query"] or None,
|
|
1397
1422
|
started_after=started_after,
|
|
1398
1423
|
started_before=started_before,
|
|
1424
|
+
input_filters=input_filters,
|
|
1399
1425
|
)
|
|
1400
1426
|
pagination_state["instances"] = result["instances"]
|
|
1401
1427
|
pagination_state["next_page_token"] = result["next_page_token"]
|
edda/viewer_ui/data_service.py
CHANGED
|
@@ -48,6 +48,7 @@ class WorkflowDataService:
|
|
|
48
48
|
search_query: str | None = None,
|
|
49
49
|
started_after: datetime | None = None,
|
|
50
50
|
started_before: datetime | None = None,
|
|
51
|
+
input_filters: dict[str, Any] | None = None,
|
|
51
52
|
) -> dict[str, Any]:
|
|
52
53
|
"""
|
|
53
54
|
Get workflow instances with cursor-based pagination and filtering.
|
|
@@ -59,6 +60,8 @@ class WorkflowDataService:
|
|
|
59
60
|
search_query: Search by workflow name or instance ID (partial match)
|
|
60
61
|
started_after: Filter instances started after this datetime
|
|
61
62
|
started_before: Filter instances started before this datetime
|
|
63
|
+
input_filters: Filter by input data values. Keys are JSON paths
|
|
64
|
+
(e.g., "order_id"), values are expected values (exact match).
|
|
62
65
|
|
|
63
66
|
Returns:
|
|
64
67
|
Dictionary containing:
|
|
@@ -75,6 +78,7 @@ class WorkflowDataService:
|
|
|
75
78
|
instance_id_filter=search_query,
|
|
76
79
|
started_after=started_after,
|
|
77
80
|
started_before=started_before,
|
|
81
|
+
input_filters=input_filters,
|
|
78
82
|
)
|
|
79
83
|
return result
|
|
80
84
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: edda-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: Lightweight Durable Execution Framework
|
|
5
5
|
Project-URL: Homepage, https://github.com/i2y/edda
|
|
6
6
|
Project-URL: Documentation, https://github.com/i2y/edda#readme
|
|
@@ -28,6 +28,8 @@ Requires-Dist: httpx>=0.28.1
|
|
|
28
28
|
Requires-Dist: pydantic>=2.0.0
|
|
29
29
|
Requires-Dist: sqlalchemy[asyncio]>=2.0.0
|
|
30
30
|
Requires-Dist: uvloop>=0.22.1
|
|
31
|
+
Provides-Extra: cpu-monitor
|
|
32
|
+
Requires-Dist: psutil>=5.9.0; extra == 'cpu-monitor'
|
|
31
33
|
Provides-Extra: dev
|
|
32
34
|
Requires-Dist: black>=25.9.0; extra == 'dev'
|
|
33
35
|
Requires-Dist: mcp>=1.22.0; extra == 'dev'
|
|
@@ -42,12 +44,17 @@ Requires-Dist: testcontainers[postgres]>=4.0.0; extra == 'dev'
|
|
|
42
44
|
Requires-Dist: tsuno>=0.1.3; extra == 'dev'
|
|
43
45
|
Provides-Extra: mcp
|
|
44
46
|
Requires-Dist: mcp>=1.22.0; extra == 'mcp'
|
|
47
|
+
Provides-Extra: mirascope
|
|
48
|
+
Requires-Dist: mirascope[anthropic,google,openai]>=2.0.0a0; extra == 'mirascope'
|
|
49
|
+
Requires-Dist: pydantic-settings>=2.0.0; extra == 'mirascope'
|
|
45
50
|
Provides-Extra: mysql
|
|
46
51
|
Requires-Dist: aiomysql>=0.2.0; extra == 'mysql'
|
|
47
52
|
Provides-Extra: opentelemetry
|
|
48
53
|
Requires-Dist: opentelemetry-api>=1.20.0; extra == 'opentelemetry'
|
|
49
54
|
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0; extra == 'opentelemetry'
|
|
50
55
|
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'opentelemetry'
|
|
56
|
+
Provides-Extra: postgres-notify
|
|
57
|
+
Requires-Dist: asyncpg>=0.30.0; extra == 'postgres-notify'
|
|
51
58
|
Provides-Extra: postgresql
|
|
52
59
|
Requires-Dist: asyncpg>=0.30.0; extra == 'postgresql'
|
|
53
60
|
Provides-Extra: server
|
|
@@ -87,7 +94,9 @@ For detailed documentation, visit [https://i2y.github.io/edda/](https://i2y.gith
|
|
|
87
94
|
- ☁️ **CloudEvents Support**: Native support for CloudEvents protocol
|
|
88
95
|
- ⏱️ **Event & Timer Waiting**: Free up worker resources while waiting for events or timers, resume on any available worker
|
|
89
96
|
- 📬 **Channel-based Messaging**: Actor-model style communication with competing (job queue) and broadcast (fan-out) modes
|
|
97
|
+
- ⚡ **Instant Notifications**: PostgreSQL LISTEN/NOTIFY for near-instant event delivery (optional)
|
|
90
98
|
- 🤖 **MCP Integration**: Expose durable workflows as AI tools via Model Context Protocol
|
|
99
|
+
- 🧠 **Mirascope Integration**: Durable LLM calls
|
|
91
100
|
- 🌍 **ASGI/WSGI Support**: Deploy with your preferred server (uvicorn, gunicorn, uWSGI)
|
|
92
101
|
|
|
93
102
|
## Use Cases
|
|
@@ -221,6 +230,9 @@ uv add edda-framework --extra mysql
|
|
|
221
230
|
# With Viewer UI
|
|
222
231
|
uv add edda-framework --extra viewer
|
|
223
232
|
|
|
233
|
+
# With PostgreSQL instant notifications (LISTEN/NOTIFY)
|
|
234
|
+
uv add edda-framework --extra postgres-notify
|
|
235
|
+
|
|
224
236
|
# All extras (PostgreSQL, MySQL, Viewer UI)
|
|
225
237
|
uv add edda-framework --extra postgresql --extra mysql --extra viewer
|
|
226
238
|
```
|
|
@@ -272,6 +284,8 @@ pip install "git+https://github.com/i2y/edda.git[postgresql,viewer]"
|
|
|
272
284
|
|
|
273
285
|
**Important**: For multi-process or multi-pod deployments (K8s, Docker Compose with multiple replicas, etc.), you **must** use PostgreSQL or MySQL. SQLite supports multiple async workers within a single process, but its table-level locking makes it unsuitable for multi-process/multi-pod scenarios.
|
|
274
286
|
|
|
287
|
+
> **Tip**: For PostgreSQL, install the `postgres-notify` extra for near-instant event delivery using LISTEN/NOTIFY instead of polling.
|
|
288
|
+
|
|
275
289
|
### Development Installation
|
|
276
290
|
|
|
277
291
|
If you want to contribute to Edda or modify the framework itself:
|
|
@@ -492,6 +506,8 @@ app = EddaApp(
|
|
|
492
506
|
# Connection pool settings (optional)
|
|
493
507
|
pool_size=5, # Concurrent connections
|
|
494
508
|
max_overflow=10, # Additional burst capacity
|
|
509
|
+
# Batch processing (optional)
|
|
510
|
+
max_workflows_per_batch=10, # Or "auto" / "auto:cpu" for dynamic scaling
|
|
495
511
|
)
|
|
496
512
|
```
|
|
497
513
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
edda/__init__.py,sha256=hGC6WR2R36M8LWC97F-0Rw4Ln0QUUT_1xC-7acOy_Fk,2237
|
|
2
2
|
edda/activity.py,sha256=nRm9eBrr0lFe4ZRQ2whyZ6mo5xd171ITIVhqytUhOpw,21025
|
|
3
|
-
edda/app.py,sha256=
|
|
3
|
+
edda/app.py,sha256=hoxDKp6q5qHl_dNLMkLxKhuibUC6D8FtuiWsIZkzwhA,61546
|
|
4
4
|
edda/channels.py,sha256=Budi0FyxalmcAMwj50mX3WzRce5OuLKXGws0Hp_snfw,34745
|
|
5
5
|
edda/compensation.py,sha256=iKLlnTxiF1YSatmYQW84EkPB1yMKUEZBtgjuGnghLtY,11824
|
|
6
6
|
edda/context.py,sha256=pPn98-G5HgaOGDRzEhma58TzBulwsiTvmNEMLIu0XwI,21330
|
|
@@ -16,28 +16,35 @@ edda/integrations/__init__.py,sha256=F_CaTvlDEbldfOpPKq_U9ve1E573tS6XzqXnOtyHcXI
|
|
|
16
16
|
edda/integrations/mcp/__init__.py,sha256=YK-8m0DIdP-RSqewlIX7xnWU7TD3NioCiW2_aZSgnn8,1232
|
|
17
17
|
edda/integrations/mcp/decorators.py,sha256=31SmbDwmHEGvUNa3aaatW91hBkpnS5iN9uy47dID3J4,10037
|
|
18
18
|
edda/integrations/mcp/server.py,sha256=Q5r4AbMn-9gBcy2CZocbgW7O0fn7Qb4e9CBJa1FEmzU,14507
|
|
19
|
+
edda/integrations/mirascope/__init__.py,sha256=TKKIs1W2ef88qT1oNoNm0-DQZObOc7tiuw3ul38nc6U,2509
|
|
20
|
+
edda/integrations/mirascope/agent.py,sha256=9y2HmyEDs5zREJgRuXI9EINjj09rWy991Khs7eDXfyY,16235
|
|
21
|
+
edda/integrations/mirascope/call.py,sha256=2pSDrja8Zix6d3TM4VejLmp1DHxbUnSAdSBSg7CFC7k,5754
|
|
22
|
+
edda/integrations/mirascope/decorator.py,sha256=TIK9qoR5ydaz-r33HAMuLrY4rsKJ5tsPlJJp5T_06B8,5488
|
|
23
|
+
edda/integrations/mirascope/types.py,sha256=vgEAu8EFTLSd92XSAxtZpMoe5gv93fe4Rm0DaXaDlV8,9088
|
|
19
24
|
edda/integrations/opentelemetry/__init__.py,sha256=x1_PyyygGDW-rxQTwoIrGzyjKErXHOOKdquFAMlCOAo,906
|
|
20
25
|
edda/integrations/opentelemetry/hooks.py,sha256=rCb6K_gJJMxjQ-UoJnbIOWsafapipzu7w-YPROZKxDA,21330
|
|
21
26
|
edda/outbox/__init__.py,sha256=azXG1rtheJEjOyoWmMsBeR2jp8Bz02R3wDEd5tQnaWA,424
|
|
22
|
-
edda/outbox/relayer.py,sha256=
|
|
27
|
+
edda/outbox/relayer.py,sha256=_yOZVpjj862lzMtEK47RMdVdbxXmL8v-FXppZWdy4Ag,10444
|
|
23
28
|
edda/outbox/transactional.py,sha256=LFfUjunqRlGibaINi-efGXFFivWGO7v3mhqrqyGW6Nw,3808
|
|
24
29
|
edda/serialization/__init__.py,sha256=hnOVJN-mJNIsSa_XH9jwhIydOsWvIfCaFaSd37HUplg,216
|
|
25
30
|
edda/serialization/base.py,sha256=xJy2CY9gdJDCF0tmCor8NomL2Lr_w7cveVvxccuc-tA,1998
|
|
26
31
|
edda/serialization/json.py,sha256=Dq96V4n1yozexjCPd_CL6Iuvh1u3jJhef6sTcNxXZeA,2842
|
|
27
|
-
edda/storage/__init__.py,sha256=
|
|
32
|
+
edda/storage/__init__.py,sha256=NjvAzYV3SknACrC16ZQOA-xCKOj1-s3rBIWOS1ZGCaM,407
|
|
28
33
|
edda/storage/models.py,sha256=vUwjiAOvp9uFNQgLK57kEGo7uzXplDZikOfnlOyed2M,12146
|
|
29
|
-
edda/storage/
|
|
30
|
-
edda/storage/
|
|
34
|
+
edda/storage/notify_base.py,sha256=gUb-ypG1Bo0c-KrleYmC7eKtdwQNUeqGS5k7UILlSsQ,5055
|
|
35
|
+
edda/storage/pg_notify.py,sha256=to5rDIQbiqqkNNVMODye_KvY4EDqRSUQblTeoeDZv8w,11850
|
|
36
|
+
edda/storage/protocol.py,sha256=vdB5GvBen8lgUA0qEfBXfQTLbVfGKeBTQuEwSUqLZtI,39463
|
|
37
|
+
edda/storage/sqlalchemy_storage.py,sha256=IAc8SYHM2xoJEIVDG05_mkguWQGB3wIAALsc0QI8EcE,144484
|
|
31
38
|
edda/viewer_ui/__init__.py,sha256=N1-T33SXadOXcBsDSgJJ9Iqz4y4verJngWryQu70c5c,517
|
|
32
|
-
edda/viewer_ui/app.py,sha256=
|
|
39
|
+
edda/viewer_ui/app.py,sha256=K3c5sMeJz_AE9gh5QftxwvfDthLeJi1i2CDkP9gb4Ig,96695
|
|
33
40
|
edda/viewer_ui/components.py,sha256=A0IxLwgj_Lu51O57OfzOwME8jzoJtKegEVvSnWc7uPo,45174
|
|
34
|
-
edda/viewer_ui/data_service.py,sha256=
|
|
41
|
+
edda/viewer_ui/data_service.py,sha256=KOqnWr-Y8seH_dkJH_ejHRfxQqn7aY8Ni5C54tx2Z-E,36621
|
|
35
42
|
edda/viewer_ui/theme.py,sha256=mrXoXLRzgSnvE2a58LuMcPJkhlvHEDMWVa8Smqtk4l0,8118
|
|
36
43
|
edda/visualizer/__init__.py,sha256=DOpDstNhR0VcXAs_eMKxaL30p_0u4PKZ4o2ndnYhiRo,343
|
|
37
44
|
edda/visualizer/ast_analyzer.py,sha256=plmx7C9X_X35xLY80jxOL3ljg3afXxBePRZubqUIkxY,13663
|
|
38
45
|
edda/visualizer/mermaid_generator.py,sha256=XWa2egoOTNDfJEjPcwoxwQmblUqXf7YInWFjFRI1QGo,12457
|
|
39
|
-
edda_framework-0.
|
|
40
|
-
edda_framework-0.
|
|
41
|
-
edda_framework-0.
|
|
42
|
-
edda_framework-0.
|
|
43
|
-
edda_framework-0.
|
|
46
|
+
edda_framework-0.11.0.dist-info/METADATA,sha256=AkgFtGUJNfhOoHXzti_R7fLli1q45Bg5xO6TfpjvsO8,36587
|
|
47
|
+
edda_framework-0.11.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
48
|
+
edda_framework-0.11.0.dist-info/entry_points.txt,sha256=dPH47s6UoJgUZxHoeSMqZsQkLaSE-SGLi-gh88k2WrU,48
|
|
49
|
+
edda_framework-0.11.0.dist-info/licenses/LICENSE,sha256=udxb-V7_cYKTHqW7lNm48rxJ-Zpf0WAY_PyGDK9BPCo,1069
|
|
50
|
+
edda_framework-0.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|