activegraph 1.0.0rc2__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 (82) hide show
  1. activegraph/__init__.py +222 -0
  2. activegraph/__main__.py +5 -0
  3. activegraph/behaviors/__init__.py +1 -0
  4. activegraph/behaviors/base.py +153 -0
  5. activegraph/behaviors/decorators.py +218 -0
  6. activegraph/cli/__init__.py +17 -0
  7. activegraph/cli/main.py +793 -0
  8. activegraph/cli/quickstart.py +556 -0
  9. activegraph/core/__init__.py +1 -0
  10. activegraph/core/clock.py +46 -0
  11. activegraph/core/event.py +33 -0
  12. activegraph/core/graph.py +846 -0
  13. activegraph/core/ids.py +135 -0
  14. activegraph/core/patch.py +47 -0
  15. activegraph/core/view.py +59 -0
  16. activegraph/errors.py +342 -0
  17. activegraph/frame.py +15 -0
  18. activegraph/llm/__init__.py +51 -0
  19. activegraph/llm/anthropic.py +339 -0
  20. activegraph/llm/cache.py +180 -0
  21. activegraph/llm/errors.py +257 -0
  22. activegraph/llm/prompt.py +420 -0
  23. activegraph/llm/provider.py +66 -0
  24. activegraph/llm/recorded.py +270 -0
  25. activegraph/llm/types.py +130 -0
  26. activegraph/observability/__init__.py +61 -0
  27. activegraph/observability/logging.py +205 -0
  28. activegraph/observability/metrics.py +219 -0
  29. activegraph/observability/migration.py +404 -0
  30. activegraph/observability/prometheus.py +101 -0
  31. activegraph/observability/status.py +83 -0
  32. activegraph/packs/__init__.py +999 -0
  33. activegraph/packs/diligence/__init__.py +86 -0
  34. activegraph/packs/diligence/behaviors.py +447 -0
  35. activegraph/packs/diligence/fixtures/__init__.py +364 -0
  36. activegraph/packs/diligence/fixtures/companies.py +511 -0
  37. activegraph/packs/diligence/object_types.py +163 -0
  38. activegraph/packs/diligence/settings.py +60 -0
  39. activegraph/packs/diligence/tools.py +124 -0
  40. activegraph/packs/loader.py +709 -0
  41. activegraph/packs/scaffold.py +317 -0
  42. activegraph/policy.py +20 -0
  43. activegraph/runtime/__init__.py +1 -0
  44. activegraph/runtime/behavior_graph.py +151 -0
  45. activegraph/runtime/budget.py +120 -0
  46. activegraph/runtime/config_errors.py +124 -0
  47. activegraph/runtime/diff.py +145 -0
  48. activegraph/runtime/errors.py +216 -0
  49. activegraph/runtime/exec_errors.py +232 -0
  50. activegraph/runtime/patterns.py +946 -0
  51. activegraph/runtime/queue.py +27 -0
  52. activegraph/runtime/registration_errors.py +291 -0
  53. activegraph/runtime/registry.py +111 -0
  54. activegraph/runtime/runtime.py +2441 -0
  55. activegraph/runtime/scheduler.py +206 -0
  56. activegraph/runtime/view_builder.py +65 -0
  57. activegraph/store/__init__.py +41 -0
  58. activegraph/store/base.py +66 -0
  59. activegraph/store/conformance.py +161 -0
  60. activegraph/store/errors.py +84 -0
  61. activegraph/store/memory.py +118 -0
  62. activegraph/store/postgres.py +609 -0
  63. activegraph/store/serde.py +202 -0
  64. activegraph/store/sqlite.py +446 -0
  65. activegraph/store/url.py +230 -0
  66. activegraph/tools/__init__.py +64 -0
  67. activegraph/tools/base.py +57 -0
  68. activegraph/tools/cache.py +157 -0
  69. activegraph/tools/context.py +48 -0
  70. activegraph/tools/decorators.py +70 -0
  71. activegraph/tools/errors.py +320 -0
  72. activegraph/tools/graph_query.py +94 -0
  73. activegraph/tools/recorded.py +205 -0
  74. activegraph/tools/web_fetch.py +80 -0
  75. activegraph/trace/__init__.py +1 -0
  76. activegraph/trace/causal.py +123 -0
  77. activegraph/trace/printer.py +495 -0
  78. activegraph-1.0.0rc2.dist-info/METADATA +228 -0
  79. activegraph-1.0.0rc2.dist-info/RECORD +82 -0
  80. activegraph-1.0.0rc2.dist-info/WHEEL +5 -0
  81. activegraph-1.0.0rc2.dist-info/entry_points.txt +5 -0
  82. activegraph-1.0.0rc2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,118 @@
