activegraph 1.0.0rc2__tar.gz → 1.0.1__tar.gz
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.
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/PKG-INFO +88 -13
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/README.md +72 -12
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/__init__.py +3 -1
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/behaviors/decorators.py +73 -1
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/errors.py +10 -7
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/__init__.py +10 -1
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/anthropic.py +1 -52
- activegraph-1.0.1/activegraph/llm/openai.py +349 -0
- activegraph-1.0.1/activegraph/llm/parsing.py +84 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/prompt.py +108 -3
- activegraph-1.0.1/activegraph/packs/diligence/prompts/document_researcher.md +25 -0
- activegraph-1.0.1/activegraph/packs/diligence/prompts/memo_synthesizer.md +35 -0
- activegraph-1.0.1/activegraph/packs/diligence/prompts/question_generator.md +25 -0
- activegraph-1.0.1/activegraph/packs/diligence/prompts/risk_identifier.md +26 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/sqlite.py +22 -2
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph.egg-info/PKG-INFO +88 -13
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph.egg-info/SOURCES.txt +11 -1
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph.egg-info/requires.txt +18 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/pyproject.toml +45 -2
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_doc_links.py +17 -7
- activegraph-1.0.1/tests/test_doc_site_reachable.py +121 -0
- activegraph-1.0.1/tests/test_llm_openai.py +263 -0
- activegraph-1.0.1/tests/test_v1_0_1_patches.py +226 -0
- activegraph-1.0.1/tests/test_wheel_completeness.py +99 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/__main__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/behaviors/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/behaviors/base.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/cli/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/cli/main.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/cli/quickstart.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/core/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/core/clock.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/core/event.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/core/graph.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/core/ids.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/core/patch.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/core/view.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/frame.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/cache.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/errors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/provider.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/recorded.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/llm/types.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/observability/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/observability/logging.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/observability/metrics.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/observability/migration.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/observability/prometheus.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/observability/status.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/diligence/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/diligence/behaviors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/diligence/fixtures/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/diligence/fixtures/companies.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/diligence/object_types.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/diligence/settings.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/diligence/tools.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/loader.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/packs/scaffold.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/policy.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/behavior_graph.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/budget.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/config_errors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/diff.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/errors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/exec_errors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/patterns.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/queue.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/registration_errors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/registry.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/runtime.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/scheduler.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/runtime/view_builder.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/base.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/conformance.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/errors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/memory.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/postgres.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/serde.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/store/url.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/base.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/cache.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/context.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/decorators.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/errors.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/graph_query.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/recorded.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/tools/web_fetch.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/trace/__init__.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/trace/causal.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph/trace/printer.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph.egg-info/dependency_links.txt +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph.egg-info/entry_points.txt +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/activegraph.egg-info/top_level.txt +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/setup.cfg +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_activate_after.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_causal_cross_tool.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_cli.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_clock.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_diff.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_diligence_pack.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_diligence_with_tools.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_errors_format.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_event.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_fork.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_graph.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_ids.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_anthropic.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_behavior.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_budget.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_causal.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_claim_extraction.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_determinism.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_failure.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_prompt.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_provider_fixtures.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_replay.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_tool_loop.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_trace.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_trace_snapshot.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_llm_types.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_migration.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_observability_logging.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_observability_metrics.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_operate_example.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_pack_scaffold.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_packs.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_patch.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_pattern_matcher.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_pattern_parser.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_pattern_subscriptions.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_persistence.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_postgres_store.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_quickstart.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_quickstart_snapshot.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_replay.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_replay_trace_snapshot.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_requeue_unfired.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_resume_example.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_runtime.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_runtime_status.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_serde.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_store_conformance.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_store_url.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_tool_replay.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_tool_trace_snapshot.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_tools.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_trace.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_tutorial_snippets.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_version_sync.py +0 -0
- {activegraph-1.0.0rc2 → activegraph-1.0.1}/tests/test_view.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: activegraph
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: An event-sourced reactive graph runtime for long-running, auditable, agentic systems.
|
|
5
5
|
Author: Active Graph contributors
|
|
6
6
|
License: MIT
|
|
@@ -18,7 +18,16 @@ Requires-Dist: click<9,>=8
|
|
|
18
18
|
Requires-Dist: pydantic>=2
|
|
19
19
|
Provides-Extra: llm
|
|
20
20
|
Requires-Dist: anthropic>=0.40; extra == "llm"
|
|
21
|
+
Requires-Dist: openai>=1.0; extra == "llm"
|
|
22
|
+
Requires-Dist: tiktoken>=0.7; extra == "llm"
|
|
21
23
|
Requires-Dist: pydantic>=2; extra == "llm"
|
|
24
|
+
Provides-Extra: anthropic
|
|
25
|
+
Requires-Dist: anthropic>=0.40; extra == "anthropic"
|
|
26
|
+
Requires-Dist: pydantic>=2; extra == "anthropic"
|
|
27
|
+
Provides-Extra: openai
|
|
28
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
29
|
+
Requires-Dist: tiktoken>=0.7; extra == "openai"
|
|
30
|
+
Requires-Dist: pydantic>=2; extra == "openai"
|
|
22
31
|
Provides-Extra: sqlite
|
|
23
32
|
Provides-Extra: postgres
|
|
24
33
|
Requires-Dist: psycopg[binary]<4,>=3.1; extra == "postgres"
|
|
@@ -26,6 +35,8 @@ Provides-Extra: prometheus
|
|
|
26
35
|
Requires-Dist: prometheus_client>=0.20; extra == "prometheus"
|
|
27
36
|
Provides-Extra: all
|
|
28
37
|
Requires-Dist: anthropic>=0.40; extra == "all"
|
|
38
|
+
Requires-Dist: openai>=1.0; extra == "all"
|
|
39
|
+
Requires-Dist: tiktoken>=0.7; extra == "all"
|
|
29
40
|
Requires-Dist: pydantic>=2; extra == "all"
|
|
30
41
|
Requires-Dist: psycopg[binary]<4,>=3.1; extra == "all"
|
|
31
42
|
Requires-Dist: prometheus_client>=0.20; extra == "all"
|
|
@@ -34,6 +45,10 @@ Requires-Dist: pytest>=7; extra == "dev"
|
|
|
34
45
|
Requires-Dist: pydantic>=2; extra == "dev"
|
|
35
46
|
Requires-Dist: prometheus_client>=0.20; extra == "dev"
|
|
36
47
|
Requires-Dist: psycopg[binary]<4,>=3.1; extra == "dev"
|
|
48
|
+
Provides-Extra: docs
|
|
49
|
+
Requires-Dist: mkdocs>=1.6; extra == "docs"
|
|
50
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
51
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
|
|
37
52
|
|
|
38
53
|
# Active Graph
|
|
39
54
|
|
|
@@ -73,12 +88,20 @@ capability.
|
|
|
73
88
|
|
|
74
89
|
```bash
|
|
75
90
|
pip install activegraph # core runtime + SQLite store + Diligence pack
|
|
76
|
-
pip install "activegraph[llm]" # Anthropic
|
|
91
|
+
pip install "activegraph[llm]" # Anthropic + OpenAI providers
|
|
92
|
+
pip install "activegraph[anthropic]" # Anthropic provider only
|
|
93
|
+
pip install "activegraph[openai]" # OpenAI provider only (+ tiktoken)
|
|
77
94
|
pip install "activegraph[postgres]" # Postgres-backed event store
|
|
78
95
|
pip install "activegraph[prometheus]" # Prometheus metrics
|
|
79
96
|
pip install "activegraph[all]" # everything
|
|
80
97
|
```
|
|
81
98
|
|
|
99
|
+
Both LLM providers expose the same `LLMProvider` Protocol surface;
|
|
100
|
+
swap one for the other without touching `@llm_behavior` definitions.
|
|
101
|
+
The [LLM providers reference](https://docs.activegraph.ai/reference/llm-providers/)
|
|
102
|
+
covers the side-by-side surface and the v1.0.1 limitations
|
|
103
|
+
(OpenAI tool use is a v1.1 candidate).
|
|
104
|
+
|
|
82
105
|
Python 3.11+. Two hard dependencies (`click` for the CLI, `pydantic`
|
|
83
106
|
for the pack format); persistence backends and provider integrations
|
|
84
107
|
are opt-in extras.
|
|
@@ -102,7 +125,54 @@ are opt-in extras.
|
|
|
102
125
|
8 object types, 7 behaviors, 3 tools, recorded fixtures.
|
|
103
126
|
- **Per-error reference pages.** Every error message ends with a
|
|
104
127
|
`More:` link to a page that explains when it fires, why, and how to
|
|
105
|
-
fix it. Catalog at [docs.activegraph.
|
|
128
|
+
fix it. Catalog at [docs.activegraph.ai/reference/errors](https://docs.activegraph.ai/reference/errors/).
|
|
129
|
+
|
|
130
|
+
## Concepts at a glance
|
|
131
|
+
|
|
132
|
+
The framework's twelve primitives, in roughly the order you meet them
|
|
133
|
+
when reading a trace. Each links to its concept page on the doc site;
|
|
134
|
+
read those when you want depth on one piece.
|
|
135
|
+
|
|
136
|
+
- **Graph** — objects and typed relations forming the world the
|
|
137
|
+
framework reasons about. The graph is a projection of the event log;
|
|
138
|
+
every mutation is an event. [→ concepts/graph](https://docs.activegraph.ai/concepts/graph/)
|
|
139
|
+
- **Events** — the append-only history. Every behavior fires in
|
|
140
|
+
response to events and produces more events; the trace is the
|
|
141
|
+
ordered log of all of them. [→ concepts/events](https://docs.activegraph.ai/concepts/events/)
|
|
142
|
+
- **Behaviors** — the unit of reactive code. Function, class, or
|
|
143
|
+
LLM-backed; declares what events it subscribes to and what it
|
|
144
|
+
produces. The determinism contract is per-behavior. [→ concepts/behaviors](https://docs.activegraph.ai/concepts/behaviors/)
|
|
145
|
+
- **Relations** — typed edges between objects, with their own
|
|
146
|
+
behaviors. The relation-behavior primitive — coordination logic on
|
|
147
|
+
the edge, not on either endpoint — is uncommon in other agent
|
|
148
|
+
frameworks. [→ concepts/relations](https://docs.activegraph.ai/concepts/relations/)
|
|
149
|
+
- **Patches** — proposed mutations with optimistic concurrency.
|
|
150
|
+
Behaviors propose patches; the runtime applies or rejects them;
|
|
151
|
+
rejections are events in their own right. [→ concepts/patches](https://docs.activegraph.ai/concepts/patches/)
|
|
152
|
+
- **Views** — scoped reads of the graph for behavior context. Type
|
|
153
|
+
filters, depth filters, recent-event windows. Views are how
|
|
154
|
+
pattern-driven behaviors see only what they need to. [→ concepts/views](https://docs.activegraph.ai/concepts/views/)
|
|
155
|
+
- **Frames** — bounded contexts for a run. Goal, constraints, budget,
|
|
156
|
+
and the registered behaviors for this frame. A run can have one
|
|
157
|
+
frame or many. [→ concepts/frames](https://docs.activegraph.ai/concepts/frames/)
|
|
158
|
+
- **Policies** — approval and gating for behavior capabilities. Which
|
|
159
|
+
behaviors can call which tools, which mutations require human
|
|
160
|
+
approval, what the runtime refuses. [→ concepts/policies](https://docs.activegraph.ai/concepts/policies/)
|
|
161
|
+
- **Patterns** — the Cypher subset for pattern subscriptions. Beyond
|
|
162
|
+
event-type + predicate, behaviors can subscribe to graph shapes
|
|
163
|
+
(claim-cited-by-evidence, task-blocks-task, …) with `NOT EXISTS`
|
|
164
|
+
and temporal predicates. [→ concepts/patterns](https://docs.activegraph.ai/concepts/patterns/)
|
|
165
|
+
- **Replay** — re-execute a run from its event log. Strict mode
|
|
166
|
+
re-fires every behavior and fails on divergence; permissive mode
|
|
167
|
+
reconstructs state without re-firing. The LLM replay cache is what
|
|
168
|
+
makes fork cheap. [→ concepts/replay](https://docs.activegraph.ai/concepts/replay/)
|
|
169
|
+
- **Forking** — branch any run at any event into an independent
|
|
170
|
+
fork; structurally diff the fork against the parent. The framework's
|
|
171
|
+
mechanism for hypothesis testing on agentic systems. [→ concepts/forking](https://docs.activegraph.ai/concepts/forking/)
|
|
172
|
+
- **Failure model** — a behavior failure is a `behavior.failed`
|
|
173
|
+
event, not an exception. The audit trail captures failures as
|
|
174
|
+
first-class history. Exceptions live at runtime entry points only.
|
|
175
|
+
[→ concepts/failure-model](https://docs.activegraph.ai/concepts/failure-model/)
|
|
106
176
|
|
|
107
177
|
## A small example
|
|
108
178
|
|
|
@@ -140,14 +210,14 @@ runtime.print_trace()
|
|
|
140
210
|
|
|
141
211
|
The `unblock` relation behavior fires only for events touching one of
|
|
142
212
|
its edge endpoints. The conceptual deep-dive on edges-with-logic is
|
|
143
|
-
in [`docs/concepts/relations.md`](https://docs.activegraph.
|
|
213
|
+
in [`docs/concepts/relations.md`](https://docs.activegraph.ai/concepts/relations/).
|
|
144
214
|
|
|
145
215
|
## Documentation
|
|
146
216
|
|
|
147
|
-
- **[docs.activegraph.
|
|
217
|
+
- **[docs.activegraph.ai](https://docs.activegraph.ai/)** — full doc site:
|
|
148
218
|
concepts, guides, cookbook, CLI reference, API reference, the
|
|
149
219
|
per-error catalog.
|
|
150
|
-
- **[10-minute tutorial](https://docs.activegraph.
|
|
220
|
+
- **[10-minute tutorial](https://docs.activegraph.ai/quickstart/)** — install
|
|
151
221
|
to a working custom behavior, including fork-and-diff.
|
|
152
222
|
- **[CHANGELOG.md](CHANGELOG.md)** — every release, with per-version
|
|
153
223
|
migration notes.
|
|
@@ -159,7 +229,9 @@ in [`docs/concepts/relations.md`](https://docs.activegraph.dev/concepts/relation
|
|
|
159
229
|
[`resume_and_fork.py`](examples/resume_and_fork.py),
|
|
160
230
|
[`llm_claim_extraction.py`](examples/llm_claim_extraction.py),
|
|
161
231
|
[`diligence_with_tools.py`](examples/diligence_with_tools.py),
|
|
162
|
-
[`operate_a_run.py`](examples/operate_a_run.py)
|
|
232
|
+
[`operate_a_run.py`](examples/operate_a_run.py),
|
|
233
|
+
[`babyagi.py`](examples/babyagi.py) — BabyAGI's autonomous agent loop,
|
|
234
|
+
rebuilt as three reactive behaviors over a shared graph.
|
|
163
235
|
|
|
164
236
|
## What this is not
|
|
165
237
|
|
|
@@ -178,17 +250,20 @@ in [`docs/concepts/relations.md`](https://docs.activegraph.dev/concepts/relation
|
|
|
178
250
|
|
|
179
251
|
## Status
|
|
180
252
|
|
|
181
|
-
**v1.0
|
|
182
|
-
|
|
183
|
-
|
|
253
|
+
**v1.0 (stable)** (2026-05). The first-time-user gate per
|
|
254
|
+
[CONTRACT v1.0 #C4](CONTRACT.md#v10-c4-v10-ships-as-v10-rc1-first-time-user-gate-is-owned-externally)
|
|
255
|
+
ran through three rcs; v1.0 final ships rc3 plus a tutorial-step-7
|
|
256
|
+
output fix and a README "Concepts at a glance" index. See
|
|
257
|
+
[CHANGELOG.md](CHANGELOG.md) for the full v0 → v1.0 history and
|
|
184
258
|
per-version migration notes.
|
|
185
259
|
|
|
186
260
|
Major shipped milestones:
|
|
187
261
|
|
|
188
|
-
- **v1.0
|
|
189
|
-
pages, doc site at [docs.activegraph.
|
|
262
|
+
- **v1.0** — error hierarchy rewrite with per-error reference
|
|
263
|
+
pages, doc site at [docs.activegraph.ai](https://docs.activegraph.ai/),
|
|
190
264
|
`activegraph quickstart` command, mypy `--strict` and docstring
|
|
191
|
-
coverage CI gates
|
|
265
|
+
coverage CI gates, wheel-completeness and deploy-verification CI
|
|
266
|
+
gates.
|
|
192
267
|
- **v0.9** — pack format and the Diligence reference pack (8 object
|
|
193
268
|
types, 7 behaviors, 3 tools, recorded fixtures).
|
|
194
269
|
- **v0.8** — operator surface: structured logging, Prometheus
|
|
@@ -36,12 +36,20 @@ capability.
|
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
pip install activegraph # core runtime + SQLite store + Diligence pack
|
|
39
|
-
pip install "activegraph[llm]" # Anthropic
|
|
39
|
+
pip install "activegraph[llm]" # Anthropic + OpenAI providers
|
|
40
|
+
pip install "activegraph[anthropic]" # Anthropic provider only
|
|
41
|
+
pip install "activegraph[openai]" # OpenAI provider only (+ tiktoken)
|
|
40
42
|
pip install "activegraph[postgres]" # Postgres-backed event store
|
|
41
43
|
pip install "activegraph[prometheus]" # Prometheus metrics
|
|
42
44
|
pip install "activegraph[all]" # everything
|
|
43
45
|
```
|
|
44
46
|
|
|
47
|
+
Both LLM providers expose the same `LLMProvider` Protocol surface;
|
|
48
|
+
swap one for the other without touching `@llm_behavior` definitions.
|
|
49
|
+
The [LLM providers reference](https://docs.activegraph.ai/reference/llm-providers/)
|
|
50
|
+
covers the side-by-side surface and the v1.0.1 limitations
|
|
51
|
+
(OpenAI tool use is a v1.1 candidate).
|
|
52
|
+
|
|
45
53
|
Python 3.11+. Two hard dependencies (`click` for the CLI, `pydantic`
|
|
46
54
|
for the pack format); persistence backends and provider integrations
|
|
47
55
|
are opt-in extras.
|
|
@@ -65,7 +73,54 @@ are opt-in extras.
|
|
|
65
73
|
8 object types, 7 behaviors, 3 tools, recorded fixtures.
|
|
66
74
|
- **Per-error reference pages.** Every error message ends with a
|
|
67
75
|
`More:` link to a page that explains when it fires, why, and how to
|
|
68
|
-
fix it. Catalog at [docs.activegraph.
|
|
76
|
+
fix it. Catalog at [docs.activegraph.ai/reference/errors](https://docs.activegraph.ai/reference/errors/).
|
|
77
|
+
|
|
78
|
+
## Concepts at a glance
|
|
79
|
+
|
|
80
|
+
The framework's twelve primitives, in roughly the order you meet them
|
|
81
|
+
when reading a trace. Each links to its concept page on the doc site;
|
|
82
|
+
read those when you want depth on one piece.
|
|
83
|
+
|
|
84
|
+
- **Graph** — objects and typed relations forming the world the
|
|
85
|
+
framework reasons about. The graph is a projection of the event log;
|
|
86
|
+
every mutation is an event. [→ concepts/graph](https://docs.activegraph.ai/concepts/graph/)
|
|
87
|
+
- **Events** — the append-only history. Every behavior fires in
|
|
88
|
+
response to events and produces more events; the trace is the
|
|
89
|
+
ordered log of all of them. [→ concepts/events](https://docs.activegraph.ai/concepts/events/)
|
|
90
|
+
- **Behaviors** — the unit of reactive code. Function, class, or
|
|
91
|
+
LLM-backed; declares what events it subscribes to and what it
|
|
92
|
+
produces. The determinism contract is per-behavior. [→ concepts/behaviors](https://docs.activegraph.ai/concepts/behaviors/)
|
|
93
|
+
- **Relations** — typed edges between objects, with their own
|
|
94
|
+
behaviors. The relation-behavior primitive — coordination logic on
|
|
95
|
+
the edge, not on either endpoint — is uncommon in other agent
|
|
96
|
+
frameworks. [→ concepts/relations](https://docs.activegraph.ai/concepts/relations/)
|
|
97
|
+
- **Patches** — proposed mutations with optimistic concurrency.
|
|
98
|
+
Behaviors propose patches; the runtime applies or rejects them;
|
|
99
|
+
rejections are events in their own right. [→ concepts/patches](https://docs.activegraph.ai/concepts/patches/)
|
|
100
|
+
- **Views** — scoped reads of the graph for behavior context. Type
|
|
101
|
+
filters, depth filters, recent-event windows. Views are how
|
|
102
|
+
pattern-driven behaviors see only what they need to. [→ concepts/views](https://docs.activegraph.ai/concepts/views/)
|
|
103
|
+
- **Frames** — bounded contexts for a run. Goal, constraints, budget,
|
|
104
|
+
and the registered behaviors for this frame. A run can have one
|
|
105
|
+
frame or many. [→ concepts/frames](https://docs.activegraph.ai/concepts/frames/)
|
|
106
|
+
- **Policies** — approval and gating for behavior capabilities. Which
|
|
107
|
+
behaviors can call which tools, which mutations require human
|
|
108
|
+
approval, what the runtime refuses. [→ concepts/policies](https://docs.activegraph.ai/concepts/policies/)
|
|
109
|
+
- **Patterns** — the Cypher subset for pattern subscriptions. Beyond
|
|
110
|
+
event-type + predicate, behaviors can subscribe to graph shapes
|
|
111
|
+
(claim-cited-by-evidence, task-blocks-task, …) with `NOT EXISTS`
|
|
112
|
+
and temporal predicates. [→ concepts/patterns](https://docs.activegraph.ai/concepts/patterns/)
|
|
113
|
+
- **Replay** — re-execute a run from its event log. Strict mode
|
|
114
|
+
re-fires every behavior and fails on divergence; permissive mode
|
|
115
|
+
reconstructs state without re-firing. The LLM replay cache is what
|
|
116
|
+
makes fork cheap. [→ concepts/replay](https://docs.activegraph.ai/concepts/replay/)
|
|
117
|
+
- **Forking** — branch any run at any event into an independent
|
|
118
|
+
fork; structurally diff the fork against the parent. The framework's
|
|
119
|
+
mechanism for hypothesis testing on agentic systems. [→ concepts/forking](https://docs.activegraph.ai/concepts/forking/)
|
|
120
|
+
- **Failure model** — a behavior failure is a `behavior.failed`
|
|
121
|
+
event, not an exception. The audit trail captures failures as
|
|
122
|
+
first-class history. Exceptions live at runtime entry points only.
|
|
123
|
+
[→ concepts/failure-model](https://docs.activegraph.ai/concepts/failure-model/)
|
|
69
124
|
|
|
70
125
|
## A small example
|
|
71
126
|
|
|
@@ -103,14 +158,14 @@ runtime.print_trace()
|
|
|
103
158
|
|
|
104
159
|
The `unblock` relation behavior fires only for events touching one of
|
|
105
160
|
its edge endpoints. The conceptual deep-dive on edges-with-logic is
|
|
106
|
-
in [`docs/concepts/relations.md`](https://docs.activegraph.
|
|
161
|
+
in [`docs/concepts/relations.md`](https://docs.activegraph.ai/concepts/relations/).
|
|
107
162
|
|
|
108
163
|
## Documentation
|
|
109
164
|
|
|
110
|
-
- **[docs.activegraph.
|
|
165
|
+
- **[docs.activegraph.ai](https://docs.activegraph.ai/)** — full doc site:
|
|
111
166
|
concepts, guides, cookbook, CLI reference, API reference, the
|
|
112
167
|
per-error catalog.
|
|
113
|
-
- **[10-minute tutorial](https://docs.activegraph.
|
|
168
|
+
- **[10-minute tutorial](https://docs.activegraph.ai/quickstart/)** — install
|
|
114
169
|
to a working custom behavior, including fork-and-diff.
|
|
115
170
|
- **[CHANGELOG.md](CHANGELOG.md)** — every release, with per-version
|
|
116
171
|
migration notes.
|
|
@@ -122,7 +177,9 @@ in [`docs/concepts/relations.md`](https://docs.activegraph.dev/concepts/relation
|
|
|
122
177
|
[`resume_and_fork.py`](examples/resume_and_fork.py),
|
|
123
178
|
[`llm_claim_extraction.py`](examples/llm_claim_extraction.py),
|
|
124
179
|
[`diligence_with_tools.py`](examples/diligence_with_tools.py),
|
|
125
|
-
[`operate_a_run.py`](examples/operate_a_run.py)
|
|
180
|
+
[`operate_a_run.py`](examples/operate_a_run.py),
|
|
181
|
+
[`babyagi.py`](examples/babyagi.py) — BabyAGI's autonomous agent loop,
|
|
182
|
+
rebuilt as three reactive behaviors over a shared graph.
|
|
126
183
|
|
|
127
184
|
## What this is not
|
|
128
185
|
|
|
@@ -141,17 +198,20 @@ in [`docs/concepts/relations.md`](https://docs.activegraph.dev/concepts/relation
|
|
|
141
198
|
|
|
142
199
|
## Status
|
|
143
200
|
|
|
144
|
-
**v1.0
|
|
145
|
-
|
|
146
|
-
|
|
201
|
+
**v1.0 (stable)** (2026-05). The first-time-user gate per
|
|
202
|
+
[CONTRACT v1.0 #C4](CONTRACT.md#v10-c4-v10-ships-as-v10-rc1-first-time-user-gate-is-owned-externally)
|
|
203
|
+
ran through three rcs; v1.0 final ships rc3 plus a tutorial-step-7
|
|
204
|
+
output fix and a README "Concepts at a glance" index. See
|
|
205
|
+
[CHANGELOG.md](CHANGELOG.md) for the full v0 → v1.0 history and
|
|
147
206
|
per-version migration notes.
|
|
148
207
|
|
|
149
208
|
Major shipped milestones:
|
|
150
209
|
|
|
151
|
-
- **v1.0
|
|
152
|
-
pages, doc site at [docs.activegraph.
|
|
210
|
+
- **v1.0** — error hierarchy rewrite with per-error reference
|
|
211
|
+
pages, doc site at [docs.activegraph.ai](https://docs.activegraph.ai/),
|
|
153
212
|
`activegraph quickstart` command, mypy `--strict` and docstring
|
|
154
|
-
coverage CI gates
|
|
213
|
+
coverage CI gates, wheel-completeness and deploy-verification CI
|
|
214
|
+
gates.
|
|
155
215
|
- **v0.9** — pack format and the Diligence reference pack (8 object
|
|
156
216
|
types, 7 behaviors, 3 tools, recorded fixtures).
|
|
157
217
|
- **v0.8** — operator surface: structured logging, Prometheus
|
|
@@ -9,6 +9,7 @@ from activegraph.behaviors.decorators import (
|
|
|
9
9
|
clear_registry,
|
|
10
10
|
get_registry,
|
|
11
11
|
llm_behavior,
|
|
12
|
+
register,
|
|
12
13
|
relation_behavior,
|
|
13
14
|
)
|
|
14
15
|
from activegraph.core.clock import Clock, FrozenClock, TickingClock
|
|
@@ -215,8 +216,9 @@ __all__ = [
|
|
|
215
216
|
"migrate",
|
|
216
217
|
"open_store",
|
|
217
218
|
"parse_store_url",
|
|
219
|
+
"register",
|
|
218
220
|
"relation_behavior",
|
|
219
221
|
"tool",
|
|
220
222
|
]
|
|
221
223
|
|
|
222
|
-
__version__ = "1.0.
|
|
224
|
+
__version__ = "1.0.1"
|
|
@@ -27,14 +27,66 @@ from activegraph.behaviors.base import (
|
|
|
27
27
|
_REGISTRY: list[Union[Behavior, RelationBehavior]] = []
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def clear_registry() ->
|
|
30
|
+
def clear_registry() -> list[Union[Behavior, RelationBehavior]]:
|
|
31
|
+
"""Empty the global behavior registry and return what was cleared.
|
|
32
|
+
|
|
33
|
+
Tests that need isolation between cases call this in a fixture; the
|
|
34
|
+
return value is the list of removed behaviors in registration
|
|
35
|
+
order, so multi-run scripts can capture them once and re-register
|
|
36
|
+
via :func:`register` on each subsequent run without re-importing
|
|
37
|
+
the modules whose ``@behavior`` decorators populated the registry
|
|
38
|
+
in the first place. See the *Multi-run scripts* cookbook recipe.
|
|
39
|
+
|
|
40
|
+
v1.0.1: the return value is new. v1.0 returned ``None``; callers
|
|
41
|
+
that ignored the return still work unchanged.
|
|
42
|
+
"""
|
|
43
|
+
cleared: list[Union[Behavior, RelationBehavior]] = list(_REGISTRY)
|
|
31
44
|
_REGISTRY.clear()
|
|
45
|
+
return cleared
|
|
32
46
|
|
|
33
47
|
|
|
34
48
|
def get_registry() -> list[Union[Behavior, RelationBehavior]]:
|
|
49
|
+
"""Snapshot of the global behavior registry (a shallow copy)."""
|
|
35
50
|
return list(_REGISTRY)
|
|
36
51
|
|
|
37
52
|
|
|
53
|
+
def register(behavior_obj: Union[Behavior, RelationBehavior]) -> None:
|
|
54
|
+
"""Append an already-constructed behavior to the global registry.
|
|
55
|
+
|
|
56
|
+
The decorators (:func:`behavior`, :func:`relation_behavior`,
|
|
57
|
+
:func:`llm_behavior`) register on definition; this function exists
|
|
58
|
+
for the case where definition and registration are decoupled —
|
|
59
|
+
most commonly, multi-run scripts that call :func:`clear_registry`
|
|
60
|
+
between runs and need to re-populate the registry without
|
|
61
|
+
re-importing the decorator-bearing modules:
|
|
62
|
+
|
|
63
|
+
.. code-block:: python
|
|
64
|
+
|
|
65
|
+
from activegraph import clear_registry, register
|
|
66
|
+
|
|
67
|
+
cleared = clear_registry() # capture before the first run
|
|
68
|
+
rt1 = Runtime(graph1); rt1.run_goal("first")
|
|
69
|
+
|
|
70
|
+
for b in cleared: # restore for the next run
|
|
71
|
+
register(b)
|
|
72
|
+
rt2 = Runtime(graph2); rt2.run_goal("second")
|
|
73
|
+
|
|
74
|
+
See the *Multi-run scripts* cookbook recipe.
|
|
75
|
+
|
|
76
|
+
v1.0.1: new. v1.0 required reaching into the private
|
|
77
|
+
``_REGISTRY`` list — the user-test gate surfaced that as a rough
|
|
78
|
+
edge.
|
|
79
|
+
"""
|
|
80
|
+
if not isinstance(behavior_obj, (Behavior, RelationBehavior)):
|
|
81
|
+
raise TypeError(
|
|
82
|
+
f"register() expected a Behavior, RelationBehavior, or "
|
|
83
|
+
f"LLMBehavior instance; got {type(behavior_obj).__name__}. "
|
|
84
|
+
f"Use the @behavior / @relation_behavior / @llm_behavior "
|
|
85
|
+
f"decorators to construct one."
|
|
86
|
+
)
|
|
87
|
+
_REGISTRY.append(behavior_obj)
|
|
88
|
+
|
|
89
|
+
|
|
38
90
|
def behavior(
|
|
39
91
|
name: Optional[str] = None,
|
|
40
92
|
on: Optional[list[str]] = None,
|
|
@@ -124,6 +176,26 @@ def llm_behavior(
|
|
|
124
176
|
|
|
125
177
|
Keyword-only on purpose — `@llm_behavior` carries enough
|
|
126
178
|
parameters that positional binding would be a footgun.
|
|
179
|
+
|
|
180
|
+
`prompt_template=` is the only escape hatch from the
|
|
181
|
+
runtime-assembled prompt. It is a `str.format`-style template that
|
|
182
|
+
receives four placeholders:
|
|
183
|
+
|
|
184
|
+
- ``{system}`` — the system block: behavior name, frame goal and
|
|
185
|
+
constraints, role description, and (when `output_schema=` is set)
|
|
186
|
+
the schema with an example instance.
|
|
187
|
+
- ``{view}`` — the scoped graph view: objects, relations, and
|
|
188
|
+
recent events, rendered as Markdown (format locked per
|
|
189
|
+
CONTRACT v0.6 #13).
|
|
190
|
+
- ``{event}`` — the triggering event as id, type, actor, and
|
|
191
|
+
pretty-printed JSON payload with volatile keys stripped.
|
|
192
|
+
- ``{instruction}`` — the one-sentence task derived from `creates=`
|
|
193
|
+
and `output_schema=`.
|
|
194
|
+
|
|
195
|
+
The four placeholders carry the same runtime-assembled content
|
|
196
|
+
whether or not a template is set; the template only re-arranges
|
|
197
|
+
them. Omitting `prompt_template=` (the default) uses the
|
|
198
|
+
runtime's canonical layout.
|
|
127
199
|
"""
|
|
128
200
|
|
|
129
201
|
from activegraph.runtime.patterns import parse as _parse_pattern
|
|
@@ -16,7 +16,7 @@ locked format:
|
|
|
16
16
|
<concrete action>
|
|
17
17
|
|
|
18
18
|
More:
|
|
19
|
-
https://docs.activegraph.
|
|
19
|
+
https://docs.activegraph.ai/errors/<slug>
|
|
20
20
|
|
|
21
21
|
The seven category bases are stable. Concrete leaves are migrated under
|
|
22
22
|
their categories one PR at a time (CONTRACT v1.0 #C1 — the rewrite ships
|
|
@@ -25,8 +25,8 @@ as the reference category; subsequent PRs migrate the other categories
|
|
|
25
25
|
without changing the bases.
|
|
26
26
|
|
|
27
27
|
`_doc_slug` on each class is the URL slug for the error's doc page. The
|
|
28
|
-
base URL is the
|
|
29
|
-
|
|
28
|
+
base URL is the primary `docs.activegraph.ai` domain (CONTRACT v1.0 #C6,
|
|
29
|
+
v1.0-rc3 amendment); the constant is the single swap point.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
from __future__ import annotations
|
|
@@ -34,10 +34,13 @@ from __future__ import annotations
|
|
|
34
34
|
from typing import Any, ClassVar
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
# CONTRACT v1.0 #C6
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
|
|
37
|
+
# CONTRACT v1.0 #C6 (v1.0-rc3 amendment): primary doc-site domain is
|
|
38
|
+
# docs.activegraph.ai. Until the user-owned Pages enablement and DNS
|
|
39
|
+
# land, the URL renders the same 404 the rc2 user-test surfaced; the
|
|
40
|
+
# v1.1 #9 deploy-verification gate fails until that lands, which is
|
|
41
|
+
# the correct signal. One-line swap point: update this constant and
|
|
42
|
+
# every error message URL and `DOCS_BASE_URL`-derived f-string follows.
|
|
43
|
+
DOCS_BASE_URL = "https://docs.activegraph.ai"
|
|
41
44
|
|
|
42
45
|
|
|
43
46
|
def _indent_continuation(text: str, indent: str = " ") -> str:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""LLM behaviors subpackage. CONTRACT v0.6.
|
|
1
|
+
"""LLM behaviors subpackage. CONTRACT v0.6; OpenAIProvider added v1.0.1 #5.
|
|
2
2
|
|
|
3
3
|
Public surface:
|
|
4
4
|
|
|
@@ -6,6 +6,8 @@ Public surface:
|
|
|
6
6
|
LLMMessage — single role-tagged message
|
|
7
7
|
LLMResponse — what `complete()` returns
|
|
8
8
|
AnthropicProvider — reference implementation
|
|
9
|
+
OpenAIProvider — second concrete provider, surface parity
|
|
10
|
+
with AnthropicProvider (v1.0.1 #5)
|
|
9
11
|
RecordedLLMProvider — fixture-backed provider for tests
|
|
10
12
|
RecordingLLMProvider — wraps another provider, persists responses
|
|
11
13
|
as fixtures (for first-time test seed)
|
|
@@ -17,11 +19,16 @@ Public surface:
|
|
|
17
19
|
LLMBehaviorError — structured failure carrier from @llm_behavior
|
|
18
20
|
wrappers; runtime turns it into
|
|
19
21
|
`behavior.failed` with a `reason`
|
|
22
|
+
parse_structured_response — JSON-extraction-then-Pydantic-validate
|
|
23
|
+
helper shared by every provider that uses
|
|
24
|
+
the framework's instruction-based path
|
|
20
25
|
"""
|
|
21
26
|
|
|
22
27
|
from activegraph.llm.anthropic import AnthropicProvider
|
|
23
28
|
from activegraph.llm.cache import LLMCache
|
|
24
29
|
from activegraph.llm.errors import LLMBehaviorError, MissingProviderError
|
|
30
|
+
from activegraph.llm.openai import OpenAIProvider
|
|
31
|
+
from activegraph.llm.parsing import parse_structured_response
|
|
25
32
|
from activegraph.llm.prompt import (
|
|
26
33
|
AssembledPrompt,
|
|
27
34
|
assemble_prompt,
|
|
@@ -42,10 +49,12 @@ __all__ = [
|
|
|
42
49
|
"LLMProvider",
|
|
43
50
|
"LLMResponse",
|
|
44
51
|
"MissingProviderError",
|
|
52
|
+
"OpenAIProvider",
|
|
45
53
|
"RecordedLLMProvider",
|
|
46
54
|
"RecordingLLMProvider",
|
|
47
55
|
"ToolCall",
|
|
48
56
|
"assemble_prompt",
|
|
57
|
+
"parse_structured_response",
|
|
49
58
|
"schema_to_json",
|
|
50
59
|
"serialize_view",
|
|
51
60
|
]
|
|
@@ -23,12 +23,12 @@ keeps the surface narrow on purpose.
|
|
|
23
23
|
from __future__ import annotations
|
|
24
24
|
|
|
25
25
|
import json
|
|
26
|
-
import re
|
|
27
26
|
import time
|
|
28
27
|
from decimal import Decimal
|
|
29
28
|
from typing import Any, Mapping, Optional
|
|
30
29
|
|
|
31
30
|
from activegraph.llm.errors import LLMBehaviorError
|
|
31
|
+
from activegraph.llm.parsing import parse_structured_response as _parse_structured
|
|
32
32
|
from activegraph.llm.provider import LLMProvider
|
|
33
33
|
from activegraph.llm.types import LLMMessage, LLMResponse, ToolCall
|
|
34
34
|
|
|
@@ -265,57 +265,6 @@ def _message_to_anthropic(m: LLMMessage) -> dict[str, Any]:
|
|
|
265
265
|
return {"role": m.role, "content": m.content}
|
|
266
266
|
|
|
267
267
|
|
|
268
|
-
_FENCED_JSON_RE = re.compile(r"```(?:json)?\s*(\{.*?\}|\[.*?\])\s*```", re.DOTALL)
|
|
269
|
-
_BRACE_RE = re.compile(r"(\{.*\}|\[.*\])", re.DOTALL)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
def _parse_structured(text: str, schema: type) -> Any:
|
|
273
|
-
"""Parse JSON out of an LLM response and validate against `schema`.
|
|
274
|
-
|
|
275
|
-
Strategy: try direct JSON first; on failure, extract a fenced
|
|
276
|
-
```json``` block; on failure, grab the first {...}/[...] span.
|
|
277
|
-
Two distinct failure modes flow back as `LLMBehaviorError`:
|
|
278
|
-
|
|
279
|
-
reason=llm.parse_error — no JSON found / json.loads failed
|
|
280
|
-
reason=llm.schema_violation — JSON found but Pydantic rejected it
|
|
281
|
-
"""
|
|
282
|
-
|
|
283
|
-
candidate = text.strip()
|
|
284
|
-
obj: Any = None
|
|
285
|
-
parse_err: Optional[Exception] = None
|
|
286
|
-
try:
|
|
287
|
-
obj = json.loads(candidate)
|
|
288
|
-
except Exception as e:
|
|
289
|
-
parse_err = e
|
|
290
|
-
if obj is None:
|
|
291
|
-
m = _FENCED_JSON_RE.search(text) or _BRACE_RE.search(text)
|
|
292
|
-
if m:
|
|
293
|
-
try:
|
|
294
|
-
obj = json.loads(m.group(1))
|
|
295
|
-
parse_err = None
|
|
296
|
-
except Exception as e:
|
|
297
|
-
parse_err = e
|
|
298
|
-
if obj is None:
|
|
299
|
-
raise LLMBehaviorError(
|
|
300
|
-
"llm.parse_error",
|
|
301
|
-
f"no JSON found in response: {parse_err}",
|
|
302
|
-
payload_extras={"raw_text": text, "underlying": str(parse_err)},
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
try:
|
|
306
|
-
return schema.model_validate(obj)
|
|
307
|
-
except Exception as e:
|
|
308
|
-
raise LLMBehaviorError(
|
|
309
|
-
"llm.schema_violation",
|
|
310
|
-
f"response did not match schema {schema.__name__}: {e}",
|
|
311
|
-
payload_extras={
|
|
312
|
-
"raw_text": text,
|
|
313
|
-
"schema": schema.__name__,
|
|
314
|
-
"validation_errors": str(e),
|
|
315
|
-
},
|
|
316
|
-
) from e
|
|
317
|
-
|
|
318
|
-
|
|
319
268
|
def _classify_provider_exception(e: Exception) -> str:
|
|
320
269
|
name = type(e).__name__.lower()
|
|
321
270
|
if "ratelimit" in name or "429" in str(e):
|