dagc 0.1.0__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.
Files changed (41) hide show
  1. dagc-0.1.0/LICENSE +21 -0
  2. dagc-0.1.0/PKG-INFO +225 -0
  3. dagc-0.1.0/README.md +178 -0
  4. dagc-0.1.0/pyproject.toml +56 -0
  5. dagc-0.1.0/setup.cfg +4 -0
  6. dagc-0.1.0/src/dagc/__init__.py +47 -0
  7. dagc-0.1.0/src/dagc/adapters.py +93 -0
  8. dagc-0.1.0/src/dagc/baselines.py +82 -0
  9. dagc-0.1.0/src/dagc/cli.py +112 -0
  10. dagc-0.1.0/src/dagc/compressor.py +968 -0
  11. dagc-0.1.0/src/dagc/config.py +119 -0
  12. dagc-0.1.0/src/dagc/extraction.py +662 -0
  13. dagc-0.1.0/src/dagc/formats.py +206 -0
  14. dagc-0.1.0/src/dagc/graph.py +263 -0
  15. dagc-0.1.0/src/dagc/schema.py +194 -0
  16. dagc-0.1.0/src/dagc/utils.py +250 -0
  17. dagc-0.1.0/src/dagc.egg-info/PKG-INFO +225 -0
  18. dagc-0.1.0/src/dagc.egg-info/SOURCES.txt +39 -0
  19. dagc-0.1.0/src/dagc.egg-info/dependency_links.txt +1 -0
  20. dagc-0.1.0/src/dagc.egg-info/entry_points.txt +3 -0
  21. dagc-0.1.0/src/dagc.egg-info/requires.txt +36 -0
  22. dagc-0.1.0/src/dagc.egg-info/top_level.txt +2 -0
  23. dagc-0.1.0/src/dagc_eval/__init__.py +42 -0
  24. dagc-0.1.0/src/dagc_eval/adversarial.py +214 -0
  25. dagc-0.1.0/src/dagc_eval/benchmark.py +375 -0
  26. dagc-0.1.0/src/dagc_eval/diagnostics.py +139 -0
  27. dagc-0.1.0/src/dagc_eval/export.py +80 -0
  28. dagc-0.1.0/src/dagc_eval/interfaces.py +73 -0
  29. dagc-0.1.0/src/dagc_eval/leaderboard.py +77 -0
  30. dagc-0.1.0/src/dagc_eval/match.py +238 -0
  31. dagc-0.1.0/src/dagc_eval/normalize.py +23 -0
  32. dagc-0.1.0/src/dagc_eval/reproduce.py +318 -0
  33. dagc-0.1.0/src/dagc_eval/server.py +201 -0
  34. dagc-0.1.0/src/dagc_eval/stats.py +93 -0
  35. dagc-0.1.0/tests/test_adversarial.py +21 -0
  36. dagc-0.1.0/tests/test_artifacts_extraction.py +106 -0
  37. dagc-0.1.0/tests/test_decision_protection.py +117 -0
  38. dagc-0.1.0/tests/test_format_robustness.py +257 -0
  39. dagc-0.1.0/tests/test_optional_adapter_imports.py +33 -0
  40. dagc-0.1.0/tests/test_schema_adapters.py +49 -0
  41. dagc-0.1.0/tests/test_stats.py +89 -0
