tracegc 0.5.0__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.
- tracegc/__init__.py +18 -0
- tracegc/analysis.py +145 -0
- tracegc/api.py +832 -0
- tracegc/benchmark/cli_runner.py +250 -0
- tracegc/benchmark/estimate_cost.py +86 -0
- tracegc/benchmark/fixtures/coding_agent_long.json +1306 -0
- tracegc/benchmark/fixtures/coding_agent_medium.json +471 -0
- tracegc/benchmark/fixtures/coding_agent_short.json +182 -0
- tracegc/benchmark/fixtures/customer_support_long.json +1287 -0
- tracegc/benchmark/fixtures/customer_support_medium.json +463 -0
- tracegc/benchmark/fixtures/customer_support_short.json +169 -0
- tracegc/benchmark/fixtures/research_agent_long.json +1287 -0
- tracegc/benchmark/fixtures/research_agent_medium.json +463 -0
- tracegc/benchmark/fixtures/research_agent_short.json +158 -0
- tracegc/benchmark/generate_fixtures.py +550 -0
- tracegc/benchmark/methods.py +307 -0
- tracegc/benchmark/run_benchmark.py +601 -0
- tracegc/benchmark/scoring.py +104 -0
- tracegc/benchmark/test_gemini.py +70 -0
- tracegc/cli.py +173 -0
- tracegc/compactor.py +224 -0
- tracegc/dead_branch_sweeper.py +86 -0
- tracegc/dedup_engine.py +103 -0
- tracegc/events.py +149 -0
- tracegc/graph.py +169 -0
- tracegc/middleware.py +123 -0
- tracegc/override_engine.py +127 -0
- tracegc/receipts.py +34 -0
- tracegc/retention_policy.py +21 -0
- tracegc/semantic.py +373 -0
- tracegc/semantic_engine.py +426 -0
- tracegc/topo_sampler.py +126 -0
- tracegc-0.5.0.dist-info/METADATA +444 -0
- tracegc-0.5.0.dist-info/RECORD +67 -0
- tracegc-0.5.0.dist-info/WHEEL +5 -0
- tracegc-0.5.0.dist-info/entry_points.txt +2 -0
- tracegc-0.5.0.dist-info/licenses/LICENSE +201 -0
- tracegc-0.5.0.dist-info/top_level.txt +5 -0
- tracegc-crewai/build/lib/tracegc_crewai/__init__.py +20 -0
- tracegc-crewai/build/lib/tracegc_crewai/adapter.py +137 -0
- tracegc-crewai/tests/conftest.py +7 -0
- tracegc-crewai/tests/test_adapter.py +127 -0
- tracegc-crewai/tracegc_crewai/__init__.py +20 -0
- tracegc-crewai/tracegc_crewai/adapter.py +137 -0
- tracegc-langgraph/build/lib/tracegc_langgraph/__init__.py +1 -0
- tracegc-langgraph/tracegc_langgraph/__init__.py +1 -0
- tracegc-mcp/build/lib/tracegc_mcp/__init__.py +6 -0
- tracegc-mcp/build/lib/tracegc_mcp/server.py +75 -0
- tracegc-mcp/tests/test_mcp_server.py +49 -0
- tracegc-mcp/tracegc_mcp/__init__.py +6 -0
- tracegc-mcp/tracegc_mcp/server.py +75 -0
- tracegc-storage/build/lib/tracegc_storage/__init__.py +7 -0
- tracegc-storage/build/lib/tracegc_storage/canonical.py +11 -0
- tracegc-storage/build/lib/tracegc_storage/errors.py +29 -0
- tracegc-storage/build/lib/tracegc_storage/memory_store.py +219 -0
- tracegc-storage/build/lib/tracegc_storage/protocol.py +32 -0
- tracegc-storage/build/lib/tracegc_storage/sqlite_store.py +493 -0
- tracegc-storage/tests/test_canonical.py +55 -0
- tracegc-storage/tests/test_conformance.py +217 -0
- tracegc-storage/tests/test_memory_store.py +70 -0
- tracegc-storage/tests/test_sqlite_store.py +240 -0
- tracegc-storage/tracegc_storage/__init__.py +7 -0
- tracegc-storage/tracegc_storage/canonical.py +11 -0
- tracegc-storage/tracegc_storage/errors.py +29 -0
- tracegc-storage/tracegc_storage/memory_store.py +219 -0
- tracegc-storage/tracegc_storage/protocol.py +32 -0
- tracegc-storage/tracegc_storage/sqlite_store.py +493 -0
tracegc/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# tracegc/__init__.py
|
|
2
|
+
"""Top level package for the deterministic context compaction library.
|
|
3
|
+
|
|
4
|
+
Exports the public API so users can simply do::
|
|
5
|
+
|
|
6
|
+
from tracegc import StateGraph, compact_events, TraceGCMiddleware
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .graph import StateGraph
|
|
10
|
+
from .compactor import compact_events
|
|
11
|
+
from .middleware import (
|
|
12
|
+
TraceGCMiddleware,
|
|
13
|
+
call_anthropic_with_compaction,
|
|
14
|
+
call_openai_with_compaction,
|
|
15
|
+
)
|
|
16
|
+
from .api import TraceGC, compact, CompactionResult, Receipt
|
|
17
|
+
from .semantic import extract_semantic_events
|
|
18
|
+
from .analysis import analyze_retained_events
|
tracegc/analysis.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# tracegc/analysis.py
|
|
2
|
+
"""Analysis module for querying decision-lifecycle states and information value across trace nodes."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from typing import Dict, List, Set, Optional, Any
|
|
7
|
+
from .graph import StateGraph
|
|
8
|
+
from .retention_policy import is_protected
|
|
9
|
+
from .semantic_engine import update_decision_lifecycle_status
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_active_decisions(
|
|
13
|
+
graph: StateGraph,
|
|
14
|
+
tracked_decision_keys: Optional[Set[str]] = None,
|
|
15
|
+
) -> Dict[str, dict]:
|
|
16
|
+
"""Retrieve active or confirmed decision nodes from the graph.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
graph:
|
|
21
|
+
The ``StateGraph`` to analyze.
|
|
22
|
+
tracked_decision_keys:
|
|
23
|
+
Optional set of decision keys to track.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
Dict[str, dict]
|
|
28
|
+
Mapping of node_id -> event dict for nodes with status in {"ACTIVE", "CONFIRMED"}.
|
|
29
|
+
"""
|
|
30
|
+
statuses = update_decision_lifecycle_status(graph, tracked_decision_keys=tracked_decision_keys)
|
|
31
|
+
active_nodes: Dict[str, dict] = {}
|
|
32
|
+
for node_id, status in statuses.items():
|
|
33
|
+
if status in {"ACTIVE", "CONFIRMED"}:
|
|
34
|
+
active_nodes[node_id] = graph.nodes[node_id]
|
|
35
|
+
return active_nodes
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def analyze_retained_events(
|
|
39
|
+
graph: StateGraph,
|
|
40
|
+
tracked_decision_keys: Optional[Set[str]] = None,
|
|
41
|
+
) -> List[Dict[str, Any]]:
|
|
42
|
+
"""Perform an information value analysis on the trace compaction graph.
|
|
43
|
+
|
|
44
|
+
Reports the semantic meaning, dependency state, and retention rationale
|
|
45
|
+
for each event in the graph.
|
|
46
|
+
"""
|
|
47
|
+
tracked_keys = (
|
|
48
|
+
tracked_decision_keys
|
|
49
|
+
if tracked_decision_keys is not None
|
|
50
|
+
else {"database"}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# 1. Pre-calculate active reference targets
|
|
54
|
+
active_referenced_ids = set()
|
|
55
|
+
for nid, node in graph.nodes.items():
|
|
56
|
+
if nid in graph.pruned:
|
|
57
|
+
continue
|
|
58
|
+
for ref in node.get("ref_to", []):
|
|
59
|
+
active_referenced_ids.add(ref)
|
|
60
|
+
|
|
61
|
+
analysis = []
|
|
62
|
+
|
|
63
|
+
for node_id, event in graph.nodes.items():
|
|
64
|
+
ev_type = event.get("type", "unknown")
|
|
65
|
+
node_status = graph.decision_status.get(node_id, event.get("status"))
|
|
66
|
+
|
|
67
|
+
# Derive semantic meaning
|
|
68
|
+
if ev_type == "set_var":
|
|
69
|
+
meaning = f"variable assignment: {event.get('key')} = {event.get('value')}"
|
|
70
|
+
elif ev_type == "tool_call":
|
|
71
|
+
meaning = f"tool call: {event.get('tool_name')}({event.get('arguments')})"
|
|
72
|
+
elif ev_type == "tool_result":
|
|
73
|
+
meaning = f"tool result for call {event.get('call_id')}"
|
|
74
|
+
elif ev_type == "command_run":
|
|
75
|
+
meaning = f"shell command run: {event.get('command')}"
|
|
76
|
+
elif ev_type == "test_run":
|
|
77
|
+
meaning = f"test suite execution: {event.get('test_names')}"
|
|
78
|
+
elif ev_type == "decision":
|
|
79
|
+
meaning = f"agent decision: {event.get('content')}"
|
|
80
|
+
elif ev_type == "verification":
|
|
81
|
+
meaning = f"verification assertion: {event.get('content')}"
|
|
82
|
+
else:
|
|
83
|
+
meaning = f"{ev_type}: {event.get('content', event.get('message', ''))}"
|
|
84
|
+
|
|
85
|
+
retained = node_id not in graph.pruned
|
|
86
|
+
|
|
87
|
+
# Calculate dependencies (what active nodes reference this event)
|
|
88
|
+
dependents = []
|
|
89
|
+
for nid, node in graph.nodes.items():
|
|
90
|
+
if nid in graph.pruned:
|
|
91
|
+
continue
|
|
92
|
+
if node_id in node.get("ref_to", []):
|
|
93
|
+
dependents.append(nid)
|
|
94
|
+
|
|
95
|
+
# Reason retained or pruned
|
|
96
|
+
if retained:
|
|
97
|
+
if is_protected(event):
|
|
98
|
+
reason_retained = "protected by critical retention policy"
|
|
99
|
+
elif dependents:
|
|
100
|
+
reason_retained = f"referenced by active dependency nodes: {dependents}"
|
|
101
|
+
elif ev_type == "set_var" and event.get("key") in tracked_keys and node_status in {"ACTIVE", "CONFIRMED"}:
|
|
102
|
+
reason_retained = f"current active {event.get('key')} state decision"
|
|
103
|
+
elif ev_type in {"command_run", "test_run"} and event.get("exit_code") == 0:
|
|
104
|
+
reason_retained = "successful execution evidence of current state"
|
|
105
|
+
elif ev_type == "verification" and event.get("passed") is True:
|
|
106
|
+
reason_retained = "passed verification evidence of current state"
|
|
107
|
+
else:
|
|
108
|
+
reason_retained = "neutral active narrative/event context"
|
|
109
|
+
else:
|
|
110
|
+
reason_retained = graph.prune_reasons.get(node_id, "pruned as obsolete override or dead branch")
|
|
111
|
+
|
|
112
|
+
# Potentially removable checks
|
|
113
|
+
potentially_removable = False
|
|
114
|
+
reason_not_removed = "n/a (already pruned)"
|
|
115
|
+
|
|
116
|
+
if retained:
|
|
117
|
+
if ev_type in {"tool_result", "command_run"} and event.get("exit_code") == 0:
|
|
118
|
+
# Successful execution evidence is potentially removable if we only care about state
|
|
119
|
+
potentially_removable = True
|
|
120
|
+
reason_not_removed = "retained as successful execution evidence justifying current state"
|
|
121
|
+
elif ev_type == "tool_call" and event.get("tool_name") in {"view_file", "read_file"}:
|
|
122
|
+
potentially_removable = True
|
|
123
|
+
reason_not_removed = "retained file read (evidence); can be removed if subsequent edits prove it obsolete"
|
|
124
|
+
elif ev_type == "verification" and event.get("passed") is True:
|
|
125
|
+
potentially_removable = True
|
|
126
|
+
reason_not_removed = "retained passed verification result (evidence)"
|
|
127
|
+
elif ev_type == "decision":
|
|
128
|
+
# Intermediate reasoning is potentially removable if fully superseded
|
|
129
|
+
potentially_removable = True
|
|
130
|
+
reason_not_removed = "retained intermediate agent reasoning/conversation"
|
|
131
|
+
else:
|
|
132
|
+
reason_not_removed = "required to define active state configuration/dependencies"
|
|
133
|
+
|
|
134
|
+
analysis.append({
|
|
135
|
+
"event_id": node_id,
|
|
136
|
+
"semantic_meaning": meaning,
|
|
137
|
+
"current_state": node_status or ("ACTIVE" if retained else "PRUNED"),
|
|
138
|
+
"dependencies": dependents,
|
|
139
|
+
"retained": retained,
|
|
140
|
+
"reason_retained": reason_retained,
|
|
141
|
+
"potentially_removable": potentially_removable,
|
|
142
|
+
"reason_not_removed": reason_not_removed
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
return analysis
|