1
+ """In-memory EventStore. CONTRACT v0.5 #2.
2
+
3
+ Volatile, dict-backed. Useful for tests, for the default in-memory Runtime,
4
+ and as the reference implementation of the EventStore protocol.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Iterator, Optional
10
+
11
+ from activegraph.core.event import Event
12
+ from activegraph.store.errors import DuplicateEventError, EventNotFoundError
13
+
14
+
15
+ def _event_not_found(event_id: str, *, run_id: str, where: str) -> EventNotFoundError:
16
+ return EventNotFoundError(
17
+ f"event {event_id!r} not found in run {run_id!r}",
18
+ what_failed=(
19
+ f"The in-memory store was asked for event {event_id!r} (in {where}) "
20
+ f"but no event with that id exists in run {run_id!r}."
21
+ ),
22
+ why=(
23
+ "Event ids are the addressing primitive for the entire framework — "
24
+ "the replay cache, the causal-chain walk, and the fork primitive "
25
+ "all reference events by id. A lookup against an unknown id is a "
26
+ "bug in the caller; returning a default would silently corrupt the "
27
+ "audit trail."
28
+ ),
29
+ how_to_fix=(
30
+ "Check the event id against the events that actually exist in this "
31
+ "run. Common causes:\n"
32
+ " - typo in a hand-typed event id (evt_42 vs evt_042)\n"
33
+ " - referencing an id from a different run\n"
34
+ " - the run was truncated by an earlier fork or replay\n"
35
+ "\n"
36
+ "Inspect the run's event log to see the valid ids:\n"
37
+ " activegraph inspect <store-url> --run-id " + run_id
38
+ ),
39
+ context={"event_id": event_id, "run_id": run_id, "where": where},
40
+ )
41
+
42
+
43
+ class InMemoryEventStore:
44
+ def __init__(self, run_id: str = "run_mem") -> None:
45
+ self.run_id = run_id
46
+ self._events: list[Event] = []
47
+ self._by_id: dict[str, int] = {}
48
+
49
+ def append(self, event: Event) -> None:
50
+ if event.id in self._by_id:
51
+ raise DuplicateEventError(
52
+ f"duplicate event id: {event.id}",
53
+ what_failed=(
54
+ f"An event with id {event.id!r} already exists in this "
55
+ f"in-memory store. Appends are id-unique."
56
+ ),
57
+ why=(
58
+ "Event ids are the addressing primitive for the entire "
59
+ "framework — behaviors reference events by id, the replay "
60
+ "cache keys on them, the causal chain walks them. A "
61
+ "duplicate id would silently reroute one of those "
62
+ "references, corrupting the audit trail. The store refuses "
63
+ "the append rather than risk it."
64
+ ),
65
+ how_to_fix=(
66
+ "Event ids in normal use come from the runtime's monotonic "
67
+ "id generator (IDGen) and cannot collide. A duplicate almost "
68
+ "always means a test fixture is hand-constructing events with "
69
+ "fixed ids and a previous test left state behind. Use IDGen "
70
+ "to generate ids, or call `clear_registry()` / construct a "
71
+ "fresh Graph between tests."
72
+ ),
73
+ context={"event_id": event.id, "run_id": self.run_id},
74
+ )
75
+ self._by_id[event.id] = len(self._events)
76
+ self._events.append(event)
77
+
78
+ def iter_events(
79
+ self,
80
+ after: Optional[str] = None,
81
+ until: Optional[str] = None,
82
+ ) -> Iterator[Event]:
83
+ start = 0
84
+ end = len(self._events)
85
+ if after is not None:
86
+ if after not in self._by_id:
87
+ raise _event_not_found(after, run_id=self.run_id, where="iter_events(after=)")
88
+ start = self._by_id[after] + 1
89
+ if until is not None:
90
+ if until not in self._by_id:
91
+ raise _event_not_found(until, run_id=self.run_id, where="iter_events(until=)")
92
+ end = self._by_id[until] + 1
93
+ for i in range(start, end):
94
+ yield self._events[i]
95
+
96
+ def get_event(self, event_id: str) -> Optional[Event]:
97
+ idx = self._by_id.get(event_id)
98
+ if idx is None:
99
+ return None
100
+ return self._events[idx]
101
+
102
+ def count(self) -> int:
103
+ return len(self._events)
104
+
105
+ def truncate_after(self, event_id: str) -> None:
106
+ if event_id not in self._by_id:
107
+ raise _event_not_found(event_id, run_id=self.run_id, where="truncate_after(event_id=)")
108
+ cut = self._by_id[event_id] + 1
109
+ dropped = self._events[cut:]
110
+ self._events = self._events[:cut]
111
+ for ev in dropped:
112
+ del self._by_id[ev.id]
113
+
114
+ def close(self) -> None:
115
+ pass
116
+
117
+ def __len__(self) -> int:
118
+ return len(self._events)