dagc-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaurya Sawant
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
dagc-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.4
2
+ Name: dagc
3
+ Version: 0.1.0
4
+ Summary: Decision-Anchored Graph Compression for agent/chat traces: preserve decision-critical artifacts with regex, embeddings, and graph algorithms, support varied message formats, and include optional evaluation tools.
5
+ Author: Shaurya Sawant
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Shauryasawant/DAGC-Decision-Anchored-Graph-Compression
8
+ Project-URL: Repository, https://github.com/Shauryasawant/DAGC-Decision-Anchored-Graph-Compression
9
+ Project-URL: Issues, https://github.com/Shauryasawant/DAGC-Decision-Anchored-Graph-Compression/issues
10
+ Keywords: agent,chat,compression,context,llm,memory
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: numpy>=1.22
19
+ Requires-Dist: scipy>=1.10
20
+ Provides-Extra: tiktoken
21
+ Requires-Dist: tiktoken>=0.5; extra == "tiktoken"
22
+ Provides-Extra: sentence-transformers
23
+ Requires-Dist: sentence-transformers>=2.2; extra == "sentence-transformers"
24
+ Provides-Extra: openai
25
+ Requires-Dist: openai>=1.0; extra == "openai"
26
+ Provides-Extra: cohere
27
+ Requires-Dist: cohere>=5.0; extra == "cohere"
28
+ Provides-Extra: anthropic
29
+ Requires-Dist: anthropic>=0.30; extra == "anthropic"
30
+ Provides-Extra: mistralai
31
+ Requires-Dist: mistralai>=1.0; extra == "mistralai"
32
+ Provides-Extra: server
33
+ Requires-Dist: fastapi>=0.111; extra == "server"
34
+ Requires-Dist: httpx>=0.27; extra == "server"
35
+ Requires-Dist: uvicorn>=0.30; extra == "server"
36
+ Provides-Extra: all
37
+ Requires-Dist: tiktoken>=0.5; extra == "all"
38
+ Requires-Dist: sentence-transformers>=2.2; extra == "all"
39
+ Requires-Dist: openai>=1.0; extra == "all"
40
+ Requires-Dist: cohere>=5.0; extra == "all"
41
+ Requires-Dist: anthropic>=0.30; extra == "all"
42
+ Requires-Dist: mistralai>=1.0; extra == "all"
43
+ Requires-Dist: fastapi>=0.111; extra == "all"
44
+ Requires-Dist: httpx>=0.27; extra == "all"
45
+ Requires-Dist: uvicorn>=0.30; extra == "all"
46
+ Dynamic: license-file
47
+
48
+ # DAGC — Decision-Anchored Graph Compression
49
+
50
+ `dagc` shortens agent and chat histories while prioritising the values that
51
+ later decisions depend on: tool arguments, IDs, paths, metrics, and confirmed
52
+ choices. It is designed for applications that need to reduce context size
53
+ without losing the evidence behind an earlier decision.
54
+
55
+ The core package is local-only. It does not make LLM or network calls unless
56
+ you configure an optional embedding or evaluation adapter that does.
57
+
58
+ ## What it includes
59
+
60
+ - Decision-aware message compression with configurable token reduction.
61
+ - Zero-dependency fallback tokenizer and embedder for local use.
62
+ - Optional adapters for `tiktoken`, Sentence Transformers, OpenAI, and Cohere.
63
+ - `compress_any()` for normalising and restoring common message formats.
64
+ - `dagc_eval`, an optional reproducibility and benchmark toolkit.
65
+ - `dagc-server`, an optional HTTP proxy for compressing message arrays before
66
+ forwarding a request to an upstream LLM API.
67
+
68
+ ## Install
69
+
70
+ Install the package from this repository while developing:
71
+
72
+ ```bash
73
+ pip install -e .
74
+ ```
75
+
76
+ After publishing, install it from PyPI:
77
+
78
+ ```bash
79
+ pip install dagc
80
+ ```
81
+
82
+ The core package only requires NumPy and SciPy. For model-aligned token counts
83
+ and semantic embeddings, install the relevant extras:
84
+
85
+ ```bash
86
+ pip install "dagc[tiktoken,sentence-transformers]"
87
+ ```
88
+
89
+ ## Quick start
90
+
91
+ ```python
92
+ from dagc import compress
93
+
94
+ compressed = compress(messages, target_reduction=0.85)
95
+ response = client.chat.completions.create(
96
+ model="gpt-4.1",
97
+ messages=compressed,
98
+ )
99
+ ```
100
+
101
+ `compress()` accepts a list of message dictionaries and returns a new list.
102
+ The returned messages include `_orig_idx`, which records their position in the
103
+ original trace.
104
+
105
+ For arbitrary message shapes, use `compress_any()` instead. It normalises
106
+ common message and envelope formats, compresses them, then restores the
107
+ original structure by default:
108
+
109
+ ```python
110
+ from dagc import compress_any
111
+
112
+ compressed_payload = compress_any(request_payload, target_reduction=0.85)
113
+ ```
114
+
115
+ ## Configure production adapters
116
+
117
+ The default adapters are useful for getting started, but a tokenizer and
118
+ embedding model matched to your application usually produce better results.
119
+
120
+ ```python
121
+ import dagc
122
+ from dagc.adapters import SentenceTransformerEmbedder, TiktokenTokenizer
123
+
124
+ dagc.configure(
125
+ tokenizer=TiktokenTokenizer("cl100k_base"),
126
+ embedder=SentenceTransformerEmbedder("all-MiniLM-L6-v2"),
127
+ )
128
+ ```
129
+
130
+ See [examples/byok_openai_embeddings.py](examples/byok_openai_embeddings.py)
131
+ for a Mistral embedding example and [examples/langgraph_style_node.py](examples/langgraph_style_node.py)
132
+ for a workflow-node example.
133
+
134
+ ## Tuning
135
+
136
+ ```python
137
+ from dagc import DAGCConfig, compress
138
+
139
+ cfg = DAGCConfig(TARGET_REDUCTION=0.90, KEEP_LAST_K=3)
140
+ compressed = compress(messages, cfg=cfg)
141
+
142
+ # Equivalent inline overrides:
143
+ compressed = compress(messages, TARGET_REDUCTION=0.90, KEEP_LAST_K=3)
144
+ ```
145
+
146
+ | Field | Default | Purpose |
147
+ | --- | ---: | --- |
148
+ | `TARGET_REDUCTION` | `0.87` | Requested fraction of tokens to remove. |
149
+ | `KEEP_LAST_K` | `1` | Retains the latest messages as protected context. |
150
+ | `PROTECT_TOOL_CALLS` | `True` | Protects tool-call messages during selection. |
151
+ | `PROTECT_JUDGMENTS` | `True` | Protects assistant judgments and confirmations. |
152
+ | `USE_CAUSAL_SKELETON` | `True` | Uses the causal message graph during selection. |
153
+
154
+ Protected messages may still have their content shortened when
155
+ `COMPRESS_PROTECTED=True` (the default). Use the settings in `DAGCConfig` to
156
+ adjust those caps for your application.
157
+
158
+ ## How compression works
159
+
160
+ 1. The extractor identifies tool calls, decisions, and confirmations, then
161
+ collects the IDs, paths, values, and rationale associated with them.
162
+ 2. The first selection phase reserves budget for decision-critical evidence.
163
+ 3. The remaining budget is filled with causally relevant, task-relevant
164
+ sentences while reducing redundant context.
165
+ 4. A final pass checks for missing critical values and adds available evidence
166
+ back when needed.
167
+
168
+ This is heuristic software, so evaluate it with your own traces before relying
169
+ on a specific reduction target in production.
170
+
171
+ ## Evaluate a trace
172
+
173
+ `dagc_eval` measures whether a compressed trace still has enough information
174
+ to reproduce the decisions in the original trace.
175
+
176
+ ```python
177
+ from dagc_eval import TASKS, compute_drr, generate_trace
178
+
179
+ trace = generate_trace(TASKS[0])
180
+ result = compute_drr(trace)
181
+ print(result["DRR_soft"], result["RCI"])
182
+ ```
183
+
184
+ The default evaluation path is deterministic and runs offline. You can also
185
+ pass a BYOK client for reconstruction attempts that need an LLM:
186
+
187
+ ```python
188
+ import openai
189
+ from dagc_eval import compute_drr
190
+ from dagc_eval.interfaces import OpenAIChatClient
191
+
192
+ llm = OpenAIChatClient(openai.OpenAI())
193
+ result = compute_drr(trace, llm=llm)
194
+ ```
195
+
196
+ The command-line interface exposes the same workflows:
197
+
198
+ ```bash
199
+ dagc compress trace.json --target-reduction 0.85 -o compressed.json
200
+ dagc evaluate trace.json -o report.md
201
+ dagc benchmark --n-traces 3 -o benchmark.json
202
+ ```
203
+
204
+ ## Optional proxy
205
+
206
+ Install the server extra to run the wire-compatible compression proxy:
207
+
208
+ ```bash
209
+ pip install "dagc[server]"
210
+ export UPSTREAM_BASE_URL="https://your-llm-provider.example"
211
+ dagc-server
212
+ ```
213
+
214
+ The proxy looks for a `messages`, `trace`, `conversation`, or `turns` array in
215
+ the request body. If compression fails, it forwards the original request
216
+ unchanged.
217
+
218
+ ## Project layout
219
+
220
+ ```text
221
+ src/dagc/ Core compression, formats, adapters, and graph utilities
222
+ src/dagc_eval/ Evaluation, benchmarks, diagnostics, exports, and proxy server
223
+ examples/ Runnable integration examples
224
+ tests/ Unit and format-robustness tests
225
+ ```
dagc-0.1.0/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # DAGC — Decision-Anchored Graph Compression
2
+
3
+ `dagc` shortens agent and chat histories while prioritising the values that
4
+ later decisions depend on: tool arguments, IDs, paths, metrics, and confirmed
5
+ choices. It is designed for applications that need to reduce context size
6
+ without losing the evidence behind an earlier decision.
7
+
8
+ The core package is local-only. It does not make LLM or network calls unless
9
+ you configure an optional embedding or evaluation adapter that does.
10
+
11
+ ## What it includes
12
+
13
+ - Decision-aware message compression with configurable token reduction.
14
+ - Zero-dependency fallback tokenizer and embedder for local use.
15
+ - Optional adapters for `tiktoken`, Sentence Transformers, OpenAI, and Cohere.
16
+ - `compress_any()` for normalising and restoring common message formats.
17
+ - `dagc_eval`, an optional reproducibility and benchmark toolkit.
18
+ - `dagc-server`, an optional HTTP proxy for compressing message arrays before
19
+ forwarding a request to an upstream LLM API.
20
+
21
+ ## Install
22
+
23
+ Install the package from this repository while developing:
24
+
25
+ ```bash
26
+ pip install -e .
27
+ ```
28
+
29
+ After publishing, install it from PyPI:
30
+
31
+ ```bash
32
+ pip install dagc
33
+ ```
34
+
35
+ The core package only requires NumPy and SciPy. For model-aligned token counts
36
+ and semantic embeddings, install the relevant extras:
37
+
38
+ ```bash
39
+ pip install "dagc[tiktoken,sentence-transformers]"
40
+ ```
41
+
42
+ ## Quick start
43
+
44
+ ```python
45
+ from dagc import compress
46
+
47
+ compressed = compress(messages, target_reduction=0.85)
48
+ response = client.chat.completions.create(
49
+ model="gpt-4.1",
50
+ messages=compressed,
51
+ )
52
+ ```
53
+
54
+ `compress()` accepts a list of message dictionaries and returns a new list.
55
+ The returned messages include `_orig_idx`, which records their position in the
56
+ original trace.
57
+
58
+ For arbitrary message shapes, use `compress_any()` instead. It normalises
59
+ common message and envelope formats, compresses them, then restores the
60
+ original structure by default:
61
+
62
+ ```python
63
+ from dagc import compress_any
64
+
65
+ compressed_payload = compress_any(request_payload, target_reduction=0.85)
66
+ ```
67
+
68
+ ## Configure production adapters
69
+
70
+ The default adapters are useful for getting started, but a tokenizer and
71
+ embedding model matched to your application usually produce better results.
72
+
73
+ ```python
74
+ import dagc
75
+ from dagc.adapters import SentenceTransformerEmbedder, TiktokenTokenizer
76
+
77
+ dagc.configure(
78
+ tokenizer=TiktokenTokenizer("cl100k_base"),
79
+ embedder=SentenceTransformerEmbedder("all-MiniLM-L6-v2"),
80
+ )
81
+ ```
82
+
83
+ See [examples/byok_openai_embeddings.py](examples/byok_openai_embeddings.py)
84
+ for a Mistral embedding example and [examples/langgraph_style_node.py](examples/langgraph_style_node.py)
85
+ for a workflow-node example.
86
+
87
+ ## Tuning
88
+
89
+ ```python
90
+ from dagc import DAGCConfig, compress
91
+
92
+ cfg = DAGCConfig(TARGET_REDUCTION=0.90, KEEP_LAST_K=3)
93
+ compressed = compress(messages, cfg=cfg)
94
+
95
+ # Equivalent inline overrides:
96
+ compressed = compress(messages, TARGET_REDUCTION=0.90, KEEP_LAST_K=3)
97
+ ```
98
+
99
+ | Field | Default | Purpose |
100
+ | --- | ---: | --- |
101
+ | `TARGET_REDUCTION` | `0.87` | Requested fraction of tokens to remove. |
102
+ | `KEEP_LAST_K` | `1` | Retains the latest messages as protected context. |
103
+ | `PROTECT_TOOL_CALLS` | `True` | Protects tool-call messages during selection. |
104
+ | `PROTECT_JUDGMENTS` | `True` | Protects assistant judgments and confirmations. |
105
+ | `USE_CAUSAL_SKELETON` | `True` | Uses the causal message graph during selection. |
106
+
107
+ Protected messages may still have their content shortened when
108
+ `COMPRESS_PROTECTED=True` (the default). Use the settings in `DAGCConfig` to
109
+ adjust those caps for your application.
110
+
111
+ ## How compression works
112
+
113
+ 1. The extractor identifies tool calls, decisions, and confirmations, then
114
+ collects the IDs, paths, values, and rationale associated with them.
115
+ 2. The first selection phase reserves budget for decision-critical evidence.
116
+ 3. The remaining budget is filled with causally relevant, task-relevant
117
+ sentences while reducing redundant context.
118
+ 4. A final pass checks for missing critical values and adds available evidence
119
+ back when needed.
120
+
121
+ This is heuristic software, so evaluate it with your own traces before relying
122
+ on a specific reduction target in production.
123
+
124
+ ## Evaluate a trace
125
+
126
+ `dagc_eval` measures whether a compressed trace still has enough information
127
+ to reproduce the decisions in the original trace.
128
+
129
+ ```python
130
+ from dagc_eval import TASKS, compute_drr, generate_trace
131
+
132
+ trace = generate_trace(TASKS[0])
133
+ result = compute_drr(trace)
134
+ print(result["DRR_soft"], result["RCI"])
135
+ ```
136
+
137
+ The default evaluation path is deterministic and runs offline. You can also
138
+ pass a BYOK client for reconstruction attempts that need an LLM:
139
+
140
+ ```python
141
+ import openai
142
+ from dagc_eval import compute_drr
143
+ from dagc_eval.interfaces import OpenAIChatClient
144
+
145
+ llm = OpenAIChatClient(openai.OpenAI())
146
+ result = compute_drr(trace, llm=llm)
147
+ ```
148
+
149
+ The command-line interface exposes the same workflows:
150
+
151
+ ```bash
152
+ dagc compress trace.json --target-reduction 0.85 -o compressed.json
153
+ dagc evaluate trace.json -o report.md
154
+ dagc benchmark --n-traces 3 -o benchmark.json
155
+ ```
156
+
157
+ ## Optional proxy
158
+
159
+ Install the server extra to run the wire-compatible compression proxy:
160
+
161
+ ```bash
162
+ pip install "dagc[server]"
163
+ export UPSTREAM_BASE_URL="https://your-llm-provider.example"
164
+ dagc-server
165
+ ```
166
+
167
+ The proxy looks for a `messages`, `trace`, `conversation`, or `turns` array in
168
+ the request body. If compression fails, it forwards the original request
169
+ unchanged.
170
+
171
+ ## Project layout
172
+
173
+ ```text
174
+ src/dagc/ Core compression, formats, adapters, and graph utilities
175
+ src/dagc_eval/ Evaluation, benchmarks, diagnostics, exports, and proxy server
176
+ examples/ Runnable integration examples
177
+ tests/ Unit and format-robustness tests
178
+ ```
@@ -0,0 +1,56 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dagc"
7
+ version = "0.1.0"
8
+ description = "Decision-Anchored Graph Compression for agent/chat traces: preserve decision-critical artifacts with regex, embeddings, and graph algorithms, support varied message formats, and include optional evaluation tools."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ authors = [{ name = "Shaurya Sawant" }]
12
+ license = "MIT"
13
+ license-files = ["LICENSE"]
14
+ keywords = ["agent", "chat", "compression", "context", "llm", "memory"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ ]
21
+ dependencies = [
22
+ "numpy>=1.22",
23
+ "scipy>=1.10",
24
+ ]
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/Shauryasawant/DAGC-Decision-Anchored-Graph-Compression"
28
+ Repository = "https://github.com/Shauryasawant/DAGC-Decision-Anchored-Graph-Compression"
29
+ Issues = "https://github.com/Shauryasawant/DAGC-Decision-Anchored-Graph-Compression/issues"
30
+
31
+ [project.optional-dependencies]
32
+ # Optional tokenizer and embedding adapters.
33
+ tiktoken = ["tiktoken>=0.5"]
34
+ sentence-transformers = ["sentence-transformers>=2.2"]
35
+ openai = ["openai>=1.0"]
36
+ cohere = ["cohere>=5.0"]
37
+
38
+ # Optional SDKs for dagc_eval adapters.
39
+ anthropic = ["anthropic>=0.30"]
40
+ mistralai = ["mistralai>=1.0"]
41
+
42
+ # Optional dependencies for dagc-server.
43
+ server = ["fastapi>=0.111", "httpx>=0.27", "uvicorn>=0.30"]
44
+
45
+ # All optional dependencies.
46
+ all = ["tiktoken>=0.5", "sentence-transformers>=2.2", "openai>=1.0", "cohere>=5.0", "anthropic>=0.30", "mistralai>=1.0", "fastapi>=0.111", "httpx>=0.27", "uvicorn>=0.30"]
47
+
48
+ [tool.setuptools.packages.find]
49
+ where = ["src"]
50
+
51
+ [project.scripts]
52
+ dagc = "dagc.cli:main"
53
+ dagc-server = "dagc_eval.server:run"
54
+
55
+ [tool.pytest.ini_options]
56
+ pythonpath = ["src"]
dagc-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,47 @@
1
+ """
2
+ dagc — Decision-Anchored Graph Compression.
3
+
4
+ Compress long agent/chat message histories while guaranteeing that every
5
+ artifact a decision depends on (tool-call arguments, confirmed IDs, cited
6
+ metrics) survives compression. Zero required dependencies, zero LLM calls.
7
+
8
+ from dagc import compress
9
+ compressed = compress(messages, target_reduction=0.85)
10
+ response = client.chat.completions.create(model="gpt-4", messages=compressed)
11
+
12
+ Bring your own tokenizer/embedder for production-grade quality:
13
+
14
+ import dagc
15
+ from dagc.adapters import TiktokenTokenizer, SentenceTransformerEmbedder
16
+ dagc.configure(
17
+ tokenizer=TiktokenTokenizer("cl100k_base"),
18
+ embedder=SentenceTransformerEmbedder("all-MiniLM-L6-v2"),
19
+ )
20
+
21
+ """
22
+ from .compressor import compress, compress_any, compress_dagc, DAGCConfig, DAGC_CFG
23
+ from .extraction import extract_decisions
24
+ from .graph import (
25
+ build_dependency_graph, attach_dependencies, compute_rci, compute_chain_rci,
26
+ CausalMessageGraph, CausalGraphConfig, SpectralCompressor,
27
+ )
28
+ from .config import configure, Runtime, Tokenizer, Embedder, runtime
29
+ from .formats import (
30
+ normalize_message, normalize_trace,
31
+ denormalize_message, denormalize_trace,
32
+ register_adapter as register_format_adapter,
33
+ )
34
+ from .schema import register_adapter, to_dagc_format
35
+
36
+ __version__ = "0.1.0"
37
+
38
+ __all__ = [
39
+ "compress", "compress_any", "compress_dagc", "DAGCConfig", "DAGC_CFG",
40
+ "extract_decisions",
41
+ "build_dependency_graph", "attach_dependencies", "compute_rci", "compute_chain_rci",
42
+ "CausalMessageGraph", "CausalGraphConfig", "SpectralCompressor",
43
+ "configure", "Runtime", "Tokenizer", "Embedder", "runtime",
44
+ "normalize_message", "normalize_trace",
45
+ "denormalize_message", "denormalize_trace",
46
+ "register_adapter", "register_format_adapter", "to_dagc_format",
47
+ ]
@@ -0,0 +1,93 @@
1
+ """
2
+ Optional, real-quality Tokenizer/Embedder adapters. Each is lazily
3
+ imported so that importing `dagc.adapters` never requires having every
4
+ vendor SDK installed -- only the one you actually instantiate.
5
+
6
+ Install what you need:
7
+ pip install dagc[tiktoken]
8
+ pip install dagc[sentence-transformers]
9
+ pip install dagc[openai]
10
+
11
+ Or write your own -- any object with .encode()/.decode() (Tokenizer) or
12
+ .encode() -> np.ndarray (Embedder) works, see dagc.config.Tokenizer /
13
+ dagc.config.Embedder for the exact protocol.
14
+ """
15
+ from __future__ import annotations
16
+ from typing import List
17
+ import numpy as np
18
+
19
+
20
+ class TiktokenTokenizer:
21
+ """Real BPE token counts via OpenAI's tiktoken. pip install tiktoken."""
22
+ def __init__(self, encoding_name: str = "cl100k_base"):
23
+ try:
24
+ import tiktoken
25
+ except ImportError as e:
26
+ raise ImportError(
27
+ "TiktokenTokenizer needs tiktoken. Install it with "
28
+ "pip install -e '.[tiktoken]'"
29
+ ) from e
30
+ self._enc = tiktoken.get_encoding(encoding_name)
31
+
32
+ def encode(self, text: str) -> List[int]:
33
+ return self._enc.encode(str(text))
34
+
35
+ def decode(self, tokens: List[int]) -> str:
36
+ return self._enc.decode(tokens)
37
+
38
+
39
+ class SentenceTransformerEmbedder:
40
+ """Local, free, good-quality embeddings. pip install sentence-transformers."""
41
+ def __init__(self, model_name: str = "all-MiniLM-L6-v2"):
42
+ try:
43
+ from sentence_transformers import SentenceTransformer
44
+ except ImportError as e:
45
+ raise ImportError(
46
+ "SentenceTransformerEmbedder needs sentence-transformers. "
47
+ "Install it with pip install -e '.[sentence-transformers]'"
48
+ ) from e
49
+ self._model = SentenceTransformer(model_name)
50
+
51
+ def encode(self, texts: List[str], normalize_embeddings: bool = False) -> np.ndarray:
52
+ return np.asarray(
53
+ self._model.encode(list(texts), normalize_embeddings=normalize_embeddings)
54
+ )
55
+
56
+
57
+ class OpenAIEmbedder:
58
+ """
59
+ BYOK wrapper around any OpenAI-compatible embeddings endpoint.
60
+ Pass your own already-configured client (openai.OpenAI(...)) --
61
+ dagc never sees or stores your API key.
62
+ """
63
+ def __init__(self, client, model: str = "text-embedding-3-small"):
64
+ self._client = client
65
+ self._model = model
66
+
67
+ def encode(self, texts: List[str], normalize_embeddings: bool = False) -> np.ndarray:
68
+ resp = self._client.embeddings.create(model=self._model, input=list(texts))
69
+ vecs = np.array([d.embedding for d in resp.data], dtype=np.float32)
70
+ if normalize_embeddings:
71
+ norms = np.linalg.norm(vecs, axis=1, keepdims=True)
72
+ norms[norms == 0] = 1.0
73
+ vecs = vecs / norms
74
+ return vecs
75
+
76
+
77
+ class CohereEmbedder:
78
+ """BYOK wrapper around a Cohere client (cohere.Client(...))."""
79
+ def __init__(self, client, model: str = "embed-english-v3.0",
80
+ input_type: str = "search_document"):
81
+ self._client = client
82
+ self._model = model
83
+ self._input_type = input_type
84
+
85
+ def encode(self, texts: List[str], normalize_embeddings: bool = False) -> np.ndarray:
86
+ resp = self._client.embed(texts=list(texts), model=self._model,
87
+ input_type=self._input_type)
88
+ vecs = np.array(resp.embeddings, dtype=np.float32)
89
+ if normalize_embeddings:
90
+ norms = np.linalg.norm(vecs, axis=1, keepdims=True)
91
+ norms[norms == 0] = 1.0
92
+ vecs = vecs / norms
93
+ return vecs