aethergraph 0.1.0a1__py3-none-any.whl → 0.1.0a3__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 +4 -10
- aethergraph/__main__.py +296 -0
- aethergraph/api/v1/__init__.py +0 -0
- aethergraph/api/v1/agents.py +46 -0
- aethergraph/api/v1/apps.py +70 -0
- aethergraph/api/v1/artifacts.py +415 -0
- aethergraph/api/v1/channels.py +89 -0
- aethergraph/api/v1/deps.py +168 -0
- aethergraph/api/v1/graphs.py +259 -0
- aethergraph/api/v1/identity.py +25 -0
- aethergraph/api/v1/memory.py +353 -0
- aethergraph/api/v1/misc.py +47 -0
- aethergraph/api/v1/pagination.py +29 -0
- aethergraph/api/v1/runs.py +568 -0
- aethergraph/api/v1/schemas.py +535 -0
- aethergraph/api/v1/session.py +323 -0
- aethergraph/api/v1/stats.py +201 -0
- aethergraph/api/v1/viz.py +152 -0
- aethergraph/config/config.py +22 -0
- aethergraph/config/loader.py +3 -2
- aethergraph/config/storage.py +209 -0
- aethergraph/contracts/__init__.py +0 -0
- aethergraph/contracts/services/__init__.py +0 -0
- aethergraph/contracts/services/artifacts.py +27 -14
- aethergraph/contracts/services/memory.py +45 -17
- aethergraph/contracts/services/metering.py +129 -0
- aethergraph/contracts/services/runs.py +50 -0
- aethergraph/contracts/services/sessions.py +87 -0
- aethergraph/contracts/services/state_stores.py +3 -0
- aethergraph/contracts/services/viz.py +44 -0
- aethergraph/contracts/storage/artifact_index.py +88 -0
- aethergraph/contracts/storage/artifact_store.py +99 -0
- aethergraph/contracts/storage/async_kv.py +34 -0
- aethergraph/contracts/storage/blob_store.py +50 -0
- aethergraph/contracts/storage/doc_store.py +35 -0
- aethergraph/contracts/storage/event_log.py +31 -0
- aethergraph/contracts/storage/vector_index.py +48 -0
- aethergraph/core/__init__.py +0 -0
- aethergraph/core/execution/forward_scheduler.py +13 -2
- aethergraph/core/execution/global_scheduler.py +21 -15
- aethergraph/core/execution/step_forward.py +10 -1
- aethergraph/core/graph/__init__.py +0 -0
- aethergraph/core/graph/graph_builder.py +8 -4
- aethergraph/core/graph/graph_fn.py +156 -15
- aethergraph/core/graph/graph_spec.py +8 -0
- aethergraph/core/graph/graphify.py +146 -27
- aethergraph/core/graph/node_spec.py +0 -2
- aethergraph/core/graph/node_state.py +3 -0
- aethergraph/core/graph/task_graph.py +39 -1
- aethergraph/core/runtime/__init__.py +0 -0
- aethergraph/core/runtime/ad_hoc_context.py +64 -4
- aethergraph/core/runtime/base_service.py +28 -4
- aethergraph/core/runtime/execution_context.py +13 -15
- aethergraph/core/runtime/graph_runner.py +222 -37
- aethergraph/core/runtime/node_context.py +510 -6
- aethergraph/core/runtime/node_services.py +12 -5
- aethergraph/core/runtime/recovery.py +15 -1
- aethergraph/core/runtime/run_manager.py +783 -0
- aethergraph/core/runtime/run_manager_local.py +204 -0
- aethergraph/core/runtime/run_registration.py +2 -2
- aethergraph/core/runtime/run_types.py +89 -0
- aethergraph/core/runtime/runtime_env.py +136 -7
- aethergraph/core/runtime/runtime_metering.py +71 -0
- aethergraph/core/runtime/runtime_registry.py +36 -13
- aethergraph/core/runtime/runtime_services.py +194 -6
- aethergraph/core/tools/builtins/toolset.py +1 -1
- aethergraph/core/tools/toolkit.py +5 -0
- aethergraph/plugins/agents/default_chat_agent copy.py +90 -0
- aethergraph/plugins/agents/default_chat_agent.py +171 -0
- aethergraph/plugins/agents/shared.py +81 -0
- aethergraph/plugins/channel/adapters/webui.py +112 -112
- aethergraph/plugins/channel/routes/webui_routes.py +367 -102
- aethergraph/plugins/channel/utils/slack_utils.py +115 -59
- aethergraph/plugins/channel/utils/telegram_utils.py +88 -47
- aethergraph/plugins/channel/websockets/weibui_ws.py +172 -0
- aethergraph/runtime/__init__.py +15 -0
- aethergraph/server/app_factory.py +196 -34
- aethergraph/server/clients/channel_client.py +202 -0
- aethergraph/server/http/channel_http_routes.py +116 -0
- aethergraph/server/http/channel_ws_routers.py +45 -0
- aethergraph/server/loading.py +117 -0
- aethergraph/server/server.py +131 -0
- aethergraph/server/server_state.py +240 -0
- aethergraph/server/start.py +227 -66
- aethergraph/server/ui_static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- aethergraph/server/ui_static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- aethergraph/server/ui_static/assets/index-BR5GtXcZ.css +1 -0
- aethergraph/server/ui_static/assets/index-CQ0HZZ83.js +400 -0
- aethergraph/server/ui_static/index.html +15 -0
- aethergraph/server/ui_static/logo.png +0 -0
- aethergraph/services/artifacts/__init__.py +0 -0
- aethergraph/services/artifacts/facade.py +1239 -132
- aethergraph/services/auth/{dev.py → authn.py} +0 -8
- aethergraph/services/auth/authz.py +100 -0
- aethergraph/services/channel/__init__.py +0 -0
- aethergraph/services/channel/channel_bus.py +19 -1
- aethergraph/services/channel/factory.py +13 -1
- aethergraph/services/channel/ingress.py +311 -0
- aethergraph/services/channel/queue_adapter.py +75 -0
- aethergraph/services/channel/session.py +502 -19
- aethergraph/services/container/default_container.py +122 -43
- aethergraph/services/continuations/continuation.py +6 -0
- aethergraph/services/continuations/stores/fs_store.py +19 -0
- aethergraph/services/eventhub/event_hub.py +76 -0
- aethergraph/services/kv/__init__.py +0 -0
- aethergraph/services/kv/ephemeral.py +244 -0
- aethergraph/services/llm/__init__.py +0 -0
- aethergraph/services/llm/generic_client copy.py +691 -0
- aethergraph/services/llm/generic_client.py +1288 -187
- aethergraph/services/llm/providers.py +3 -1
- aethergraph/services/llm/types.py +47 -0
- aethergraph/services/llm/utils.py +284 -0
- aethergraph/services/logger/std.py +3 -0
- aethergraph/services/mcp/__init__.py +9 -0
- aethergraph/services/mcp/http_client.py +38 -0
- aethergraph/services/mcp/service.py +225 -1
- aethergraph/services/mcp/stdio_client.py +41 -6
- aethergraph/services/mcp/ws_client.py +44 -2
- aethergraph/services/memory/__init__.py +0 -0
- aethergraph/services/memory/distillers/llm_long_term.py +234 -0
- aethergraph/services/memory/distillers/llm_meta_summary.py +398 -0
- aethergraph/services/memory/distillers/long_term.py +225 -0
- aethergraph/services/memory/facade/__init__.py +3 -0
- aethergraph/services/memory/facade/chat.py +440 -0
- aethergraph/services/memory/facade/core.py +447 -0
- aethergraph/services/memory/facade/distillation.py +424 -0
- aethergraph/services/memory/facade/rag.py +410 -0
- aethergraph/services/memory/facade/results.py +315 -0
- aethergraph/services/memory/facade/retrieval.py +139 -0
- aethergraph/services/memory/facade/types.py +77 -0
- aethergraph/services/memory/facade/utils.py +43 -0
- aethergraph/services/memory/facade_dep.py +1539 -0
- aethergraph/services/memory/factory.py +9 -3
- aethergraph/services/memory/utils.py +10 -0
- aethergraph/services/metering/eventlog_metering.py +470 -0
- aethergraph/services/metering/noop.py +25 -4
- aethergraph/services/rag/__init__.py +0 -0
- aethergraph/services/rag/facade.py +279 -23
- aethergraph/services/rag/index_factory.py +2 -2
- aethergraph/services/rag/node_rag.py +317 -0
- aethergraph/services/rate_limit/inmem_rate_limit.py +24 -0
- aethergraph/services/registry/__init__.py +0 -0
- aethergraph/services/registry/agent_app_meta.py +419 -0
- aethergraph/services/registry/registry_key.py +1 -1
- aethergraph/services/registry/unified_registry.py +74 -6
- aethergraph/services/scope/scope.py +159 -0
- aethergraph/services/scope/scope_factory.py +164 -0
- aethergraph/services/state_stores/serialize.py +5 -0
- aethergraph/services/state_stores/utils.py +2 -1
- aethergraph/services/viz/__init__.py +0 -0
- aethergraph/services/viz/facade.py +413 -0
- aethergraph/services/viz/viz_service.py +69 -0
- aethergraph/storage/artifacts/artifact_index_jsonl.py +180 -0
- aethergraph/storage/artifacts/artifact_index_sqlite.py +426 -0
- aethergraph/storage/artifacts/cas_store.py +422 -0
- aethergraph/storage/artifacts/fs_cas.py +18 -0
- aethergraph/storage/artifacts/s3_cas.py +14 -0
- aethergraph/storage/artifacts/utils.py +124 -0
- aethergraph/storage/blob/fs_blob.py +86 -0
- aethergraph/storage/blob/s3_blob.py +115 -0
- aethergraph/storage/continuation_store/fs_cont.py +283 -0
- aethergraph/storage/continuation_store/inmem_cont.py +146 -0
- aethergraph/storage/continuation_store/kvdoc_cont.py +261 -0
- aethergraph/storage/docstore/fs_doc.py +63 -0
- aethergraph/storage/docstore/sqlite_doc.py +31 -0
- aethergraph/storage/docstore/sqlite_doc_sync.py +90 -0
- aethergraph/storage/eventlog/fs_event.py +136 -0
- aethergraph/storage/eventlog/sqlite_event.py +47 -0
- aethergraph/storage/eventlog/sqlite_event_sync.py +178 -0
- aethergraph/storage/factory.py +432 -0
- aethergraph/storage/fs_utils.py +28 -0
- aethergraph/storage/graph_state_store/state_store.py +64 -0
- aethergraph/storage/kv/inmem_kv.py +103 -0
- aethergraph/storage/kv/layered_kv.py +52 -0
- aethergraph/storage/kv/sqlite_kv.py +39 -0
- aethergraph/storage/kv/sqlite_kv_sync.py +98 -0
- aethergraph/storage/memory/event_persist.py +68 -0
- aethergraph/storage/memory/fs_persist.py +118 -0
- aethergraph/{services/memory/hotlog_kv.py → storage/memory/hotlog.py} +8 -2
- aethergraph/{services → storage}/memory/indices.py +31 -7
- aethergraph/storage/metering/meter_event.py +55 -0
- aethergraph/storage/runs/doc_store.py +280 -0
- aethergraph/storage/runs/inmen_store.py +82 -0
- aethergraph/storage/runs/sqlite_run_store.py +403 -0
- aethergraph/storage/sessions/doc_store.py +183 -0
- aethergraph/storage/sessions/inmem_store.py +110 -0
- aethergraph/storage/sessions/sqlite_session_store.py +399 -0
- aethergraph/storage/vector_index/chroma_index.py +138 -0
- aethergraph/storage/vector_index/faiss_index.py +179 -0
- aethergraph/storage/vector_index/sqlite_index.py +187 -0
- {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/METADATA +138 -31
- aethergraph-0.1.0a3.dist-info/RECORD +356 -0
- aethergraph-0.1.0a3.dist-info/entry_points.txt +3 -0
- aethergraph/services/artifacts/factory.py +0 -35
- aethergraph/services/artifacts/fs_store.py +0 -656
- aethergraph/services/artifacts/jsonl_index.py +0 -123
- aethergraph/services/artifacts/sqlite_index.py +0 -209
- aethergraph/services/memory/distillers/episode.py +0 -116
- aethergraph/services/memory/distillers/rolling.py +0 -74
- aethergraph/services/memory/facade.py +0 -633
- aethergraph/services/memory/persist_fs.py +0 -40
- aethergraph/services/rag/index/base.py +0 -27
- aethergraph/services/rag/index/faiss_index.py +0 -121
- aethergraph/services/rag/index/sqlite_index.py +0 -134
- aethergraph-0.1.0a1.dist-info/RECORD +0 -182
- aethergraph-0.1.0a1.dist-info/entry_points.txt +0 -2
- {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/WHEEL +0 -0
- {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/licenses/LICENSE +0 -0
- {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/licenses/NOTICE +0 -0
- {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field, replace
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class Scope:
|
|
9
|
+
# Tenant / actor
|
|
10
|
+
org_id: str | None = None
|
|
11
|
+
user_id: str | None = None
|
|
12
|
+
client_id: str | None = None
|
|
13
|
+
mode: str | None = None # "cloud", "demo", "local", etc.
|
|
14
|
+
|
|
15
|
+
# App / execution context
|
|
16
|
+
app_id: str | None = None
|
|
17
|
+
session_id: str | None = None
|
|
18
|
+
run_id: str | None = None
|
|
19
|
+
graph_id: str | None = None
|
|
20
|
+
node_id: str | None = None
|
|
21
|
+
flow_id: str | None = None # optional flow ID within a graph -- not implemented yet
|
|
22
|
+
|
|
23
|
+
# Tooling / proveance (optional)
|
|
24
|
+
tool_name: str | None = None
|
|
25
|
+
tool_version: str | None = None
|
|
26
|
+
|
|
27
|
+
# Extra tags
|
|
28
|
+
labels: dict[str, Any] = field(default_factory=dict)
|
|
29
|
+
|
|
30
|
+
# Internal override for memory scope ID
|
|
31
|
+
_memory_scope_id: str | None = None
|
|
32
|
+
|
|
33
|
+
def __item__(self, key: str) -> Any:
|
|
34
|
+
return getattr(self, key)
|
|
35
|
+
|
|
36
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
37
|
+
return getattr(self, key, default)
|
|
38
|
+
|
|
39
|
+
def artifact_scope_labels(self) -> dict[str, str]:
|
|
40
|
+
"""
|
|
41
|
+
Labels to attach to every artifact for this scope.
|
|
42
|
+
These will be mirrored both into Artifact.labels and the index.
|
|
43
|
+
"""
|
|
44
|
+
out: dict[str, str] = {}
|
|
45
|
+
if self.org_id:
|
|
46
|
+
out["org_id"] = self.org_id
|
|
47
|
+
if self.user_id:
|
|
48
|
+
out["user_id"] = self.user_id
|
|
49
|
+
if self.client_id:
|
|
50
|
+
out["client_id"] = self.client_id
|
|
51
|
+
if self.app_id:
|
|
52
|
+
out["app_id"] = self.app_id
|
|
53
|
+
if self.session_id:
|
|
54
|
+
out["session_id"] = self.session_id
|
|
55
|
+
if self.run_id:
|
|
56
|
+
out["run_id"] = self.run_id
|
|
57
|
+
if self.graph_id:
|
|
58
|
+
out["graph_id"] = self.graph_id
|
|
59
|
+
if self.node_id:
|
|
60
|
+
out["node_id"] = self.node_id
|
|
61
|
+
|
|
62
|
+
# canonicial scope ids
|
|
63
|
+
if self.session_id:
|
|
64
|
+
out["scope_id"] = self.session_id # session-centric
|
|
65
|
+
elif self.run_id:
|
|
66
|
+
out["scope_id"] = self.run_id # run-centric for non-session runs
|
|
67
|
+
elif self.graph_id:
|
|
68
|
+
out["scope_id"] = f"graph:{self.graph_id}" # graph-centric for non-run artifacts
|
|
69
|
+
elif self.node_id:
|
|
70
|
+
out["scope_id"] = f"node:{self.node_id}" # node-centric for non-graph artifacts
|
|
71
|
+
return out
|
|
72
|
+
|
|
73
|
+
def metering_dimensions(self) -> dict[str, Any]:
|
|
74
|
+
"""Dimensions for MeteringService: what to attach to events."""
|
|
75
|
+
out: dict[str, Any] = {}
|
|
76
|
+
if self.user_id:
|
|
77
|
+
out["user_id"] = self.user_id
|
|
78
|
+
if self.org_id:
|
|
79
|
+
out["org_id"] = self.org_id
|
|
80
|
+
if self.client_id:
|
|
81
|
+
out["client_id"] = self.client_id
|
|
82
|
+
if self.app_id:
|
|
83
|
+
out["app_id"] = self.app_id
|
|
84
|
+
if self.session_id:
|
|
85
|
+
out["session_id"] = self.session_id
|
|
86
|
+
if self.run_id:
|
|
87
|
+
out["run_id"] = self.run_id
|
|
88
|
+
if self.graph_id:
|
|
89
|
+
out["graph_id"] = self.graph_id
|
|
90
|
+
if self.node_id:
|
|
91
|
+
out["node_id"] = self.node_id
|
|
92
|
+
if self.flow_id:
|
|
93
|
+
out["flow_id"] = self.flow_id
|
|
94
|
+
return out
|
|
95
|
+
|
|
96
|
+
def with_memory_scope(self, mem_scope_id: str) -> Scope:
|
|
97
|
+
"""Return a copy with explicit memory scope override"""
|
|
98
|
+
return replace(self, _memory_scope_id=mem_scope_id)
|
|
99
|
+
|
|
100
|
+
def memory_scope_id(self) -> str:
|
|
101
|
+
"""
|
|
102
|
+
Stable key for “memory bucket”.
|
|
103
|
+
Default precedence: explicit override > session > user > run > org > app.
|
|
104
|
+
"""
|
|
105
|
+
if self._memory_scope_id:
|
|
106
|
+
return self._memory_scope_id
|
|
107
|
+
if self.session_id:
|
|
108
|
+
return f"session:{self.session_id}"
|
|
109
|
+
if self.user_id:
|
|
110
|
+
return f"user:{self.user_id}"
|
|
111
|
+
if self.run_id:
|
|
112
|
+
return f"run:{self.run_id}"
|
|
113
|
+
if self.org_id:
|
|
114
|
+
return f"org:{self.org_id}"
|
|
115
|
+
if self.app_id:
|
|
116
|
+
return f"app:{self.app_id}"
|
|
117
|
+
return "global"
|
|
118
|
+
|
|
119
|
+
def rag_labels(self, *, scope_id: str | None = None) -> dict[str, Any]:
|
|
120
|
+
"""
|
|
121
|
+
Labels that should be stamped on RAG docs/chunks.
|
|
122
|
+
scope_id is usually memory_scope_id (for memory-tied corpora),
|
|
123
|
+
but can be any logical scope key.
|
|
124
|
+
"""
|
|
125
|
+
out: dict[str, Any] = {}
|
|
126
|
+
if self.user_id:
|
|
127
|
+
out["user_id"] = self.user_id
|
|
128
|
+
if self.org_id:
|
|
129
|
+
out["org_id"] = self.org_id
|
|
130
|
+
if self.client_id:
|
|
131
|
+
out["client_id"] = self.client_id
|
|
132
|
+
if self.app_id:
|
|
133
|
+
out["app_id"] = self.app_id
|
|
134
|
+
if self.session_id:
|
|
135
|
+
out["session_id"] = self.session_id
|
|
136
|
+
if self.run_id:
|
|
137
|
+
out["run_id"] = self.run_id
|
|
138
|
+
if self.graph_id:
|
|
139
|
+
out["graph_id"] = self.graph_id
|
|
140
|
+
if self.node_id:
|
|
141
|
+
out["node_id"] = self.node_id
|
|
142
|
+
if scope_id:
|
|
143
|
+
out["scope_id"] = scope_id
|
|
144
|
+
return out
|
|
145
|
+
|
|
146
|
+
def rag_filter(self, *, scope_id: str | None = None) -> dict[str, Any]:
|
|
147
|
+
"""
|
|
148
|
+
Default filter for RAG search based on identity.
|
|
149
|
+
You can adjust strictness (e.g., ignore run_id for per-user corpora).
|
|
150
|
+
"""
|
|
151
|
+
out: dict[str, Any] = {}
|
|
152
|
+
if self.user_id:
|
|
153
|
+
out["user_id"] = self.user_id
|
|
154
|
+
if self.org_id:
|
|
155
|
+
out["org_id"] = self.org_id
|
|
156
|
+
if scope_id:
|
|
157
|
+
out["scope_id"] = scope_id
|
|
158
|
+
# you can choose to include session_id / run_id only for very strict isolation
|
|
159
|
+
return out
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from aethergraph.api.v1.deps import RequestIdentity
|
|
5
|
+
from aethergraph.services.scope.scope import Scope
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class ScopeFactory:
|
|
10
|
+
default_app_id: str | None = None
|
|
11
|
+
|
|
12
|
+
def base_from_identity(self, identity: RequestIdentity | None) -> Scope:
|
|
13
|
+
"""
|
|
14
|
+
Create a base Scope from a RequestIdentity.
|
|
15
|
+
"""
|
|
16
|
+
if identity is None:
|
|
17
|
+
return Scope(mode="local")
|
|
18
|
+
|
|
19
|
+
return Scope(
|
|
20
|
+
org_id=identity.org_id,
|
|
21
|
+
user_id=identity.user_id,
|
|
22
|
+
client_id=identity.client_id,
|
|
23
|
+
mode=identity.mode,
|
|
24
|
+
app_id=self.default_app_id,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def for_node(
|
|
28
|
+
self,
|
|
29
|
+
*,
|
|
30
|
+
identity: RequestIdentity | None = None,
|
|
31
|
+
run_id: str | None = None,
|
|
32
|
+
graph_id: str | None = None,
|
|
33
|
+
node_id: str | None = None,
|
|
34
|
+
session_id: str | None = None,
|
|
35
|
+
app_id: str | None = None,
|
|
36
|
+
tool_name: str | None = None,
|
|
37
|
+
tool_version: str | None = None,
|
|
38
|
+
) -> Scope:
|
|
39
|
+
"""
|
|
40
|
+
Create a Scope for a specific node execution.
|
|
41
|
+
"""
|
|
42
|
+
base = self.base_from_identity(identity)
|
|
43
|
+
return Scope(
|
|
44
|
+
org_id=base.org_id,
|
|
45
|
+
user_id=base.user_id,
|
|
46
|
+
client_id=base.client_id,
|
|
47
|
+
mode=base.mode,
|
|
48
|
+
app_id=app_id or base.app_id,
|
|
49
|
+
session_id=session_id,
|
|
50
|
+
run_id=run_id,
|
|
51
|
+
graph_id=graph_id,
|
|
52
|
+
node_id=node_id,
|
|
53
|
+
tool_name=tool_name,
|
|
54
|
+
tool_version=tool_version,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def for_run(
|
|
58
|
+
self,
|
|
59
|
+
*,
|
|
60
|
+
identity: RequestIdentity | None = None,
|
|
61
|
+
run_id: str,
|
|
62
|
+
graph_id: str | None = None,
|
|
63
|
+
session_id: str | None = None,
|
|
64
|
+
flow_id: str | None = None,
|
|
65
|
+
) -> Scope:
|
|
66
|
+
s = self.base_from_identity(identity)
|
|
67
|
+
s.run_id = run_id
|
|
68
|
+
s.graph_id = graph_id
|
|
69
|
+
s.session_id = session_id
|
|
70
|
+
s.flow_id = flow_id
|
|
71
|
+
return s
|
|
72
|
+
|
|
73
|
+
def for_memory_custom_override(
|
|
74
|
+
self,
|
|
75
|
+
*,
|
|
76
|
+
identity: RequestIdentity | None = None,
|
|
77
|
+
run_id: str,
|
|
78
|
+
graph_id: str | None = None,
|
|
79
|
+
node_id: str | None = None,
|
|
80
|
+
session_id: str | None = None,
|
|
81
|
+
level: Literal["session", "user", "run", "org"] = "session",
|
|
82
|
+
custom_scope_id: str | None = None,
|
|
83
|
+
):
|
|
84
|
+
"""
|
|
85
|
+
Scope for MemoryFacade. level defines how we group memory:
|
|
86
|
+
- "session": per-session (default)
|
|
87
|
+
- "user": across runs/sessions for a given user
|
|
88
|
+
- "run": per-run
|
|
89
|
+
- "org": org-level memory
|
|
90
|
+
"""
|
|
91
|
+
s = self.for_node(
|
|
92
|
+
identity=identity,
|
|
93
|
+
run_id=run_id,
|
|
94
|
+
graph_id=graph_id,
|
|
95
|
+
node_id=node_id,
|
|
96
|
+
session_id=session_id,
|
|
97
|
+
)
|
|
98
|
+
if custom_scope_id is not None:
|
|
99
|
+
mem_id = custom_scope_id
|
|
100
|
+
else:
|
|
101
|
+
if level == "session":
|
|
102
|
+
base = session_id or run_id
|
|
103
|
+
mem_id = f"session:{base}"
|
|
104
|
+
elif level == "user":
|
|
105
|
+
u = s.user_id or s.client_id or "anon"
|
|
106
|
+
mem_id = f"user:{u}"
|
|
107
|
+
elif level == "run":
|
|
108
|
+
mem_id = f"run:{run_id}"
|
|
109
|
+
elif level == "org":
|
|
110
|
+
o = s.org_id or "orgless"
|
|
111
|
+
mem_id = f"org:{o}"
|
|
112
|
+
else: # pragma: no cover
|
|
113
|
+
mem_id = f"run:{run_id}"
|
|
114
|
+
|
|
115
|
+
return s.with_memory_scope(mem_id)
|
|
116
|
+
|
|
117
|
+
def for_memory(
|
|
118
|
+
self,
|
|
119
|
+
*,
|
|
120
|
+
identity: RequestIdentity | None = None,
|
|
121
|
+
run_id: str,
|
|
122
|
+
graph_id: str | None = None,
|
|
123
|
+
node_id: str | None = None,
|
|
124
|
+
session_id: str | None = None,
|
|
125
|
+
level: Literal["session", "user", "run", "org"] = "session",
|
|
126
|
+
custom_scope_id: str | None = None,
|
|
127
|
+
):
|
|
128
|
+
"""
|
|
129
|
+
Rule of thumb for memory scope IDs:
|
|
130
|
+
- session-level: "session:{session_id}" or "session:{run_id}" if no session
|
|
131
|
+
- user-level: "user:{user_id}" or "user:{client_id}"
|
|
132
|
+
- run-level: "run:{run_id}"
|
|
133
|
+
- org-level: "org:{org_id}"
|
|
134
|
+
1) Compute the base ID from the level
|
|
135
|
+
2) If a custom scope is provided, treat it as a suffix under the root
|
|
136
|
+
e.g. "session:{base}:{custom_scope_id}"
|
|
137
|
+
"""
|
|
138
|
+
s = self.for_node(
|
|
139
|
+
identity=identity,
|
|
140
|
+
run_id=run_id,
|
|
141
|
+
graph_id=graph_id,
|
|
142
|
+
node_id=node_id,
|
|
143
|
+
session_id=session_id,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# 1) Compute the base ID from the level
|
|
147
|
+
if level == "session":
|
|
148
|
+
base = session_id or run_id
|
|
149
|
+
root = f"session:{base}"
|
|
150
|
+
elif level == "user":
|
|
151
|
+
u = s.user_id or s.client_id or "anon"
|
|
152
|
+
root = f"user:{u}"
|
|
153
|
+
elif level == "run":
|
|
154
|
+
root = f"run:{run_id}"
|
|
155
|
+
elif level == "org":
|
|
156
|
+
o = s.org_id or "orgless"
|
|
157
|
+
root = f"org:{o}"
|
|
158
|
+
else: # pragma: no cover
|
|
159
|
+
root = f"run:{run_id}"
|
|
160
|
+
|
|
161
|
+
# 2) If a custom scope is provided, treat it as a suffix under the root
|
|
162
|
+
mem_id = f"{root}:{custom_scope_id}" if custom_scope_id else root
|
|
163
|
+
|
|
164
|
+
return s.with_memory_scope(mem_id)
|
|
@@ -207,6 +207,8 @@ async def state_to_json_safe(
|
|
|
207
207
|
for nid, ns in state_obj.nodes.items():
|
|
208
208
|
status = getattr(ns, "status", None)
|
|
209
209
|
status_name = getattr(status, "name", status) # Enum.name or string
|
|
210
|
+
started_at = getattr(ns, "started_at", None)
|
|
211
|
+
finished_at = getattr(ns, "finished_at", None)
|
|
210
212
|
tool_name = getattr(ns, "tool_name", None) or getattr(
|
|
211
213
|
getattr(ns, "spec", None), "tool_name", None
|
|
212
214
|
)
|
|
@@ -232,7 +234,10 @@ async def state_to_json_safe(
|
|
|
232
234
|
"attempts": getattr(ns, "attempts", 0),
|
|
233
235
|
"next_wakeup_at": getattr(ns, "next_wakeup_at", None),
|
|
234
236
|
"wait_token": getattr(ns, "wait_token", None),
|
|
237
|
+
"started_at": started_at,
|
|
238
|
+
"finished_at": finished_at,
|
|
235
239
|
}
|
|
240
|
+
|
|
236
241
|
if include_wait_spec:
|
|
237
242
|
ws = getattr(ns, "wait_spec", None)
|
|
238
243
|
if ws:
|
|
@@ -29,7 +29,7 @@ async def snapshot_from_graph(
|
|
|
29
29
|
allow_externalize=allow_externalize,
|
|
30
30
|
include_wait_spec=include_wait_spec,
|
|
31
31
|
)
|
|
32
|
-
|
|
32
|
+
snap = GraphSnapshot(
|
|
33
33
|
run_id=run_id,
|
|
34
34
|
graph_id=graph_id,
|
|
35
35
|
rev=rev,
|
|
@@ -37,6 +37,7 @@ async def snapshot_from_graph(
|
|
|
37
37
|
spec_hash=spec_hash,
|
|
38
38
|
state=json_state,
|
|
39
39
|
)
|
|
40
|
+
return snap
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
def _status_to_str(s) -> str:
|
|
File without changes
|