continuum-toolkit 1.0.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.
- cli/__init__.py +12 -0
- cli/main.py +415 -0
- confidence/__init__.py +13 -0
- confidence/calculator.py +308 -0
- confidence/models.py +40 -0
- context/__init__.py +17 -0
- context/models.py +108 -0
- context/pruner.py +228 -0
- context/selector.py +193 -0
- continuum_toolkit-1.0.0.dist-info/METADATA +511 -0
- continuum_toolkit-1.0.0.dist-info/RECORD +72 -0
- continuum_toolkit-1.0.0.dist-info/WHEEL +5 -0
- continuum_toolkit-1.0.0.dist-info/entry_points.txt +2 -0
- continuum_toolkit-1.0.0.dist-info/licenses/LICENSE +21 -0
- continuum_toolkit-1.0.0.dist-info/top_level.txt +13 -0
- contradictions/__init__.py +19 -0
- contradictions/detector.py +442 -0
- contradictions/models.py +75 -0
- core/__init__.py +97 -0
- core/enums.py +130 -0
- core/evidence.py +117 -0
- core/interfaces.py +209 -0
- core/schema.py +391 -0
- core/serializer.py +84 -0
- core/state_models.py +530 -0
- daemon/__init__.py +12 -0
- daemon/service.py +170 -0
- extractors/__init__.py +51 -0
- extractors/base.py +117 -0
- extractors/config/parsers.py +288 -0
- extractors/config/secret_sanitizer.py +91 -0
- extractors/config_extractor.py +172 -0
- extractors/conversation/analyzers.py +193 -0
- extractors/conversation/models.py +148 -0
- extractors/conversation_extractor.py +166 -0
- extractors/git_extractor.py +305 -0
- extractors/parsers/base.py +91 -0
- extractors/parsers/comment_parser.py +51 -0
- extractors/parsers/js_ts_parser.py +171 -0
- extractors/parsers/python_parser.py +180 -0
- extractors/verification/runners.py +278 -0
- extractors/verification_extractor.py +263 -0
- extractors/workspace_extractor.py +221 -0
- graph/__init__.py +24 -0
- graph/diff.py +109 -0
- graph/manager.py +473 -0
- graph/models.py +62 -0
- graph/propagator.py +194 -0
- graph/query.py +86 -0
- graph/snapshot.py +85 -0
- handoff/__init__.py +28 -0
- handoff/adapters/__init__.py +45 -0
- handoff/adapters/base.py +90 -0
- handoff/adapters/claude_adapter.py +176 -0
- handoff/adapters/codex_gpt_adapter.py +151 -0
- handoff/adapters/gemini_adapter.py +151 -0
- handoff/adapters/local_model_adapter.py +130 -0
- handoff/models.py +88 -0
- handoff/packager.py +288 -0
- pipeline/__init__.py +9 -0
- pipeline/orchestrator.py +260 -0
- resolution/__init__.py +15 -0
- resolution/resolver.py +311 -0
- storage/__init__.py +18 -0
- storage/hooks.py +125 -0
- storage/manager.py +127 -0
- storage/models.py +39 -0
- storage/recovery.py +98 -0
- watcher/__init__.py +17 -0
- watcher/detector.py +136 -0
- watcher/models.py +62 -0
- watcher/updater.py +163 -0
handoff/models.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Handoff Models
|
|
3
|
+
==================================
|
|
4
|
+
Milestone 6 - Phase 14: Universal Handoff Package Generation.
|
|
5
|
+
Encapsulates standard vendor-neutral handoff packages and disk persistence.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field, asdict
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Dict, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class HandoffPackage:
|
|
18
|
+
"""
|
|
19
|
+
Standard vendor-neutral Continuum Handoff Package.
|
|
20
|
+
Contains:
|
|
21
|
+
- project_state_json: machine-readable canonical state JSON string
|
|
22
|
+
- project_context_md: high-level verified architectural context Markdown
|
|
23
|
+
- handoff_md: focused continuation document for the next AI agent
|
|
24
|
+
- evidence_files: map of relative filenames to content strings in evidence/
|
|
25
|
+
"""
|
|
26
|
+
project_id: str
|
|
27
|
+
package_timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
|
|
28
|
+
project_state_json: str = ""
|
|
29
|
+
project_context_md: str = ""
|
|
30
|
+
handoff_md: str = ""
|
|
31
|
+
evidence_files: Dict[str, str] = field(default_factory=dict)
|
|
32
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
33
|
+
|
|
34
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
35
|
+
return {
|
|
36
|
+
"project_id": self.project_id,
|
|
37
|
+
"package_timestamp": self.package_timestamp,
|
|
38
|
+
"project_state_json": self.project_state_json,
|
|
39
|
+
"project_context_md": self.project_context_md,
|
|
40
|
+
"handoff_md": self.handoff_md,
|
|
41
|
+
"evidence_files": self.evidence_files,
|
|
42
|
+
"metadata": self.metadata
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
def save_to_directory(self, output_dir: str) -> Dict[str, str]:
|
|
46
|
+
"""
|
|
47
|
+
Atomically saves the handoff package to output_dir with the standard structure:
|
|
48
|
+
- <output_dir>/project-state.json
|
|
49
|
+
- <output_dir>/project-context.md
|
|
50
|
+
- <output_dir>/handoff.md
|
|
51
|
+
- <output_dir>/evidence/<evidence_files>
|
|
52
|
+
|
|
53
|
+
Returns a dictionary mapping logical keys to their written filepaths.
|
|
54
|
+
"""
|
|
55
|
+
base_path = Path(output_dir)
|
|
56
|
+
base_path.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
evidence_dir = base_path / "evidence"
|
|
58
|
+
evidence_dir.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
|
|
60
|
+
written_paths: Dict[str, str] = {}
|
|
61
|
+
|
|
62
|
+
# 1. project-state.json
|
|
63
|
+
state_file = base_path / "project-state.json"
|
|
64
|
+
with open(state_file, "w", encoding="utf-8") as f:
|
|
65
|
+
f.write(self.project_state_json)
|
|
66
|
+
written_paths["project-state.json"] = str(state_file.resolve())
|
|
67
|
+
|
|
68
|
+
# 2. project-context.md
|
|
69
|
+
context_file = base_path / "project-context.md"
|
|
70
|
+
with open(context_file, "w", encoding="utf-8") as f:
|
|
71
|
+
f.write(self.project_context_md)
|
|
72
|
+
written_paths["project-context.md"] = str(context_file.resolve())
|
|
73
|
+
|
|
74
|
+
# 3. handoff.md
|
|
75
|
+
handoff_file = base_path / "handoff.md"
|
|
76
|
+
with open(handoff_file, "w", encoding="utf-8") as f:
|
|
77
|
+
f.write(self.handoff_md)
|
|
78
|
+
written_paths["handoff.md"] = str(handoff_file.resolve())
|
|
79
|
+
|
|
80
|
+
# 4. evidence files
|
|
81
|
+
for rel_filename, content in self.evidence_files.items():
|
|
82
|
+
ev_file = evidence_dir / rel_filename
|
|
83
|
+
ev_file.parent.mkdir(parents=True, exist_ok=True)
|
|
84
|
+
with open(ev_file, "w", encoding="utf-8") as f:
|
|
85
|
+
f.write(content)
|
|
86
|
+
written_paths[f"evidence/{rel_filename}"] = str(ev_file.resolve())
|
|
87
|
+
|
|
88
|
+
return written_paths
|
handoff/packager.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Universal Handoff Package Generator
|
|
3
|
+
========================================================
|
|
4
|
+
Milestone 6 - Phase 14: Universal Handoff Package Generation.
|
|
5
|
+
Generates standard vendor-neutral Continuum Handoff Packages that strictly
|
|
6
|
+
distinguish verified ground truth from conversational claims, report discrepancies,
|
|
7
|
+
blockers, confidence, and actionable next steps.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
import json
|
|
12
|
+
from typing import Any, Dict, List, Optional
|
|
13
|
+
|
|
14
|
+
from core.enums import NodeType, Status
|
|
15
|
+
from core.serializer import CanonicalStateSerializer
|
|
16
|
+
from core.state_models import (
|
|
17
|
+
CanonicalProjectState,
|
|
18
|
+
ContradictionRecord,
|
|
19
|
+
GraphNode,
|
|
20
|
+
ProjectState,
|
|
21
|
+
ConversationalState,
|
|
22
|
+
AgentExecutionState,
|
|
23
|
+
)
|
|
24
|
+
from context.models import TaskContext
|
|
25
|
+
from handoff.models import HandoffPackage
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class UniversalHandoffPackager:
|
|
29
|
+
"""
|
|
30
|
+
Constructs vendor-neutral Continuum handoff packages containing:
|
|
31
|
+
- project-state.json
|
|
32
|
+
- project-context.md
|
|
33
|
+
- handoff.md
|
|
34
|
+
- evidence/ directory artifacts
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
def generate_package(
|
|
41
|
+
self,
|
|
42
|
+
canonical_state: CanonicalProjectState,
|
|
43
|
+
task_context: Optional[TaskContext] = None
|
|
44
|
+
) -> HandoffPackage:
|
|
45
|
+
"""
|
|
46
|
+
Synthesizes the complete handoff package from a CanonicalProjectState and
|
|
47
|
+
optional focused TaskContext.
|
|
48
|
+
"""
|
|
49
|
+
# 1. Generate project-state.json (strict canonical schema)
|
|
50
|
+
project_state_json = CanonicalStateSerializer.to_json(canonical_state, indent=2)
|
|
51
|
+
|
|
52
|
+
# 2. Generate project-context.md (high-level verified architectural narrative)
|
|
53
|
+
project_context_md = self._generate_project_context_md(canonical_state)
|
|
54
|
+
|
|
55
|
+
# 3. Generate handoff.md (focused continuation briefing for the next agent)
|
|
56
|
+
handoff_md = self._generate_handoff_md(canonical_state, task_context)
|
|
57
|
+
|
|
58
|
+
# 4. Generate evidence/ directory artifacts
|
|
59
|
+
evidence_files = self._generate_evidence_artifacts(canonical_state)
|
|
60
|
+
|
|
61
|
+
metadata = {
|
|
62
|
+
"schema_version": canonical_state.schema_version,
|
|
63
|
+
"total_nodes": len(canonical_state.graph_nodes),
|
|
64
|
+
"total_edges": len(canonical_state.graph_edges),
|
|
65
|
+
"total_evidence": len(canonical_state.evidence_pool),
|
|
66
|
+
"contradiction_count": len(canonical_state.contradictions),
|
|
67
|
+
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return HandoffPackage(
|
|
71
|
+
project_id=canonical_state.project_id,
|
|
72
|
+
package_timestamp=datetime.now(timezone.utc).isoformat(),
|
|
73
|
+
project_state_json=project_state_json,
|
|
74
|
+
project_context_md=project_context_md,
|
|
75
|
+
handoff_md=handoff_md,
|
|
76
|
+
evidence_files=evidence_files,
|
|
77
|
+
metadata=metadata
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def _generate_project_context_md(self, state: CanonicalProjectState) -> str:
|
|
81
|
+
"""
|
|
82
|
+
Generates project-context.md: High-level architectural briefing of verified reality.
|
|
83
|
+
"""
|
|
84
|
+
p_state = state.project_state
|
|
85
|
+
c_state = state.conversational_state
|
|
86
|
+
|
|
87
|
+
lines = [
|
|
88
|
+
f"# Project Continuum — Verified Project Context",
|
|
89
|
+
f"**Project ID:** `{state.project_id}` | **Schema:** `{state.schema_version}`",
|
|
90
|
+
f"**Last Scanned:** `{p_state.last_scanned_at}`",
|
|
91
|
+
"",
|
|
92
|
+
"## 1. Physical Workspace Reality",
|
|
93
|
+
f"- **Root Path:** `{p_state.root_path}`",
|
|
94
|
+
f"- **Detected Languages:** {', '.join(p_state.detected_languages) if p_state.detected_languages else 'None detected'}",
|
|
95
|
+
f"- **Source Files Tracked:** {len(p_state.files)} file(s)",
|
|
96
|
+
f"- **AST Symbols Extracted:** {len(p_state.symbols)} symbol(s)",
|
|
97
|
+
f"- **Build Status:** `[{p_state.build_status.value}]`",
|
|
98
|
+
"",
|
|
99
|
+
"### Git State",
|
|
100
|
+
f"- **Repository:** {'Yes' if p_state.git_state.is_repo else 'No'}",
|
|
101
|
+
f"- **Active Branch:** `{p_state.git_state.branch or 'N/A'}`",
|
|
102
|
+
f"- **Head Commit:** `{p_state.git_state.head_commit or 'N/A'}`",
|
|
103
|
+
f"- **Working Tree Dirty:** {'Yes (Uncommitted Changes)' if p_state.git_state.is_dirty else 'Clean'}",
|
|
104
|
+
f"- **Staged Files:** {len(p_state.git_state.staged_files)}",
|
|
105
|
+
f"- **Unstaged Files:** {len(p_state.git_state.unstaged_files)}",
|
|
106
|
+
f"- **Untracked Files:** {len(p_state.git_state.untracked_files)}",
|
|
107
|
+
"",
|
|
108
|
+
"## 2. Canonical Architecture & Component Inventory",
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
if state.graph_nodes:
|
|
112
|
+
# Group by NodeType
|
|
113
|
+
nodes_by_type: Dict[str, List[GraphNode]] = {}
|
|
114
|
+
for n in state.graph_nodes.values():
|
|
115
|
+
t = n.node_type.value
|
|
116
|
+
nodes_by_type.setdefault(t, []).append(n)
|
|
117
|
+
|
|
118
|
+
for n_type, n_list in sorted(nodes_by_type.items()):
|
|
119
|
+
lines.append(f"### {n_type.capitalize()}s ({len(n_list)})")
|
|
120
|
+
for n in sorted(n_list, key=lambda x: x.name):
|
|
121
|
+
conf_str = f" | Confidence: {n.confidence_score:.0f}%" if n.confidence_score > 0 else ""
|
|
122
|
+
lines.append(f"- **{n.name}** (`{n.id}`): Status `[{n.status.value}]`{conf_str}")
|
|
123
|
+
lines.append("")
|
|
124
|
+
else:
|
|
125
|
+
lines.append("- *No graph components registered.*")
|
|
126
|
+
lines.append("")
|
|
127
|
+
|
|
128
|
+
lines.extend([
|
|
129
|
+
"## 3. Verified Test & Verification Baseline",
|
|
130
|
+
f"- **Recorded Test Executions:** {len(p_state.test_results)}",
|
|
131
|
+
])
|
|
132
|
+
|
|
133
|
+
if p_state.test_results:
|
|
134
|
+
passed = [t for t in p_state.test_results if t.status.value == "VERIFIED"]
|
|
135
|
+
failed = [t for t in p_state.test_results if t.status.value != "VERIFIED"]
|
|
136
|
+
lines.append(f"- **Passing Tests:** {len(passed)}")
|
|
137
|
+
lines.append(f"- **Failing Tests:** {len(failed)}")
|
|
138
|
+
if failed:
|
|
139
|
+
lines.append("\n#### ❌ Failing Tests Detail:")
|
|
140
|
+
for ft in failed:
|
|
141
|
+
lines.append(f"- **{ft.name}** (`{ft.suite}`): exit code {ft.exit_code}")
|
|
142
|
+
if ft.error_message:
|
|
143
|
+
lines.append(f" - Error: `{ft.error_message}`")
|
|
144
|
+
lines.append("")
|
|
145
|
+
|
|
146
|
+
lines.extend([
|
|
147
|
+
"## 4. Architectural Decisions & Requirements",
|
|
148
|
+
f"- **User Requirements:** {len(c_state.user_requirements)}",
|
|
149
|
+
f"- **Recorded Decisions:** {len(c_state.architectural_decisions)}",
|
|
150
|
+
])
|
|
151
|
+
|
|
152
|
+
if c_state.architectural_decisions:
|
|
153
|
+
for d in c_state.architectural_decisions:
|
|
154
|
+
lines.append(f"- **{d.title}**: {d.rationale}")
|
|
155
|
+
if d.constraints:
|
|
156
|
+
for c in d.constraints:
|
|
157
|
+
lines.append(f" - *Constraint*: {c}")
|
|
158
|
+
|
|
159
|
+
lines.append("\n---")
|
|
160
|
+
lines.append("*Generated automatically by Project Continuum Universal Handoff Engine.*")
|
|
161
|
+
return "\n".join(lines)
|
|
162
|
+
|
|
163
|
+
def _generate_handoff_md(
|
|
164
|
+
self,
|
|
165
|
+
state: CanonicalProjectState,
|
|
166
|
+
task_context: Optional[TaskContext] = None
|
|
167
|
+
) -> str:
|
|
168
|
+
"""
|
|
169
|
+
Generates handoff.md: Tactical continuation document explaining exactly
|
|
170
|
+
what the next agent needs to do, distinguishing verified vs unverified claims.
|
|
171
|
+
"""
|
|
172
|
+
exec_state = state.agent_execution_state
|
|
173
|
+
c_state = state.conversational_state
|
|
174
|
+
p_state = state.project_state
|
|
175
|
+
|
|
176
|
+
lines = [
|
|
177
|
+
"# Project Continuum — Agent Handoff Briefing",
|
|
178
|
+
f"**Session / Project ID:** `{state.project_id}`",
|
|
179
|
+
f"**Previous Agent Model:** `{exec_state.model_name}` (ID: `{exec_state.agent_id}`)",
|
|
180
|
+
f"**Handoff Generated At:** `{datetime.now(timezone.utc).isoformat()}`",
|
|
181
|
+
"",
|
|
182
|
+
"> ⚠️ **MANDATORY DIRECTIVE FOR RESUMING AGENT:**",
|
|
183
|
+
"> Maintain strict separation between verified physical evidence and conversational claims.",
|
|
184
|
+
"> Never accept unverified agent claims as completed tasks without physical verification.",
|
|
185
|
+
"",
|
|
186
|
+
"## 🎯 1. Tactical In-Flight & Active Tasks",
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
if exec_state.active_tasks:
|
|
190
|
+
for t in exec_state.active_tasks:
|
|
191
|
+
lines.append(f"- **{t.title}** (`{t.id}`): Status `[{t.status.value}]`")
|
|
192
|
+
if t.target_files:
|
|
193
|
+
lines.append(f" - Target Files: {', '.join(f'`{f}`' for f in t.target_files)}")
|
|
194
|
+
if t.target_symbols:
|
|
195
|
+
lines.append(f" - Target Symbols: {', '.join(f'`{s}`' for s in t.target_symbols)}")
|
|
196
|
+
if t.notes:
|
|
197
|
+
lines.append(f" - Notes: {t.notes}")
|
|
198
|
+
else:
|
|
199
|
+
lines.append("- *No in-flight tasks recorded.*")
|
|
200
|
+
|
|
201
|
+
lines.extend([
|
|
202
|
+
"",
|
|
203
|
+
"## 🚀 2. Recommended Next Action",
|
|
204
|
+
])
|
|
205
|
+
|
|
206
|
+
if exec_state.next_action:
|
|
207
|
+
na = exec_state.next_action
|
|
208
|
+
lines.append(f"- **Action Type:** `{na.action_type}`")
|
|
209
|
+
lines.append(f"- **Target URI:** `{na.target_uri}`")
|
|
210
|
+
lines.append(f"- **Description:** {na.description}")
|
|
211
|
+
if na.prerequisites:
|
|
212
|
+
lines.append(f"- **Prerequisites:** {', '.join(f'`{p}`' for p in na.prerequisites)}")
|
|
213
|
+
elif exec_state.last_error_encountered:
|
|
214
|
+
lines.append(f"- **Action Required:** Fix last encountered error: `{exec_state.last_error_encountered}`")
|
|
215
|
+
else:
|
|
216
|
+
lines.append("- *Inspect known blockers and continue highest priority in-progress component.*")
|
|
217
|
+
|
|
218
|
+
lines.extend([
|
|
219
|
+
"",
|
|
220
|
+
"## ⚠️ 3. Known Blockers & Contradiction Ledger",
|
|
221
|
+
])
|
|
222
|
+
|
|
223
|
+
if state.contradictions:
|
|
224
|
+
lines.append(f"**Total Contradictions Detected:** {len(state.contradictions)}")
|
|
225
|
+
for c in state.contradictions:
|
|
226
|
+
res_tag = " [RESOLVED]" if c.resolved else " [ACTIVE BLOCKER]"
|
|
227
|
+
lines.append(f"- 🔴 **[{c.severity}]{res_tag}**: {c.explanation}")
|
|
228
|
+
if c.claim_text:
|
|
229
|
+
lines.append(f" - *Conflicting Claim*: \"{c.claim_text}\"")
|
|
230
|
+
else:
|
|
231
|
+
lines.append("- ✅ *Zero unresolved contradictions detected between claims and physical state.*")
|
|
232
|
+
|
|
233
|
+
lines.extend([
|
|
234
|
+
"",
|
|
235
|
+
"## 💬 4. Unverified Conversational Claims & Unresolved Questions",
|
|
236
|
+
])
|
|
237
|
+
|
|
238
|
+
if c_state.agent_claims:
|
|
239
|
+
lines.append("### Unverified Agent Claims (Level 5 Evidence):")
|
|
240
|
+
for cl in c_state.agent_claims:
|
|
241
|
+
lines.append(f"- \"{cl.claim_text}\" (Claimed Status: `[{cl.claimed_status.value}]` by `{cl.source_agent}`)")
|
|
242
|
+
else:
|
|
243
|
+
lines.append("- *No unverified agent claims recorded.*")
|
|
244
|
+
|
|
245
|
+
if c_state.unresolved_questions:
|
|
246
|
+
lines.append("\n### Unresolved Questions:")
|
|
247
|
+
for uq in c_state.unresolved_questions:
|
|
248
|
+
block_tag = " **[BLOCKING]**" if uq.blocking else ""
|
|
249
|
+
lines.append(f"- ❓{block_tag} {uq.question} (Context: {uq.context or 'N/A'})")
|
|
250
|
+
|
|
251
|
+
if task_context:
|
|
252
|
+
lines.extend([
|
|
253
|
+
"",
|
|
254
|
+
"## 🔍 5. Focused Task Context",
|
|
255
|
+
task_context.to_markdown()
|
|
256
|
+
])
|
|
257
|
+
|
|
258
|
+
lines.append("\n---")
|
|
259
|
+
lines.append("*Project Continuum AI Work Continuity Package.*")
|
|
260
|
+
return "\n".join(lines)
|
|
261
|
+
|
|
262
|
+
def _generate_evidence_artifacts(self, state: CanonicalProjectState) -> Dict[str, str]:
|
|
263
|
+
"""
|
|
264
|
+
Generates artifacts for the evidence/ directory:
|
|
265
|
+
- evidence/test_results.json
|
|
266
|
+
- evidence/contradictions.json
|
|
267
|
+
- evidence/symbols_manifest.json
|
|
268
|
+
- evidence/evidence_manifest.json
|
|
269
|
+
"""
|
|
270
|
+
artifacts: Dict[str, str] = {}
|
|
271
|
+
|
|
272
|
+
# 1. Test Results
|
|
273
|
+
test_data = [t.to_dict() for t in state.project_state.test_results]
|
|
274
|
+
artifacts["test_results.json"] = json.dumps(test_data, indent=2)
|
|
275
|
+
|
|
276
|
+
# 2. Contradictions
|
|
277
|
+
contra_data = [c.to_dict() for c in state.contradictions]
|
|
278
|
+
artifacts["contradictions.json"] = json.dumps(contra_data, indent=2)
|
|
279
|
+
|
|
280
|
+
# 3. Symbols
|
|
281
|
+
sym_data = [s.to_dict() for s in state.project_state.symbols]
|
|
282
|
+
artifacts["symbols_manifest.json"] = json.dumps(sym_data, indent=2)
|
|
283
|
+
|
|
284
|
+
# 4. Evidence Pool Manifest
|
|
285
|
+
ev_data = {k: v.to_dict() for k, v in state.evidence_pool.items()}
|
|
286
|
+
artifacts["evidence_manifest.json"] = json.dumps(ev_data, indent=2)
|
|
287
|
+
|
|
288
|
+
return artifacts
|
pipeline/__init__.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - End-to-End Pipeline Package
|
|
3
|
+
===============================================
|
|
4
|
+
Exposes the ContinuumPipeline and PipelineExecutionSummary.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pipeline.orchestrator import ContinuumPipeline, PipelineExecutionSummary
|
|
8
|
+
|
|
9
|
+
__all__ = ["ContinuumPipeline", "PipelineExecutionSummary"]
|
pipeline/orchestrator.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - End-to-End Orchestrator Pipeline
|
|
3
|
+
=====================================================
|
|
4
|
+
Milestone 8 - Phase 19: End-to-End Integration & Polyglot Validation.
|
|
5
|
+
Connects the complete Continuum pipeline:
|
|
6
|
+
1. Multi-source evidence harvesting (Workspace, Config, Git, Verification, Conversation).
|
|
7
|
+
2. Evidence Resolution Engine (arbitration by hierarchy level 1-5).
|
|
8
|
+
3. Contradiction Detection Engine (detecting mismatches between claims and reality).
|
|
9
|
+
4. Confidence Calculation Engine (explainable scoring grounded in proof).
|
|
10
|
+
5. Canonical State Graph / DAG (node/edge modeling, cycle prevention, dependency propagation).
|
|
11
|
+
6. Task-driven Context Selection & Budget Pruning (minimum sufficient high-signal context).
|
|
12
|
+
7. Model-Specific Handoff Adapters (Claude, Codex/GPT, Gemini, Local LLM, Universal).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
18
|
+
|
|
19
|
+
from core.enums import EvidenceLevel, EvidenceType, NodeType, RelationType, Status, TargetModel
|
|
20
|
+
from core.evidence import Evidence
|
|
21
|
+
from core.state_models import (
|
|
22
|
+
AgentClaim,
|
|
23
|
+
AgentExecutionState,
|
|
24
|
+
CanonicalProjectState,
|
|
25
|
+
ContradictionRecord,
|
|
26
|
+
ConversationalState,
|
|
27
|
+
GraphEdge,
|
|
28
|
+
GraphNode,
|
|
29
|
+
ProjectState,
|
|
30
|
+
Requirement,
|
|
31
|
+
TestResult,
|
|
32
|
+
)
|
|
33
|
+
from core.serializer import CanonicalStateSerializer
|
|
34
|
+
from extractors.workspace_extractor import WorkspaceEvidenceExtractor
|
|
35
|
+
from extractors.config_extractor import ConfigEvidenceExtractor
|
|
36
|
+
from extractors.git_extractor import GitEvidenceExtractor
|
|
37
|
+
from extractors.verification_extractor import VerificationEvidenceExtractor
|
|
38
|
+
from extractors.conversation_extractor import ConversationEvidenceExtractor
|
|
39
|
+
from resolution.resolver import EvidenceResolver, ResolutionResult
|
|
40
|
+
from contradictions.detector import ContradictionDetector
|
|
41
|
+
from confidence.calculator import ConfidenceCalculator
|
|
42
|
+
from graph.manager import StateGraphManager
|
|
43
|
+
from context.selector import TaskContextSelector
|
|
44
|
+
from context.pruner import ContextPruner
|
|
45
|
+
from context.models import TaskContext
|
|
46
|
+
from handoff.packager import UniversalHandoffPackager
|
|
47
|
+
from handoff.adapters import get_adapter_for_model
|
|
48
|
+
from handoff.models import HandoffPackage
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class PipelineExecutionSummary:
|
|
53
|
+
"""Summary metrics of an end-to-end pipeline execution."""
|
|
54
|
+
project_id: str
|
|
55
|
+
workspace_path: str
|
|
56
|
+
languages_detected: List[str]
|
|
57
|
+
total_files_scanned: int
|
|
58
|
+
total_symbols_extracted: int
|
|
59
|
+
total_evidence_collected: int
|
|
60
|
+
contradictions_detected: int
|
|
61
|
+
project_confidence: float
|
|
62
|
+
graph_nodes_count: int
|
|
63
|
+
graph_edges_count: int
|
|
64
|
+
context_tokens_generated: Optional[int] = None
|
|
65
|
+
handoff_formats_generated: List[str] = field(default_factory=list)
|
|
66
|
+
|
|
67
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
68
|
+
return {
|
|
69
|
+
"project_id": self.project_id,
|
|
70
|
+
"workspace_path": self.workspace_path,
|
|
71
|
+
"languages_detected": self.languages_detected,
|
|
72
|
+
"total_files_scanned": self.total_files_scanned,
|
|
73
|
+
"total_symbols_extracted": self.total_symbols_extracted,
|
|
74
|
+
"total_evidence_collected": self.total_evidence_collected,
|
|
75
|
+
"contradictions_detected": self.contradictions_detected,
|
|
76
|
+
"project_confidence": self.project_confidence,
|
|
77
|
+
"graph_nodes_count": self.graph_nodes_count,
|
|
78
|
+
"graph_edges_count": self.graph_edges_count,
|
|
79
|
+
"context_tokens_generated": self.context_tokens_generated,
|
|
80
|
+
"handoff_formats_generated": self.handoff_formats_generated,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ContinuumPipeline:
|
|
85
|
+
"""
|
|
86
|
+
High-level orchestrator for Project Continuum.
|
|
87
|
+
Executes the complete end-to-end pipeline from physical workspace scanning
|
|
88
|
+
to model-optimized handoff generation.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
workspace_path: Union[str, Path],
|
|
94
|
+
project_id: Optional[str] = None,
|
|
95
|
+
custom_parsers: Optional[List[Any]] = None
|
|
96
|
+
):
|
|
97
|
+
self.workspace_path = Path(workspace_path).resolve()
|
|
98
|
+
self.project_id = project_id or f"proj_{self.workspace_path.name}"
|
|
99
|
+
|
|
100
|
+
# Initialize subsystem engines
|
|
101
|
+
self.ws_extractor = WorkspaceEvidenceExtractor(custom_parsers=custom_parsers)
|
|
102
|
+
self.config_extractor = ConfigEvidenceExtractor()
|
|
103
|
+
self.git_extractor = GitEvidenceExtractor()
|
|
104
|
+
self.verification_extractor = VerificationEvidenceExtractor()
|
|
105
|
+
self.conversation_extractor = ConversationEvidenceExtractor()
|
|
106
|
+
|
|
107
|
+
self.resolver = EvidenceResolver()
|
|
108
|
+
self.contradiction_detector = ContradictionDetector()
|
|
109
|
+
self.confidence_calculator = ConfidenceCalculator()
|
|
110
|
+
self.context_selector = TaskContextSelector()
|
|
111
|
+
self.context_pruner = ContextPruner()
|
|
112
|
+
self.universal_packager = UniversalHandoffPackager()
|
|
113
|
+
|
|
114
|
+
def run_full_analysis(
|
|
115
|
+
self,
|
|
116
|
+
conversation_input: Optional[Union[str, Path, Dict[str, Any]]] = None,
|
|
117
|
+
explicit_verification_results: Optional[List[TestResult]] = None,
|
|
118
|
+
task_description: Optional[str] = None,
|
|
119
|
+
token_budget: Optional[int] = None,
|
|
120
|
+
target_models: Optional[List[TargetModel]] = None
|
|
121
|
+
) -> Tuple[CanonicalProjectState, PipelineExecutionSummary, Dict[str, Any]]:
|
|
122
|
+
"""
|
|
123
|
+
Executes the complete end-to-end pipeline:
|
|
124
|
+
1. Workspace scanning & symbol parsing.
|
|
125
|
+
2. Manifest & config discovery.
|
|
126
|
+
3. Git tree inspection.
|
|
127
|
+
4. Test verification & results recording.
|
|
128
|
+
5. Conversation ingestion (preserving strict 3-state separation).
|
|
129
|
+
6. Truth resolution across evidence hierarchy.
|
|
130
|
+
7. Contradiction detection.
|
|
131
|
+
8. Grounded confidence computation.
|
|
132
|
+
9. DAG construction & dependency propagation.
|
|
133
|
+
10. Task-driven context selection & budget pruning.
|
|
134
|
+
11. Universal & model-specific handoff generation.
|
|
135
|
+
"""
|
|
136
|
+
# Initialize Canonical State container
|
|
137
|
+
canonical_state = CanonicalProjectState(
|
|
138
|
+
schema_version="1.0.0",
|
|
139
|
+
project_id=self.project_id,
|
|
140
|
+
project_state=ProjectState(root_path=str(self.workspace_path))
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# ----------------------------------------------------------------------
|
|
144
|
+
# Step 1: Physical Workspace & Source Code Evidence Extraction
|
|
145
|
+
# ----------------------------------------------------------------------
|
|
146
|
+
self.ws_extractor.populate_project_state(str(self.workspace_path), canonical_state)
|
|
147
|
+
|
|
148
|
+
# ----------------------------------------------------------------------
|
|
149
|
+
# Step 2: Configuration, Environment & Manifest Extraction
|
|
150
|
+
# ----------------------------------------------------------------------
|
|
151
|
+
self.config_extractor.populate_project_state(str(self.workspace_path), canonical_state)
|
|
152
|
+
|
|
153
|
+
# ----------------------------------------------------------------------
|
|
154
|
+
# Step 3: Git History & Delta Analysis
|
|
155
|
+
# ----------------------------------------------------------------------
|
|
156
|
+
self.git_extractor.populate_project_state(str(self.workspace_path), canonical_state)
|
|
157
|
+
|
|
158
|
+
# ----------------------------------------------------------------------
|
|
159
|
+
# Step 4: Verification & Test Execution Recording
|
|
160
|
+
# ----------------------------------------------------------------------
|
|
161
|
+
if explicit_verification_results:
|
|
162
|
+
for tr in explicit_verification_results:
|
|
163
|
+
canonical_state.project_state.test_results.append(tr)
|
|
164
|
+
test_ev = self.verification_extractor.create_evidence(
|
|
165
|
+
evidence_type=EvidenceType.TEST_RUN,
|
|
166
|
+
summary=f"Test Suite: {tr.suite} (Test: {tr.name}, Status: {tr.status.value})",
|
|
167
|
+
raw_payload=tr.to_dict(),
|
|
168
|
+
source_uri=tr.suite,
|
|
169
|
+
locator=f"test:{tr.suite}:{tr.name}"
|
|
170
|
+
)
|
|
171
|
+
canonical_state.add_evidence(test_ev)
|
|
172
|
+
|
|
173
|
+
# ----------------------------------------------------------------------
|
|
174
|
+
# Step 5: Conversation & Agent State Ingestion (Strict 3-State Separation)
|
|
175
|
+
# ----------------------------------------------------------------------
|
|
176
|
+
if conversation_input:
|
|
177
|
+
self.conversation_extractor.ingest_transcript(conversation_input, canonical_state)
|
|
178
|
+
|
|
179
|
+
# ----------------------------------------------------------------------
|
|
180
|
+
# Step 6 & 7: Contradiction Detection & Discrepancy Resolution
|
|
181
|
+
# ----------------------------------------------------------------------
|
|
182
|
+
contradictions = self.contradiction_detector.detect_contradictions(
|
|
183
|
+
project_state=canonical_state.project_state,
|
|
184
|
+
conversational_state=canonical_state.conversational_state,
|
|
185
|
+
evidence_pool=canonical_state.evidence_pool
|
|
186
|
+
)
|
|
187
|
+
canonical_state.contradictions = contradictions
|
|
188
|
+
|
|
189
|
+
# ----------------------------------------------------------------------
|
|
190
|
+
# Step 8 & 9: Canonical State Graph (DAG) Construction
|
|
191
|
+
# ----------------------------------------------------------------------
|
|
192
|
+
graph_manager = StateGraphManager(canonical_state)
|
|
193
|
+
graph_manager.build_from_canonical_state(canonical_state)
|
|
194
|
+
|
|
195
|
+
# ----------------------------------------------------------------------
|
|
196
|
+
# Step 10: Grounded Confidence Calculation
|
|
197
|
+
# ----------------------------------------------------------------------
|
|
198
|
+
proj_confidence, conf_explanation = self.confidence_calculator.calculate_project_confidence(canonical_state)
|
|
199
|
+
|
|
200
|
+
# ----------------------------------------------------------------------
|
|
201
|
+
# Step 11: Task Context Selection & Budget Pruning (Optional)
|
|
202
|
+
# ----------------------------------------------------------------------
|
|
203
|
+
task_ctx: Optional[TaskContext] = None
|
|
204
|
+
pruned_tokens = None
|
|
205
|
+
if task_description:
|
|
206
|
+
task_ctx = self.context_selector.extract_task_context(
|
|
207
|
+
task_description=task_description,
|
|
208
|
+
canonical_state=canonical_state,
|
|
209
|
+
token_budget=token_budget
|
|
210
|
+
)
|
|
211
|
+
if token_budget:
|
|
212
|
+
prune_res = self.context_pruner.prune_to_budget(task_ctx, token_budget)
|
|
213
|
+
pruned_tokens = prune_res.estimated_tokens_after
|
|
214
|
+
|
|
215
|
+
# ----------------------------------------------------------------------
|
|
216
|
+
# Step 12: Model Handoff Generation (Universal & Model-Specific)
|
|
217
|
+
# ----------------------------------------------------------------------
|
|
218
|
+
handoff_results: Dict[str, Any] = {}
|
|
219
|
+
generated_formats: List[str] = []
|
|
220
|
+
|
|
221
|
+
# Universal Handoff Package
|
|
222
|
+
universal_pkg = self.universal_packager.generate_package(canonical_state, task_ctx)
|
|
223
|
+
handoff_results["universal"] = universal_pkg
|
|
224
|
+
generated_formats.append("universal")
|
|
225
|
+
|
|
226
|
+
# Model-Specific Adapters
|
|
227
|
+
models_to_generate = target_models or [
|
|
228
|
+
TargetModel.CLAUDE,
|
|
229
|
+
TargetModel.CODEX_GPT,
|
|
230
|
+
TargetModel.GEMINI,
|
|
231
|
+
TargetModel.LOCAL_LLM
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
for model in models_to_generate:
|
|
235
|
+
adapter = get_adapter_for_model(model)
|
|
236
|
+
model_handoff = adapter.generate_handoff(canonical_state)
|
|
237
|
+
handoff_results[model.value] = model_handoff
|
|
238
|
+
handoff_results[model.value.lower()] = model_handoff
|
|
239
|
+
if model == TargetModel.CODEX_GPT:
|
|
240
|
+
handoff_results["codex"] = model_handoff
|
|
241
|
+
generated_formats.append(model.value)
|
|
242
|
+
|
|
243
|
+
p_state = canonical_state.project_state
|
|
244
|
+
# Build execution summary
|
|
245
|
+
summary = PipelineExecutionSummary(
|
|
246
|
+
project_id=self.project_id,
|
|
247
|
+
workspace_path=str(self.workspace_path),
|
|
248
|
+
languages_detected=list(set(p_state.detected_languages)),
|
|
249
|
+
total_files_scanned=len(p_state.files),
|
|
250
|
+
total_symbols_extracted=len(p_state.symbols),
|
|
251
|
+
total_evidence_collected=len(canonical_state.evidence_pool),
|
|
252
|
+
contradictions_detected=len(contradictions),
|
|
253
|
+
project_confidence=proj_confidence,
|
|
254
|
+
graph_nodes_count=len(canonical_state.graph_nodes),
|
|
255
|
+
graph_edges_count=len(canonical_state.graph_edges),
|
|
256
|
+
context_tokens_generated=pruned_tokens,
|
|
257
|
+
handoff_formats_generated=generated_formats
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
return canonical_state, summary, handoff_results
|
resolution/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Evidence Resolution Subsystem Package Initialization
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from resolution.resolver import (
|
|
6
|
+
EvidenceResolver,
|
|
7
|
+
EvidenceCandidate,
|
|
8
|
+
ResolutionResult,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"EvidenceResolver",
|
|
13
|
+
"EvidenceCandidate",
|
|
14
|
+
"ResolutionResult",
|
|
15
|
+
]
|