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.
Files changed (67) hide show
  1. tracegc/__init__.py +18 -0
  2. tracegc/analysis.py +145 -0
  3. tracegc/api.py +832 -0
  4. tracegc/benchmark/cli_runner.py +250 -0
  5. tracegc/benchmark/estimate_cost.py +86 -0
  6. tracegc/benchmark/fixtures/coding_agent_long.json +1306 -0
  7. tracegc/benchmark/fixtures/coding_agent_medium.json +471 -0
  8. tracegc/benchmark/fixtures/coding_agent_short.json +182 -0
  9. tracegc/benchmark/fixtures/customer_support_long.json +1287 -0
  10. tracegc/benchmark/fixtures/customer_support_medium.json +463 -0
  11. tracegc/benchmark/fixtures/customer_support_short.json +169 -0
  12. tracegc/benchmark/fixtures/research_agent_long.json +1287 -0
  13. tracegc/benchmark/fixtures/research_agent_medium.json +463 -0
  14. tracegc/benchmark/fixtures/research_agent_short.json +158 -0
  15. tracegc/benchmark/generate_fixtures.py +550 -0
  16. tracegc/benchmark/methods.py +307 -0
  17. tracegc/benchmark/run_benchmark.py +601 -0
  18. tracegc/benchmark/scoring.py +104 -0
  19. tracegc/benchmark/test_gemini.py +70 -0
  20. tracegc/cli.py +173 -0
  21. tracegc/compactor.py +224 -0
  22. tracegc/dead_branch_sweeper.py +86 -0
  23. tracegc/dedup_engine.py +103 -0
  24. tracegc/events.py +149 -0
  25. tracegc/graph.py +169 -0
  26. tracegc/middleware.py +123 -0
  27. tracegc/override_engine.py +127 -0
  28. tracegc/receipts.py +34 -0
  29. tracegc/retention_policy.py +21 -0
  30. tracegc/semantic.py +373 -0
  31. tracegc/semantic_engine.py +426 -0
  32. tracegc/topo_sampler.py +126 -0
  33. tracegc-0.5.0.dist-info/METADATA +444 -0
  34. tracegc-0.5.0.dist-info/RECORD +67 -0
  35. tracegc-0.5.0.dist-info/WHEEL +5 -0
  36. tracegc-0.5.0.dist-info/entry_points.txt +2 -0
  37. tracegc-0.5.0.dist-info/licenses/LICENSE +201 -0
  38. tracegc-0.5.0.dist-info/top_level.txt +5 -0
  39. tracegc-crewai/build/lib/tracegc_crewai/__init__.py +20 -0
  40. tracegc-crewai/build/lib/tracegc_crewai/adapter.py +137 -0
  41. tracegc-crewai/tests/conftest.py +7 -0
  42. tracegc-crewai/tests/test_adapter.py +127 -0
  43. tracegc-crewai/tracegc_crewai/__init__.py +20 -0
  44. tracegc-crewai/tracegc_crewai/adapter.py +137 -0
  45. tracegc-langgraph/build/lib/tracegc_langgraph/__init__.py +1 -0
  46. tracegc-langgraph/tracegc_langgraph/__init__.py +1 -0
  47. tracegc-mcp/build/lib/tracegc_mcp/__init__.py +6 -0
  48. tracegc-mcp/build/lib/tracegc_mcp/server.py +75 -0
  49. tracegc-mcp/tests/test_mcp_server.py +49 -0
  50. tracegc-mcp/tracegc_mcp/__init__.py +6 -0
  51. tracegc-mcp/tracegc_mcp/server.py +75 -0
  52. tracegc-storage/build/lib/tracegc_storage/__init__.py +7 -0
  53. tracegc-storage/build/lib/tracegc_storage/canonical.py +11 -0
  54. tracegc-storage/build/lib/tracegc_storage/errors.py +29 -0
  55. tracegc-storage/build/lib/tracegc_storage/memory_store.py +219 -0
  56. tracegc-storage/build/lib/tracegc_storage/protocol.py +32 -0
  57. tracegc-storage/build/lib/tracegc_storage/sqlite_store.py +493 -0
  58. tracegc-storage/tests/test_canonical.py +55 -0
  59. tracegc-storage/tests/test_conformance.py +217 -0
  60. tracegc-storage/tests/test_memory_store.py +70 -0
  61. tracegc-storage/tests/test_sqlite_store.py +240 -0
  62. tracegc-storage/tracegc_storage/__init__.py +7 -0
  63. tracegc-storage/tracegc_storage/canonical.py +11 -0
  64. tracegc-storage/tracegc_storage/errors.py +29 -0
  65. tracegc-storage/tracegc_storage/memory_store.py +219 -0
  66. tracegc-storage/tracegc_storage/protocol.py +32 -0
  67. 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