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.
Files changed (267) hide show
  1. aethergraph/__init__.py +4 -10
  2. aethergraph/__main__.py +296 -0
  3. aethergraph/api/v1/__init__.py +0 -0
  4. aethergraph/api/v1/agents.py +46 -0
  5. aethergraph/api/v1/apps.py +70 -0
  6. aethergraph/api/v1/artifacts.py +415 -0
  7. aethergraph/api/v1/channels.py +89 -0
  8. aethergraph/api/v1/deps.py +168 -0
  9. aethergraph/api/v1/graphs.py +259 -0
  10. aethergraph/api/v1/identity.py +25 -0
  11. aethergraph/api/v1/memory.py +353 -0
  12. aethergraph/api/v1/misc.py +47 -0
  13. aethergraph/api/v1/pagination.py +29 -0
  14. aethergraph/api/v1/runs.py +568 -0
  15. aethergraph/api/v1/schemas.py +535 -0
  16. aethergraph/api/v1/session.py +323 -0
  17. aethergraph/api/v1/stats.py +201 -0
  18. aethergraph/api/v1/viz.py +152 -0
  19. aethergraph/config/config.py +22 -0
  20. aethergraph/config/loader.py +3 -2
  21. aethergraph/config/storage.py +209 -0
  22. aethergraph/contracts/__init__.py +0 -0
  23. aethergraph/contracts/services/__init__.py +0 -0
  24. aethergraph/contracts/services/artifacts.py +27 -14
  25. aethergraph/contracts/services/memory.py +45 -17
  26. aethergraph/contracts/services/metering.py +129 -0
  27. aethergraph/contracts/services/runs.py +50 -0
  28. aethergraph/contracts/services/sessions.py +87 -0
  29. aethergraph/contracts/services/state_stores.py +3 -0
  30. aethergraph/contracts/services/viz.py +44 -0
  31. aethergraph/contracts/storage/artifact_index.py +88 -0
  32. aethergraph/contracts/storage/artifact_store.py +99 -0
  33. aethergraph/contracts/storage/async_kv.py +34 -0
  34. aethergraph/contracts/storage/blob_store.py +50 -0
  35. aethergraph/contracts/storage/doc_store.py +35 -0
  36. aethergraph/contracts/storage/event_log.py +31 -0
  37. aethergraph/contracts/storage/vector_index.py +48 -0
  38. aethergraph/core/__init__.py +0 -0
  39. aethergraph/core/execution/forward_scheduler.py +13 -2
  40. aethergraph/core/execution/global_scheduler.py +21 -15
  41. aethergraph/core/execution/step_forward.py +10 -1
  42. aethergraph/core/graph/__init__.py +0 -0
  43. aethergraph/core/graph/graph_builder.py +8 -4
  44. aethergraph/core/graph/graph_fn.py +156 -15
  45. aethergraph/core/graph/graph_spec.py +8 -0
  46. aethergraph/core/graph/graphify.py +146 -27
  47. aethergraph/core/graph/node_spec.py +0 -2
  48. aethergraph/core/graph/node_state.py +3 -0
  49. aethergraph/core/graph/task_graph.py +39 -1
  50. aethergraph/core/runtime/__init__.py +0 -0
  51. aethergraph/core/runtime/ad_hoc_context.py +64 -4
  52. aethergraph/core/runtime/base_service.py +28 -4
  53. aethergraph/core/runtime/execution_context.py +13 -15
  54. aethergraph/core/runtime/graph_runner.py +222 -37
  55. aethergraph/core/runtime/node_context.py +510 -6
  56. aethergraph/core/runtime/node_services.py +12 -5
  57. aethergraph/core/runtime/recovery.py +15 -1
  58. aethergraph/core/runtime/run_manager.py +783 -0
  59. aethergraph/core/runtime/run_manager_local.py +204 -0
  60. aethergraph/core/runtime/run_registration.py +2 -2
  61. aethergraph/core/runtime/run_types.py +89 -0
  62. aethergraph/core/runtime/runtime_env.py +136 -7
  63. aethergraph/core/runtime/runtime_metering.py +71 -0
  64. aethergraph/core/runtime/runtime_registry.py +36 -13
  65. aethergraph/core/runtime/runtime_services.py +194 -6
  66. aethergraph/core/tools/builtins/toolset.py +1 -1
  67. aethergraph/core/tools/toolkit.py +5 -0
  68. aethergraph/plugins/agents/default_chat_agent copy.py +90 -0
  69. aethergraph/plugins/agents/default_chat_agent.py +171 -0
  70. aethergraph/plugins/agents/shared.py +81 -0
  71. aethergraph/plugins/channel/adapters/webui.py +112 -112
  72. aethergraph/plugins/channel/routes/webui_routes.py +367 -102
  73. aethergraph/plugins/channel/utils/slack_utils.py +115 -59
  74. aethergraph/plugins/channel/utils/telegram_utils.py +88 -47
  75. aethergraph/plugins/channel/websockets/weibui_ws.py +172 -0
  76. aethergraph/runtime/__init__.py +15 -0
  77. aethergraph/server/app_factory.py +196 -34
  78. aethergraph/server/clients/channel_client.py +202 -0
  79. aethergraph/server/http/channel_http_routes.py +116 -0
  80. aethergraph/server/http/channel_ws_routers.py +45 -0
  81. aethergraph/server/loading.py +117 -0
  82. aethergraph/server/server.py +131 -0
  83. aethergraph/server/server_state.py +240 -0
  84. aethergraph/server/start.py +227 -66
  85. aethergraph/server/ui_static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  86. aethergraph/server/ui_static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  87. aethergraph/server/ui_static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  88. aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  89. aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  90. aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  91. aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  92. aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  93. aethergraph/server/ui_static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  94. aethergraph/server/ui_static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  95. aethergraph/server/ui_static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  96. aethergraph/server/ui_static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  97. aethergraph/server/ui_static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  98. aethergraph/server/ui_static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  99. aethergraph/server/ui_static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  100. aethergraph/server/ui_static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  101. aethergraph/server/ui_static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  102. aethergraph/server/ui_static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  103. aethergraph/server/ui_static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  104. aethergraph/server/ui_static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  105. aethergraph/server/ui_static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  106. aethergraph/server/ui_static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  107. aethergraph/server/ui_static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  108. aethergraph/server/ui_static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  109. aethergraph/server/ui_static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  110. aethergraph/server/ui_static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  111. aethergraph/server/ui_static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  112. aethergraph/server/ui_static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  113. aethergraph/server/ui_static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  114. aethergraph/server/ui_static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  115. aethergraph/server/ui_static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  116. aethergraph/server/ui_static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  117. aethergraph/server/ui_static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  118. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  119. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  120. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  121. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  122. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  123. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  124. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  125. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  126. aethergraph/server/ui_static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  127. aethergraph/server/ui_static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  128. aethergraph/server/ui_static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  129. aethergraph/server/ui_static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  130. aethergraph/server/ui_static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  131. aethergraph/server/ui_static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  132. aethergraph/server/ui_static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  133. aethergraph/server/ui_static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  134. aethergraph/server/ui_static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  135. aethergraph/server/ui_static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  136. aethergraph/server/ui_static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  137. aethergraph/server/ui_static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  138. aethergraph/server/ui_static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  139. aethergraph/server/ui_static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  140. aethergraph/server/ui_static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  141. aethergraph/server/ui_static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  142. aethergraph/server/ui_static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  143. aethergraph/server/ui_static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  144. aethergraph/server/ui_static/assets/index-BR5GtXcZ.css +1 -0
  145. aethergraph/server/ui_static/assets/index-CQ0HZZ83.js +400 -0
  146. aethergraph/server/ui_static/index.html +15 -0
  147. aethergraph/server/ui_static/logo.png +0 -0
  148. aethergraph/services/artifacts/__init__.py +0 -0
  149. aethergraph/services/artifacts/facade.py +1239 -132
  150. aethergraph/services/auth/{dev.py → authn.py} +0 -8
  151. aethergraph/services/auth/authz.py +100 -0
  152. aethergraph/services/channel/__init__.py +0 -0
  153. aethergraph/services/channel/channel_bus.py +19 -1
  154. aethergraph/services/channel/factory.py +13 -1
  155. aethergraph/services/channel/ingress.py +311 -0
  156. aethergraph/services/channel/queue_adapter.py +75 -0
  157. aethergraph/services/channel/session.py +502 -19
  158. aethergraph/services/container/default_container.py +122 -43
  159. aethergraph/services/continuations/continuation.py +6 -0
  160. aethergraph/services/continuations/stores/fs_store.py +19 -0
  161. aethergraph/services/eventhub/event_hub.py +76 -0
  162. aethergraph/services/kv/__init__.py +0 -0
  163. aethergraph/services/kv/ephemeral.py +244 -0
  164. aethergraph/services/llm/__init__.py +0 -0
  165. aethergraph/services/llm/generic_client copy.py +691 -0
  166. aethergraph/services/llm/generic_client.py +1288 -187
  167. aethergraph/services/llm/providers.py +3 -1
  168. aethergraph/services/llm/types.py +47 -0
  169. aethergraph/services/llm/utils.py +284 -0
  170. aethergraph/services/logger/std.py +3 -0
  171. aethergraph/services/mcp/__init__.py +9 -0
  172. aethergraph/services/mcp/http_client.py +38 -0
  173. aethergraph/services/mcp/service.py +225 -1
  174. aethergraph/services/mcp/stdio_client.py +41 -6
  175. aethergraph/services/mcp/ws_client.py +44 -2
  176. aethergraph/services/memory/__init__.py +0 -0
  177. aethergraph/services/memory/distillers/llm_long_term.py +234 -0
  178. aethergraph/services/memory/distillers/llm_meta_summary.py +398 -0
  179. aethergraph/services/memory/distillers/long_term.py +225 -0
  180. aethergraph/services/memory/facade/__init__.py +3 -0
  181. aethergraph/services/memory/facade/chat.py +440 -0
  182. aethergraph/services/memory/facade/core.py +447 -0
  183. aethergraph/services/memory/facade/distillation.py +424 -0
  184. aethergraph/services/memory/facade/rag.py +410 -0
  185. aethergraph/services/memory/facade/results.py +315 -0
  186. aethergraph/services/memory/facade/retrieval.py +139 -0
  187. aethergraph/services/memory/facade/types.py +77 -0
  188. aethergraph/services/memory/facade/utils.py +43 -0
  189. aethergraph/services/memory/facade_dep.py +1539 -0
  190. aethergraph/services/memory/factory.py +9 -3
  191. aethergraph/services/memory/utils.py +10 -0
  192. aethergraph/services/metering/eventlog_metering.py +470 -0
  193. aethergraph/services/metering/noop.py +25 -4
  194. aethergraph/services/rag/__init__.py +0 -0
  195. aethergraph/services/rag/facade.py +279 -23
  196. aethergraph/services/rag/index_factory.py +2 -2
  197. aethergraph/services/rag/node_rag.py +317 -0
  198. aethergraph/services/rate_limit/inmem_rate_limit.py +24 -0
  199. aethergraph/services/registry/__init__.py +0 -0
  200. aethergraph/services/registry/agent_app_meta.py +419 -0
  201. aethergraph/services/registry/registry_key.py +1 -1
  202. aethergraph/services/registry/unified_registry.py +74 -6
  203. aethergraph/services/scope/scope.py +159 -0
  204. aethergraph/services/scope/scope_factory.py +164 -0
  205. aethergraph/services/state_stores/serialize.py +5 -0
  206. aethergraph/services/state_stores/utils.py +2 -1
  207. aethergraph/services/viz/__init__.py +0 -0
  208. aethergraph/services/viz/facade.py +413 -0
  209. aethergraph/services/viz/viz_service.py +69 -0
  210. aethergraph/storage/artifacts/artifact_index_jsonl.py +180 -0
  211. aethergraph/storage/artifacts/artifact_index_sqlite.py +426 -0
  212. aethergraph/storage/artifacts/cas_store.py +422 -0
  213. aethergraph/storage/artifacts/fs_cas.py +18 -0
  214. aethergraph/storage/artifacts/s3_cas.py +14 -0
  215. aethergraph/storage/artifacts/utils.py +124 -0
  216. aethergraph/storage/blob/fs_blob.py +86 -0
  217. aethergraph/storage/blob/s3_blob.py +115 -0
  218. aethergraph/storage/continuation_store/fs_cont.py +283 -0
  219. aethergraph/storage/continuation_store/inmem_cont.py +146 -0
  220. aethergraph/storage/continuation_store/kvdoc_cont.py +261 -0
  221. aethergraph/storage/docstore/fs_doc.py +63 -0
  222. aethergraph/storage/docstore/sqlite_doc.py +31 -0
  223. aethergraph/storage/docstore/sqlite_doc_sync.py +90 -0
  224. aethergraph/storage/eventlog/fs_event.py +136 -0
  225. aethergraph/storage/eventlog/sqlite_event.py +47 -0
  226. aethergraph/storage/eventlog/sqlite_event_sync.py +178 -0
  227. aethergraph/storage/factory.py +432 -0
  228. aethergraph/storage/fs_utils.py +28 -0
  229. aethergraph/storage/graph_state_store/state_store.py +64 -0
  230. aethergraph/storage/kv/inmem_kv.py +103 -0
  231. aethergraph/storage/kv/layered_kv.py +52 -0
  232. aethergraph/storage/kv/sqlite_kv.py +39 -0
  233. aethergraph/storage/kv/sqlite_kv_sync.py +98 -0
  234. aethergraph/storage/memory/event_persist.py +68 -0
  235. aethergraph/storage/memory/fs_persist.py +118 -0
  236. aethergraph/{services/memory/hotlog_kv.py → storage/memory/hotlog.py} +8 -2
  237. aethergraph/{services → storage}/memory/indices.py +31 -7
  238. aethergraph/storage/metering/meter_event.py +55 -0
  239. aethergraph/storage/runs/doc_store.py +280 -0
  240. aethergraph/storage/runs/inmen_store.py +82 -0
  241. aethergraph/storage/runs/sqlite_run_store.py +403 -0
  242. aethergraph/storage/sessions/doc_store.py +183 -0
  243. aethergraph/storage/sessions/inmem_store.py +110 -0
  244. aethergraph/storage/sessions/sqlite_session_store.py +399 -0
  245. aethergraph/storage/vector_index/chroma_index.py +138 -0
  246. aethergraph/storage/vector_index/faiss_index.py +179 -0
  247. aethergraph/storage/vector_index/sqlite_index.py +187 -0
  248. {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/METADATA +138 -31
  249. aethergraph-0.1.0a3.dist-info/RECORD +356 -0
  250. aethergraph-0.1.0a3.dist-info/entry_points.txt +3 -0
  251. aethergraph/services/artifacts/factory.py +0 -35
  252. aethergraph/services/artifacts/fs_store.py +0 -656
  253. aethergraph/services/artifacts/jsonl_index.py +0 -123
  254. aethergraph/services/artifacts/sqlite_index.py +0 -209
  255. aethergraph/services/memory/distillers/episode.py +0 -116
  256. aethergraph/services/memory/distillers/rolling.py +0 -74
  257. aethergraph/services/memory/facade.py +0 -633
  258. aethergraph/services/memory/persist_fs.py +0 -40
  259. aethergraph/services/rag/index/base.py +0 -27
  260. aethergraph/services/rag/index/faiss_index.py +0 -121
  261. aethergraph/services/rag/index/sqlite_index.py +0 -134
  262. aethergraph-0.1.0a1.dist-info/RECORD +0 -182
  263. aethergraph-0.1.0a1.dist-info/entry_points.txt +0 -2
  264. {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/WHEEL +0 -0
  265. {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/licenses/LICENSE +0 -0
  266. {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/licenses/NOTICE +0 -0
  267. {aethergraph-0.1.0a1.dist-info → aethergraph-0.1.0a3.dist-info}/top_level.txt +0 -0
@@ -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: ...
@@ -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
- uri: str
12
- kind: str
13
- bytes: int
14
- sha256: str
15
- mime: str | None
16
- run_id: str
17
- graph_id: str
18
- node_id: str
19
- tool_name: str
20
- tool_version: str
21
- created_at: str
22
- labels: dict[str, Any]
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
- agent_id: str | None = None
48
+
49
+ # --------- Optional fields ---------
26
50
  tool: str | None = None # now used for tool topic: TODO: rename to topic in future
27
- kind: EventKind = "tool_result"
28
- stage: str | None = None
29
- severity: int = 2
30
- signal: float = 0.0
31
- tags: list[str] | None = None
32
- entities: list[str] | None = None
33
- inputs: list[Value] | None = None
34
- outputs: list[Value] | None = None
35
- inputs_ref: dict[str, Any] | None = None
36
- outputs_ref: dict[str, Any] | None = None
37
- metrics: dict[str, float] | None = None
38
- text: str | None = None
39
- embedding: list[float] | None = None
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
- sources: list[str] | None = None
42
- version: int = 1 # for schema evolution
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, run_id: str, *, hotlog: HotLog, persistence: Persistence, indices: Indices, **kw
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
+ """