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
aethergraph/config/config.py
CHANGED
|
@@ -5,6 +5,26 @@ from pydantic import BaseModel, Field, SecretStr
|
|
|
5
5
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
6
6
|
|
|
7
7
|
from .llm import LLMSettings
|
|
8
|
+
from .storage import StorageSettings
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RateLimitSettings(BaseSettings):
|
|
12
|
+
enabled: bool = True
|
|
13
|
+
|
|
14
|
+
# Concurrency
|
|
15
|
+
max_concurrent_runs: int = 8
|
|
16
|
+
|
|
17
|
+
# Per-identity, per-window run limits (using metering)
|
|
18
|
+
runs_window: str = "1h"
|
|
19
|
+
max_runs_per_window: int = 100
|
|
20
|
+
|
|
21
|
+
# Short-burst, in-memory limiter for POST /runs
|
|
22
|
+
burst_max_runs: int = 10
|
|
23
|
+
burst_window_seconds: int = 10
|
|
24
|
+
|
|
25
|
+
# Optional LLM caps *per run*
|
|
26
|
+
max_llm_calls_per_run: int = 200
|
|
27
|
+
max_llm_tokens_per_run: int = 200_000
|
|
8
28
|
|
|
9
29
|
|
|
10
30
|
class LoggingSettings(BaseModel):
|
|
@@ -106,6 +126,7 @@ class AppSettings(BaseSettings):
|
|
|
106
126
|
# top-level for workspace root
|
|
107
127
|
root: str = "./aethergraph_data"
|
|
108
128
|
|
|
129
|
+
rate_limit: RateLimitSettings = RateLimitSettings()
|
|
109
130
|
logging: LoggingSettings = LoggingSettings()
|
|
110
131
|
slack: SlackSettings = SlackSettings()
|
|
111
132
|
telegram: TelegramSettings = TelegramSettings()
|
|
@@ -114,6 +135,7 @@ class AppSettings(BaseSettings):
|
|
|
114
135
|
memory: MemorySettings = MemorySettings()
|
|
115
136
|
channels: ChannelSettings = ChannelSettings()
|
|
116
137
|
rag: RAGSettings = RAGSettings()
|
|
138
|
+
storage: StorageSettings = StorageSettings()
|
|
117
139
|
|
|
118
140
|
# Future fields:
|
|
119
141
|
# authn: ...
|
aethergraph/config/loader.py
CHANGED
|
@@ -37,7 +37,7 @@ def load_settings() -> AppSettings:
|
|
|
37
37
|
repo_env = (
|
|
38
38
|
(repo_root / ".env").resolve() if (repo_root and (repo_root / ".env").exists()) else None
|
|
39
39
|
)
|
|
40
|
-
|
|
40
|
+
print("Repo root for .env fallback:", repo_env)
|
|
41
41
|
candidates = _existing(
|
|
42
42
|
[
|
|
43
43
|
explicit_path or Path(), # explicit if set
|
|
@@ -45,9 +45,10 @@ def load_settings() -> AppSettings:
|
|
|
45
45
|
cwd / ".env.local",
|
|
46
46
|
workspace / ".env",
|
|
47
47
|
user_cfg_env,
|
|
48
|
-
repo_env if repo_env else Path(), # dev fallback only if exists
|
|
48
|
+
# repo_env if repo_env else Path(), # dev fallback only if exists
|
|
49
49
|
]
|
|
50
50
|
)
|
|
51
|
+
print("Loading .env files from:", candidates)
|
|
51
52
|
|
|
52
53
|
if explicit and not explicit_path.exists():
|
|
53
54
|
raise FileNotFoundError(f"AETHERGRAPH_ENV_FILE not found: {explicit_path}")
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
# --- Per-backend settings ---
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DocStoreSettings(BaseModel):
|
|
9
|
+
backend: Literal["sqlite", "fs"] = "sqlite"
|
|
10
|
+
# All paths are *relative* to AppSettings.root
|
|
11
|
+
sqlite_path: str = "docs/doc_store.db"
|
|
12
|
+
fs_dir: str = "docs/doc_store"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EventLogSettings(BaseModel):
|
|
16
|
+
backend: Literal["sqlite", "fs", "none"] = "sqlite"
|
|
17
|
+
sqlite_path: str = "events/events.db"
|
|
18
|
+
fs_dir: str = "events"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class KVStoreSettings(BaseModel):
|
|
22
|
+
backend: Literal["sqlite", "inmem"] = "sqlite"
|
|
23
|
+
sqlite_path: str = "kv/kv_store.db"
|
|
24
|
+
# Optional global prefix, you can still add extra per-subsystem prefixes
|
|
25
|
+
prefix: str = ""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# --- Artifact storage backends ---
|
|
29
|
+
class FSArtifactStoreSettings(BaseModel):
|
|
30
|
+
# Interpreted relative to AppSettings.root in the factory
|
|
31
|
+
base_dir: str = "artifacts" # => <root>/artifacts by default
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class S3ArtifactStoreSettings(BaseModel):
|
|
35
|
+
bucket: str = "" # must be set via env when backend="s3"
|
|
36
|
+
prefix: str = "artifacts" # e.g. "aethergraph/artifacts"
|
|
37
|
+
# local temp dir; if empty, factory can default to something under root
|
|
38
|
+
staging_dir: str = "./.aethergraph_tmp/artifacts"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ArtifactStorageSettings(BaseModel):
|
|
42
|
+
# which backend to use for artifacts
|
|
43
|
+
backend: Literal["fs", "s3"] = "fs"
|
|
44
|
+
|
|
45
|
+
fs: FSArtifactStoreSettings = FSArtifactStoreSettings()
|
|
46
|
+
s3: S3ArtifactStoreSettings = S3ArtifactStoreSettings()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class JsonlArtifactIndexSettings(BaseModel):
|
|
50
|
+
# Relative to AppSettings.root; we’ll join in the factory
|
|
51
|
+
path: str = "artifacts/index.jsonl"
|
|
52
|
+
occurrences_path: str | None = None # default: <stem>_occurrences.jsonl
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class SqliteArtifactIndexSettings(BaseModel):
|
|
56
|
+
path: str = "artifacts/index.sqlite"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ArtifactIndexSettings(BaseModel):
|
|
60
|
+
backend: Literal["jsonl", "sqlite"] = "sqlite"
|
|
61
|
+
jsonl: JsonlArtifactIndexSettings = JsonlArtifactIndexSettings()
|
|
62
|
+
sqlite: SqliteArtifactIndexSettings = SqliteArtifactIndexSettings()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# --- Graph State Storage ---
|
|
66
|
+
class GraphStateStorageSettings(BaseModel):
|
|
67
|
+
backend: Literal["fs", "sqlite"] = "sqlite"
|
|
68
|
+
|
|
69
|
+
# FS backend
|
|
70
|
+
fs_root: str = "graph_state" # under AppSettings.root
|
|
71
|
+
# SQLite backend
|
|
72
|
+
sqlite_path: str = "graph_state/graph_state.db" # relative to AppSettings.root
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# --- Continuation Store ---
|
|
76
|
+
class KVDocContinuationStoreSettings(BaseModel):
|
|
77
|
+
# DocStore backend type for continuations
|
|
78
|
+
doc_store_backend: Literal["sqlite", "fs"] = "sqlite"
|
|
79
|
+
sqlite_doc_store_path: str = "continuations/cont_doc_store.db" # relative to AppSettings.root
|
|
80
|
+
fs_doc_store_dir: str = "continuations/cont_doc_store" # relative to AppSettings.root
|
|
81
|
+
|
|
82
|
+
# AsyncKV backend type for token + correlator indexes
|
|
83
|
+
kv_backend: Literal["sqlite", "inmem"] = "sqlite"
|
|
84
|
+
sqlite_kv_path: str = "continuations/cont_kv_store.db" # relative to AppSettings.root
|
|
85
|
+
|
|
86
|
+
# EventLog backend for continuation audit (optional)
|
|
87
|
+
eventlog_backend: Literal["none", "sqlite", "fs"] = "fs"
|
|
88
|
+
sqlite_eventlog_path: str = "continuations/cont_events.db" # relative to AppSettings.root
|
|
89
|
+
fs_eventlog_dir: str = "continuations/cont_events" # relative to AppSettings.root
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class FSContinuationStoreSettings(BaseModel):
|
|
93
|
+
# Where to store the old filesystem layout (runs/index/...).
|
|
94
|
+
# Interpreted relative to AppSettings.root.
|
|
95
|
+
root: str = "continuations/cont_fs_store"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class MemoryContinuationStoreSettings(BaseModel):
|
|
99
|
+
# Placeholder for future options, e.g. max entries, debug flags, etc.
|
|
100
|
+
enabled: bool = True
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ContinuationStoreSettings(BaseModel):
|
|
104
|
+
# Which backend to use:
|
|
105
|
+
# - "fs": keep existing FSContinuationStore
|
|
106
|
+
# - "kvdoc": KVDocContinuationStore (DocStore + AsyncKV + EventLog)
|
|
107
|
+
# - "memory": in-memory (for tests/dev)
|
|
108
|
+
backend: Literal["fs", "kvdoc", "memory"] = "kvdoc"
|
|
109
|
+
|
|
110
|
+
# Namespacing for DocStore ids / KV keys
|
|
111
|
+
namespace: str = "cont"
|
|
112
|
+
|
|
113
|
+
# Secret for HMAC token generation; override via env.
|
|
114
|
+
secret_key: str = Field(
|
|
115
|
+
default="change-me",
|
|
116
|
+
description="Secret key for continuation HMAC tokens; set via AETHERGRAPH_CONT__SECRET_KEY.",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
fs: FSContinuationStoreSettings = FSContinuationStoreSettings()
|
|
120
|
+
kvdoc: KVDocContinuationStoreSettings = KVDocContinuationStoreSettings()
|
|
121
|
+
memory: MemoryContinuationStoreSettings = MemoryContinuationStoreSettings()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# --- Vector Index Storage ---
|
|
125
|
+
class SQLiteVectorIndexSettings(BaseModel):
|
|
126
|
+
# Relative to AppSettings.root
|
|
127
|
+
dir: str = "vector_index/sqlite"
|
|
128
|
+
filename: str = "index.sqlite" # currently not used directly, but kept for flexibility
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class FAISSVectorIndexSettings(BaseModel):
|
|
132
|
+
# Relative to AppSettings.root
|
|
133
|
+
dir: str = "vector_index/faiss"
|
|
134
|
+
dim: int | None = None # optional default; can be inferred
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class ChromaVectorIndexSettings(BaseModel):
|
|
138
|
+
# Relative to AppSettings.root
|
|
139
|
+
persist_dir: str = "vector_index/chroma"
|
|
140
|
+
collection_prefix: str = "vec_"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class VectorIndexStorageSettings(BaseModel):
|
|
144
|
+
backend: Literal["sqlite", "faiss", "chroma"] = "sqlite"
|
|
145
|
+
|
|
146
|
+
sqlite: SQLiteVectorIndexSettings = SQLiteVectorIndexSettings()
|
|
147
|
+
faiss: FAISSVectorIndexSettings = FAISSVectorIndexSettings()
|
|
148
|
+
chroma: ChromaVectorIndexSettings = ChromaVectorIndexSettings()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# --- Memory Storage Settings (overall) ---
|
|
152
|
+
class MemoryPersistenceSettings(BaseModel):
|
|
153
|
+
# "fs" uses FSPersistence, "eventlog" uses EventLogPersistence
|
|
154
|
+
backend: Literal["fs", "eventlog"] = "eventlog"
|
|
155
|
+
# FS backend
|
|
156
|
+
fs_base_dir: str = "mem"
|
|
157
|
+
# EventLog backend
|
|
158
|
+
uri_prefix: str = "memdoc://"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class MemoryHotLogSettings(BaseModel):
|
|
162
|
+
# TTL + buffer size for KVHotLog
|
|
163
|
+
ttl_s: int = 24 * 3600
|
|
164
|
+
limit: int = 400
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class MemoryIndicesSettings(BaseModel):
|
|
168
|
+
ttl_s: int = 24 * 3600
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class MemorySettings(BaseModel):
|
|
172
|
+
persistence: MemoryPersistenceSettings = MemoryPersistenceSettings()
|
|
173
|
+
hotlog: MemoryHotLogSettings = MemoryHotLogSettings()
|
|
174
|
+
indices: MemoryIndicesSettings = MemoryIndicesSettings()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class RunStorageSettings(BaseModel):
|
|
178
|
+
backend: Literal["memory", "fs", "sqlite"] = "sqlite"
|
|
179
|
+
|
|
180
|
+
# FS backend: relative to AppSettings.root
|
|
181
|
+
fs_root: str = "runs" # will become <root>/runs
|
|
182
|
+
|
|
183
|
+
# SQLite backend: relative to AppSettings.root
|
|
184
|
+
sqlite_path: str = "runs/runs.db"
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class SessionStorageSettings(BaseModel):
|
|
188
|
+
backend: Literal["memory", "fs", "sqlite"] = "sqlite"
|
|
189
|
+
|
|
190
|
+
# FS backend: relative to AppSettings.root
|
|
191
|
+
fs_root: str = "sessions" # will become <root>/sessions
|
|
192
|
+
|
|
193
|
+
# SQLite backend: relative to AppSettings.root
|
|
194
|
+
sqlite_path: str = "sessions/sessions.db"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class StorageSettings(BaseModel):
|
|
198
|
+
docs: DocStoreSettings = DocStoreSettings()
|
|
199
|
+
eventlog: EventLogSettings = EventLogSettings()
|
|
200
|
+
kv: KVStoreSettings = KVStoreSettings()
|
|
201
|
+
|
|
202
|
+
artifacts: ArtifactStorageSettings = ArtifactStorageSettings()
|
|
203
|
+
artifact_index: ArtifactIndexSettings = ArtifactIndexSettings()
|
|
204
|
+
graph_state: GraphStateStorageSettings = GraphStateStorageSettings()
|
|
205
|
+
continuation: ContinuationStoreSettings = ContinuationStoreSettings()
|
|
206
|
+
vector_index: VectorIndexStorageSettings = VectorIndexStorageSettings()
|
|
207
|
+
memory: MemorySettings = MemorySettings()
|
|
208
|
+
runs: RunStorageSettings = RunStorageSettings()
|
|
209
|
+
sessions: SessionStorageSettings = SessionStorageSettings()
|
|
File without changes
|
|
File without changes
|
|
@@ -8,21 +8,27 @@ from typing import Any, Protocol
|
|
|
8
8
|
@dataclass
|
|
9
9
|
class Artifact:
|
|
10
10
|
artifact_id: str
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
metrics: dict[str, Any]
|
|
24
|
-
preview_uri: str | None = None # for rendering previews in UI, not tied to storage
|
|
11
|
+
run_id: str | None = None
|
|
12
|
+
graph_id: str | None = None
|
|
13
|
+
node_id: str | None = None
|
|
14
|
+
tool_name: str | None = None
|
|
15
|
+
tool_version: str | None = None
|
|
16
|
+
kind: str | None = None
|
|
17
|
+
sha256: str | None = None
|
|
18
|
+
bytes: int | None = None
|
|
19
|
+
mime: str | None = None
|
|
20
|
+
created_at: str | None = None
|
|
21
|
+
labels: dict[str, Any] | None = None
|
|
22
|
+
metrics: dict[str, Any] | None = None
|
|
25
23
|
pinned: bool = False
|
|
24
|
+
uri: str | None = None
|
|
25
|
+
preview_uri: str | None = None
|
|
26
|
+
# tenant fields
|
|
27
|
+
org_id: str | None = None
|
|
28
|
+
user_id: str | None = None
|
|
29
|
+
client_id: str | None = None
|
|
30
|
+
app_id: str | None = None
|
|
31
|
+
session_id: str | None = None
|
|
26
32
|
|
|
27
33
|
def to_dict(self) -> dict[str, Any]:
|
|
28
34
|
return {
|
|
@@ -42,6 +48,11 @@ class Artifact:
|
|
|
42
48
|
"metrics": self.metrics,
|
|
43
49
|
"preview_uri": self.preview_uri,
|
|
44
50
|
"pinned": self.pinned,
|
|
51
|
+
"org_id": self.org_id,
|
|
52
|
+
"user_id": self.user_id,
|
|
53
|
+
"client_id": self.client_id,
|
|
54
|
+
"app_id": self.app_id,
|
|
55
|
+
"session_id": self.session_id,
|
|
45
56
|
}
|
|
46
57
|
|
|
47
58
|
|
|
@@ -61,6 +72,7 @@ class AsyncArtifactStore(Protocol):
|
|
|
61
72
|
labels: dict | None = None,
|
|
62
73
|
metrics: dict | None = None,
|
|
63
74
|
preview_uri: str | None = None,
|
|
75
|
+
cleanup: bool = True,
|
|
64
76
|
) -> Artifact: ...
|
|
65
77
|
async def open_writer(
|
|
66
78
|
self,
|
|
@@ -134,6 +146,7 @@ class AsyncArtifactIndex(Protocol):
|
|
|
134
146
|
labels: dict | None = None,
|
|
135
147
|
metric: str | None = None,
|
|
136
148
|
mode: str | None = None,
|
|
149
|
+
limit: int | None = None,
|
|
137
150
|
) -> list[Artifact]: ...
|
|
138
151
|
async def best(
|
|
139
152
|
self, *, kind: str, metric: str, mode: str, filters: dict | None = None
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from typing import Any, Literal, Protocol, TypedDict
|
|
5
5
|
|
|
6
|
+
from aethergraph.contracts.storage.doc_store import DocStore
|
|
7
|
+
|
|
6
8
|
EventKind = Literal[
|
|
7
9
|
"user_msg",
|
|
8
10
|
"assistant_msg",
|
|
@@ -17,29 +19,47 @@ EventKind = Literal[
|
|
|
17
19
|
|
|
18
20
|
@dataclass
|
|
19
21
|
class Event:
|
|
22
|
+
"""A structured event log entry in memory."""
|
|
23
|
+
|
|
24
|
+
# --------- Core fields ---------
|
|
20
25
|
event_id: str
|
|
21
26
|
ts: str
|
|
27
|
+
|
|
28
|
+
# --------- Execution / Tenant Identity ---------
|
|
22
29
|
run_id: str
|
|
30
|
+
scope_id: str
|
|
31
|
+
user_id: str | None = None
|
|
32
|
+
org_id: str | None = None
|
|
33
|
+
client_id: str | None = None
|
|
34
|
+
app_id: str | None = None
|
|
35
|
+
session_id: str | None = None
|
|
36
|
+
|
|
37
|
+
# --------- Core semantics ---------
|
|
38
|
+
kind: EventKind = None # logical type: "chat_user", "tool_start", etc.
|
|
39
|
+
stage: str | None = None # optional phase (user/assistant/system/tool, etc.)
|
|
40
|
+
text: str | None = None # primary human-readable content (short, truncated)
|
|
41
|
+
tags: list[str] | None = None # low-cardinality labels for filtering/searching
|
|
42
|
+
data: dict[str, Any] | None = None # arbitrary JSON payload for event-specific data
|
|
43
|
+
metrics: dict[str, float] | None = None # numeric metrics associated with event
|
|
44
|
+
|
|
45
|
+
# --------- Node context ---------
|
|
23
46
|
graph_id: str | None = None
|
|
24
47
|
node_id: str | None = None
|
|
25
|
-
|
|
48
|
+
|
|
49
|
+
# --------- Optional fields ---------
|
|
26
50
|
tool: str | None = None # now used for tool topic: TODO: rename to topic in future
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
51
|
+
topic: str | None = None
|
|
52
|
+
severity: int = 2 # 1=low, 2=medium, 3=high
|
|
53
|
+
signal: float = 0.0 # signal strength of the event (estimated importance or relevance)
|
|
54
|
+
inputs: list[Value] | None = None # optional I/O values of the event
|
|
55
|
+
outputs: list[Value] | None = None # optional I/O values of the event
|
|
56
|
+
|
|
57
|
+
# --------- Advanced fields ---------
|
|
58
|
+
embedding: list[float] | None = None # reserved for vector embeddings
|
|
40
59
|
pii_flags: dict[str, bool] | None = None
|
|
41
|
-
|
|
42
|
-
|
|
60
|
+
|
|
61
|
+
# --------- Schema versioning ---------
|
|
62
|
+
version: int = 2 # for schema evolution
|
|
43
63
|
|
|
44
64
|
|
|
45
65
|
class HotLog(Protocol):
|
|
@@ -52,6 +72,7 @@ class HotLog(Protocol):
|
|
|
52
72
|
class Persistence(Protocol):
|
|
53
73
|
async def append_event(self, run_id: str, evt: Event) -> None: ...
|
|
54
74
|
async def save_json(self, uri: str, obj: dict[str, Any]) -> None: ...
|
|
75
|
+
async def load_json(self, uri: str) -> dict[str, Any]: ...
|
|
55
76
|
|
|
56
77
|
|
|
57
78
|
class Indices(Protocol):
|
|
@@ -65,7 +86,14 @@ class Indices(Protocol):
|
|
|
65
86
|
|
|
66
87
|
class Distiller(Protocol):
|
|
67
88
|
async def distill(
|
|
68
|
-
self,
|
|
89
|
+
self,
|
|
90
|
+
run_id: str,
|
|
91
|
+
*,
|
|
92
|
+
hotlog: HotLog,
|
|
93
|
+
persistence: Persistence,
|
|
94
|
+
indices: Indices,
|
|
95
|
+
docs: DocStore,
|
|
96
|
+
**kw,
|
|
69
97
|
) -> dict[str, Any]: ...
|
|
70
98
|
|
|
71
99
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Protocol
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MeteringService(Protocol):
|
|
6
|
+
async def record_llm(
|
|
7
|
+
self,
|
|
8
|
+
*,
|
|
9
|
+
user_id: str | None = None,
|
|
10
|
+
org_id: str | None = None,
|
|
11
|
+
run_id: str | None = None,
|
|
12
|
+
model: str,
|
|
13
|
+
provider: str,
|
|
14
|
+
prompt_tokens: int,
|
|
15
|
+
completion_tokens: int,
|
|
16
|
+
latency_ms: int | None = None,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Record an LLM usage event."""
|
|
19
|
+
...
|
|
20
|
+
|
|
21
|
+
async def record_run(
|
|
22
|
+
self,
|
|
23
|
+
*,
|
|
24
|
+
user_id: str | None = None,
|
|
25
|
+
org_id: str | None = None,
|
|
26
|
+
run_id: str | None = None,
|
|
27
|
+
graph_id: str | None = None,
|
|
28
|
+
status: str | None = None,
|
|
29
|
+
duration_s: float | None = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Record a run usage event."""
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
async def record_artifact(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
user_id: str | None = None,
|
|
38
|
+
org_id: str | None = None,
|
|
39
|
+
run_id: str | None = None,
|
|
40
|
+
graph_id: str | None = None,
|
|
41
|
+
kind: str,
|
|
42
|
+
bytes: int,
|
|
43
|
+
pinned: bool = False,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Record an artifact usage event."""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
async def record_event(
|
|
49
|
+
self,
|
|
50
|
+
*,
|
|
51
|
+
user_id: str | None = None,
|
|
52
|
+
org_id: str | None = None,
|
|
53
|
+
run_id: str | None = None,
|
|
54
|
+
scope_id: str | None = None,
|
|
55
|
+
kind: str,
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Record an event usage event."""
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
# ----- Read methods ----- #
|
|
61
|
+
async def get_overview(
|
|
62
|
+
self,
|
|
63
|
+
*,
|
|
64
|
+
user_id: str | None = None,
|
|
65
|
+
org_id: str | None = None,
|
|
66
|
+
window: str = "24h", # e.g., "24h", "7d", "30d"
|
|
67
|
+
run_ids: list[str] | None = None,
|
|
68
|
+
) -> dict[str, int]:
|
|
69
|
+
"""Get an overview of usage metrics."""
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
async def get_llm_stats(
|
|
73
|
+
self,
|
|
74
|
+
*,
|
|
75
|
+
user_id: str | None = None,
|
|
76
|
+
org_id: str | None = None,
|
|
77
|
+
window: str = "24h",
|
|
78
|
+
run_ids: list[str] | None = None,
|
|
79
|
+
) -> dict[str, dict[str, int]]:
|
|
80
|
+
"""Get LLM usage statistics."""
|
|
81
|
+
...
|
|
82
|
+
|
|
83
|
+
async def get_graph_stats(
|
|
84
|
+
self,
|
|
85
|
+
*,
|
|
86
|
+
user_id: str | None = None,
|
|
87
|
+
org_id: str | None = None,
|
|
88
|
+
window: str = "24h",
|
|
89
|
+
run_ids: list[str] | None = None,
|
|
90
|
+
) -> dict[str, dict[str, int]]:
|
|
91
|
+
"""Get graph usage statistics."""
|
|
92
|
+
...
|
|
93
|
+
|
|
94
|
+
async def get_artifact_stats(
|
|
95
|
+
self,
|
|
96
|
+
*,
|
|
97
|
+
user_id: str | None = None,
|
|
98
|
+
org_id: str | None = None,
|
|
99
|
+
window: str = "24h",
|
|
100
|
+
run_ids: list[str] | None = None,
|
|
101
|
+
) -> dict[str, dict[str, int]]:
|
|
102
|
+
"""Get artifact usage statistics."""
|
|
103
|
+
...
|
|
104
|
+
|
|
105
|
+
async def get_memory_stats(
|
|
106
|
+
self,
|
|
107
|
+
*,
|
|
108
|
+
scope_id: str | None = None,
|
|
109
|
+
user_id: str | None = None,
|
|
110
|
+
org_id: str | None = None,
|
|
111
|
+
window: str = "24h",
|
|
112
|
+
run_ids: list[str] | None = None,
|
|
113
|
+
) -> dict[str, dict[str, int]]:
|
|
114
|
+
"""Get memory usage statistics."""
|
|
115
|
+
...
|
|
116
|
+
|
|
117
|
+
# Other possible methods -- channel events, embeddings, and tool calls
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class MeteringStore(Protocol):
|
|
121
|
+
async def append(self, event: dict[str, Any]) -> None: ...
|
|
122
|
+
async def query(
|
|
123
|
+
self,
|
|
124
|
+
*,
|
|
125
|
+
since: datetime | None = None,
|
|
126
|
+
until: datetime | None = None,
|
|
127
|
+
kinds: list[str] | None = None,
|
|
128
|
+
limit: int | None = None,
|
|
129
|
+
) -> list[dict[str, Any]]: ...
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
from aethergraph.core.runtime.run_types import RunRecord, RunStatus
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RunStore(Protocol):
|
|
10
|
+
"""
|
|
11
|
+
Abstract interface for storing run metadata.
|
|
12
|
+
|
|
13
|
+
Implementations can be in-memory, file-based, or backed by a DB.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
async def create(self, record: RunRecord) -> None: ...
|
|
17
|
+
async def update_status(
|
|
18
|
+
self,
|
|
19
|
+
run_id: str,
|
|
20
|
+
status: RunStatus,
|
|
21
|
+
*,
|
|
22
|
+
finished_at: datetime | None = None,
|
|
23
|
+
error: str | None = None,
|
|
24
|
+
) -> None: ...
|
|
25
|
+
async def get(self, run_id: str) -> RunRecord | None: ...
|
|
26
|
+
async def list(
|
|
27
|
+
self,
|
|
28
|
+
*,
|
|
29
|
+
graph_id: str | None = None,
|
|
30
|
+
status: RunStatus | None = None,
|
|
31
|
+
limit: int = 100,
|
|
32
|
+
offset: int = 0,
|
|
33
|
+
) -> list[RunRecord]: ...
|
|
34
|
+
|
|
35
|
+
async def record_artifact(
|
|
36
|
+
self,
|
|
37
|
+
run_id: str,
|
|
38
|
+
*,
|
|
39
|
+
artifact_id: str,
|
|
40
|
+
created_at: datetime | None = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Update artifact-related metadata for a run:
|
|
44
|
+
|
|
45
|
+
- increment artifact_count
|
|
46
|
+
- update first_artifact_at / last_artifact_at
|
|
47
|
+
- optionally maintain recent_artifact_ids (bounded list)
|
|
48
|
+
|
|
49
|
+
No-op if run_id does not exist.
|
|
50
|
+
"""
|