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
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Claude Handoff Adapter
|
|
3
|
+
==========================================
|
|
4
|
+
Milestone 6 - Phase 15: Model-Specific Handoff Adapters.
|
|
5
|
+
Formats handoff packages with semantic XML tags (<project_state>, <verified_reality>,
|
|
6
|
+
<active_blockers>, <tactical_tasks>) optimized for Claude 3 / 3.5 prompt caching and reasoning.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from typing import Any, Dict, Optional
|
|
11
|
+
|
|
12
|
+
from core.enums import TargetModel, Status
|
|
13
|
+
from core.serializer import CanonicalStateSerializer
|
|
14
|
+
from core.state_models import CanonicalProjectState
|
|
15
|
+
from handoff.adapters.base import BaseModelAdapter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ClaudeAdapter(BaseModelAdapter):
|
|
19
|
+
"""
|
|
20
|
+
Handoff adapter tailored for Anthropic's Claude models.
|
|
21
|
+
Uses structured XML tags for optimal context separation and prompt caching.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
super().__init__(target_model=TargetModel.CLAUDE)
|
|
26
|
+
|
|
27
|
+
def generate_handoff(
|
|
28
|
+
self,
|
|
29
|
+
canonical_state: CanonicalProjectState,
|
|
30
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
31
|
+
) -> Dict[str, str]:
|
|
32
|
+
# 1. project-state.json
|
|
33
|
+
state_json = CanonicalStateSerializer.to_json(canonical_state, indent=2)
|
|
34
|
+
|
|
35
|
+
# 2. project-context.md (XML structured)
|
|
36
|
+
context_md = self._build_claude_context(canonical_state)
|
|
37
|
+
|
|
38
|
+
# 3. handoff.md (XML tagged continuation briefing)
|
|
39
|
+
handoff_md = self._build_claude_handoff(canonical_state, context_selection)
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
"project-state.json": state_json,
|
|
43
|
+
"project-context.md": context_md,
|
|
44
|
+
"handoff.md": handoff_md
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
def _build_claude_context(self, state: CanonicalProjectState) -> str:
|
|
48
|
+
p_state = state.project_state
|
|
49
|
+
lines = [
|
|
50
|
+
f"# Project Continuum — Architectural Context for Claude",
|
|
51
|
+
f"<project_metadata>",
|
|
52
|
+
f" <project_id>{state.project_id}</project_id>",
|
|
53
|
+
f" <schema_version>{state.schema_version}</schema_version>",
|
|
54
|
+
f" <root_path>{p_state.root_path}</root_path>",
|
|
55
|
+
f" <languages>{', '.join(p_state.detected_languages)}</languages>",
|
|
56
|
+
f" <build_status>{p_state.build_status.value}</build_status>",
|
|
57
|
+
f"</project_metadata>",
|
|
58
|
+
"",
|
|
59
|
+
"<verified_architecture>",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
for n in state.graph_nodes.values():
|
|
63
|
+
lines.append(
|
|
64
|
+
f" <component id=\"{n.id}\" type=\"{n.node_type.value}\" status=\"{n.status.value}\" confidence=\"{n.confidence_score:.0f}%\">"
|
|
65
|
+
f"{n.name}</component>"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
lines.extend([
|
|
69
|
+
"</verified_architecture>",
|
|
70
|
+
"",
|
|
71
|
+
"<test_verification_baseline>",
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
for t in p_state.test_results:
|
|
75
|
+
err_tag = f" error=\"{t.error_message}\"" if t.error_message else ""
|
|
76
|
+
lines.append(
|
|
77
|
+
f" <test id=\"{t.test_id}\" suite=\"{t.suite}\" status=\"{t.status.value}\" exit_code=\"{t.exit_code}\"{err_tag}>"
|
|
78
|
+
f"{t.name}</test>"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
lines.extend([
|
|
82
|
+
"</test_verification_baseline>",
|
|
83
|
+
"",
|
|
84
|
+
"<architectural_constraints>",
|
|
85
|
+
])
|
|
86
|
+
|
|
87
|
+
for c in self._extract_constraints(state):
|
|
88
|
+
lines.append(f" <constraint>{c}</constraint>")
|
|
89
|
+
|
|
90
|
+
lines.append("</architectural_constraints>")
|
|
91
|
+
return "\n".join(lines)
|
|
92
|
+
|
|
93
|
+
def _build_claude_handoff(
|
|
94
|
+
self,
|
|
95
|
+
state: CanonicalProjectState,
|
|
96
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
97
|
+
) -> str:
|
|
98
|
+
exec_state = state.agent_execution_state
|
|
99
|
+
c_state = state.conversational_state
|
|
100
|
+
|
|
101
|
+
lines = [
|
|
102
|
+
"# Project Continuum — AI Agent Continuation Handoff",
|
|
103
|
+
"",
|
|
104
|
+
"<!-- CONTINUUM_HANDOFF_METADATA",
|
|
105
|
+
"Target-Model: ANTHROPIC_CLAUDE",
|
|
106
|
+
"Format: XML_TAGGED_ONTOLOGY",
|
|
107
|
+
f"Generated-At: {datetime.now(timezone.utc).isoformat()}",
|
|
108
|
+
"-->",
|
|
109
|
+
"",
|
|
110
|
+
"> 🧠 **CONTINUUM AI HANDOFF NOTICE:**",
|
|
111
|
+
"> You are taking over this ongoing software engineering project.",
|
|
112
|
+
"> This handoff package was generated directly from physical workspace AST analysis & test verification.",
|
|
113
|
+
"> Follow the structured `<system_directives>` and `<recommended_next_action>` below.",
|
|
114
|
+
"",
|
|
115
|
+
"<system_directives>",
|
|
116
|
+
" <directive>Preserve strict ontological separation between physical facts and conversational claims.</directive>",
|
|
117
|
+
" <directive>Never assume unverified agent claims are physically implemented without test verification.</directive>",
|
|
118
|
+
" <directive>Target format recognized: Anthropic Claude / XML Architecture.</directive>",
|
|
119
|
+
"</system_directives>",
|
|
120
|
+
"",
|
|
121
|
+
"<active_tasks>",
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
if exec_state.active_tasks:
|
|
125
|
+
for t in exec_state.active_tasks:
|
|
126
|
+
files_str = ", ".join(t.target_files) if t.target_files else "none"
|
|
127
|
+
lines.append(f" <task id=\"{t.id}\" status=\"{t.status.value}\" files=\"{files_str}\">{t.title}</task>")
|
|
128
|
+
else:
|
|
129
|
+
lines.append(" <task status=\"NONE\">No active in-flight tasks.</task>")
|
|
130
|
+
|
|
131
|
+
lines.extend([
|
|
132
|
+
"</active_tasks>",
|
|
133
|
+
"",
|
|
134
|
+
"<recommended_next_action>",
|
|
135
|
+
])
|
|
136
|
+
|
|
137
|
+
if exec_state.next_action:
|
|
138
|
+
na = exec_state.next_action
|
|
139
|
+
lines.append(f" <action type=\"{na.action_type}\" target=\"{na.target_uri}\">")
|
|
140
|
+
lines.append(f" <description>{na.description}</description>")
|
|
141
|
+
if na.prerequisites:
|
|
142
|
+
lines.append(f" <prerequisites>{', '.join(na.prerequisites)}</prerequisites>")
|
|
143
|
+
lines.append(" </action>")
|
|
144
|
+
else:
|
|
145
|
+
lines.append(" <action type=\"CONTINUE\">Resume highest priority in-progress component.</action>")
|
|
146
|
+
|
|
147
|
+
lines.extend([
|
|
148
|
+
"</recommended_next_action>",
|
|
149
|
+
"",
|
|
150
|
+
"<active_blockers_and_contradictions>",
|
|
151
|
+
])
|
|
152
|
+
|
|
153
|
+
active_contra = self._extract_active_contradictions(state)
|
|
154
|
+
if active_contra:
|
|
155
|
+
for c in active_contra:
|
|
156
|
+
lines.append(f" <contradiction id=\"{c['id']}\" severity=\"{c['severity']}\">")
|
|
157
|
+
lines.append(f" <explanation>{c['explanation']}</explanation>")
|
|
158
|
+
lines.append(f" <claim>{c['claim_text']}</claim>")
|
|
159
|
+
lines.append(" </contradiction>")
|
|
160
|
+
else:
|
|
161
|
+
lines.append(" <none>Zero unresolved contradictions detected.</none>")
|
|
162
|
+
|
|
163
|
+
lines.extend([
|
|
164
|
+
"</active_blockers_and_contradictions>",
|
|
165
|
+
"",
|
|
166
|
+
"<unverified_agent_claims>",
|
|
167
|
+
])
|
|
168
|
+
|
|
169
|
+
for cl in c_state.agent_claims:
|
|
170
|
+
lines.append(
|
|
171
|
+
f" <claim id=\"{cl.id}\" source=\"{cl.source_agent}\" status=\"{cl.claimed_status.value}\">"
|
|
172
|
+
f"{cl.claim_text}</claim>"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
lines.append("</unverified_agent_claims>")
|
|
176
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Codex / GPT Handoff Adapter
|
|
3
|
+
================================================
|
|
4
|
+
Milestone 6 - Phase 15: Model-Specific Handoff Adapters.
|
|
5
|
+
Formats handoff packages with high-contrast Markdown, code fences, and explicit
|
|
6
|
+
task checklists tailored for OpenAI GPT-4 / Codex reasoning engines.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
from core.enums import TargetModel, Status
|
|
12
|
+
from core.serializer import CanonicalStateSerializer
|
|
13
|
+
from core.state_models import CanonicalProjectState
|
|
14
|
+
from handoff.adapters.base import BaseModelAdapter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CodexGptAdapter(BaseModelAdapter):
|
|
18
|
+
"""
|
|
19
|
+
Handoff adapter tailored for OpenAI Codex / GPT-4 family models.
|
|
20
|
+
Uses Markdown headers, code block fencing, and structured step-by-step checklists.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
super().__init__(target_model=TargetModel.CODEX_GPT)
|
|
25
|
+
|
|
26
|
+
def generate_handoff(
|
|
27
|
+
self,
|
|
28
|
+
canonical_state: CanonicalProjectState,
|
|
29
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
30
|
+
) -> Dict[str, str]:
|
|
31
|
+
state_json = CanonicalStateSerializer.to_json(canonical_state, indent=2)
|
|
32
|
+
context_md = self._build_gpt_context(canonical_state)
|
|
33
|
+
handoff_md = self._build_gpt_handoff(canonical_state, context_selection)
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
"project-state.json": state_json,
|
|
37
|
+
"project-context.md": context_md,
|
|
38
|
+
"handoff.md": handoff_md
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def _build_gpt_context(self, state: CanonicalProjectState) -> str:
|
|
42
|
+
p_state = state.project_state
|
|
43
|
+
lines = [
|
|
44
|
+
f"# Project Continuum — Verified Context for Codex/GPT",
|
|
45
|
+
f"```json",
|
|
46
|
+
f"{{",
|
|
47
|
+
f' "project_id": "{state.project_id}",',
|
|
48
|
+
f' "root_path": "{p_state.root_path}",',
|
|
49
|
+
f' "build_status": "{p_state.build_status.value}"',
|
|
50
|
+
f"}}",
|
|
51
|
+
f"```",
|
|
52
|
+
"",
|
|
53
|
+
"## Verified Component Directory",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
for n in state.graph_nodes.values():
|
|
57
|
+
badge = "✅" if n.status == Status.VERIFIED else "⚠️"
|
|
58
|
+
lines.append(f"- {badge} **`{n.name}`** (`{n.id}`): Status `{n.status.value}` (Confidence: {n.confidence_score:.0f}%)")
|
|
59
|
+
|
|
60
|
+
lines.extend([
|
|
61
|
+
"",
|
|
62
|
+
"## Automated Test Suite Baseline",
|
|
63
|
+
])
|
|
64
|
+
|
|
65
|
+
for t in p_state.test_results:
|
|
66
|
+
icon = "PASS" if t.status == Status.VERIFIED else "FAIL"
|
|
67
|
+
err = f" -> Error: {t.error_message}" if t.error_message else ""
|
|
68
|
+
lines.append(f"- `[{icon}]` `{t.name}` in `{t.suite}` (Exit code: {t.exit_code}){err}")
|
|
69
|
+
|
|
70
|
+
lines.extend([
|
|
71
|
+
"",
|
|
72
|
+
"## Inviolable Architectural Constraints",
|
|
73
|
+
])
|
|
74
|
+
|
|
75
|
+
for c in self._extract_constraints(state):
|
|
76
|
+
lines.append(f"- [x] **CONSTRAINT**: {c}")
|
|
77
|
+
|
|
78
|
+
return "\n".join(lines)
|
|
79
|
+
|
|
80
|
+
def _build_gpt_handoff(
|
|
81
|
+
self,
|
|
82
|
+
state: CanonicalProjectState,
|
|
83
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
84
|
+
) -> str:
|
|
85
|
+
exec_state = state.agent_execution_state
|
|
86
|
+
c_state = state.conversational_state
|
|
87
|
+
|
|
88
|
+
lines = [
|
|
89
|
+
"# Project Continuum — OpenAI Codex / GPT Continuity Task Plan",
|
|
90
|
+
"",
|
|
91
|
+
"<!-- CONTINUUM_HANDOFF_METADATA",
|
|
92
|
+
"Target-Model: OPENAI_CODEX_GPT",
|
|
93
|
+
"Format: MARKDOWN_CHECKLISTS_AND_CODEBLOCKS",
|
|
94
|
+
"-->",
|
|
95
|
+
"",
|
|
96
|
+
"> 🧠 **CONTINUUM AI HANDOFF NOTICE:**",
|
|
97
|
+
"> You are taking over an ongoing software engineering project.",
|
|
98
|
+
"> Ground truth is defined by physical AST code and test results, NOT past conversational assertions.",
|
|
99
|
+
"",
|
|
100
|
+
"### 🚨 System Protocol",
|
|
101
|
+
"1. You are picking up an ongoing engineering task.",
|
|
102
|
+
"2. Ground truth is defined by physical tests and code, NOT previous assistant chat messages.",
|
|
103
|
+
"3. Resolve blockers first before proceeding.",
|
|
104
|
+
"",
|
|
105
|
+
"## 📋 Active Tasks & Next Steps",
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
if exec_state.active_tasks:
|
|
109
|
+
for t in exec_state.active_tasks:
|
|
110
|
+
lines.append(f"- [ ] **Task**: `{t.title}` (`{t.id}`) - Status: `{t.status.value}`")
|
|
111
|
+
if t.target_files:
|
|
112
|
+
lines.append(f" - Target files: {', '.join(f'`{f}`' for f in t.target_files)}")
|
|
113
|
+
else:
|
|
114
|
+
lines.append("- [ ] No in-flight tasks recorded.")
|
|
115
|
+
|
|
116
|
+
lines.extend([
|
|
117
|
+
"",
|
|
118
|
+
"## 🎯 Actionable Next Instruction",
|
|
119
|
+
])
|
|
120
|
+
|
|
121
|
+
if exec_state.next_action:
|
|
122
|
+
na = exec_state.next_action
|
|
123
|
+
lines.append(f"**Action**: `{na.action_type}` on `{na.target_uri}`")
|
|
124
|
+
lines.append(f"**Details**: {na.description}")
|
|
125
|
+
if na.prerequisites:
|
|
126
|
+
lines.append(f"**Prerequisites**: {', '.join(f'`{p}`' for p in na.prerequisites)}")
|
|
127
|
+
else:
|
|
128
|
+
lines.append("**Action**: Resume highest priority unfinished component.")
|
|
129
|
+
|
|
130
|
+
lines.extend([
|
|
131
|
+
"",
|
|
132
|
+
"## 🔴 Unresolved Blockers & Discrepancy Register",
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
active_contra = self._extract_active_contradictions(state)
|
|
136
|
+
if active_contra:
|
|
137
|
+
for c in active_contra:
|
|
138
|
+
lines.append(f"- ❌ **[{c['severity']} BLOCKER]**: {c['explanation']}")
|
|
139
|
+
lines.append(f" - Claim: \"{c['claim_text']}\"")
|
|
140
|
+
else:
|
|
141
|
+
lines.append("- ✅ No active contradictions detected.")
|
|
142
|
+
|
|
143
|
+
lines.extend([
|
|
144
|
+
"",
|
|
145
|
+
"## 💬 Unverified Conversational Statements (Level 5)",
|
|
146
|
+
])
|
|
147
|
+
|
|
148
|
+
for cl in c_state.agent_claims:
|
|
149
|
+
lines.append(f"- *Unverified Claim*: \"{cl.claim_text}\" (Agent: `{cl.source_agent}`)")
|
|
150
|
+
|
|
151
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Gemini Handoff Adapter
|
|
3
|
+
==========================================
|
|
4
|
+
Milestone 6 - Phase 15: Model-Specific Handoff Adapters.
|
|
5
|
+
Formats handoff packages with deep hierarchical structures, ontological groupings,
|
|
6
|
+
and rich contextual linkages optimized for Google Gemini 1.5 Pro / Flash large context windows.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
from core.enums import TargetModel, Status
|
|
12
|
+
from core.serializer import CanonicalStateSerializer
|
|
13
|
+
from core.state_models import CanonicalProjectState
|
|
14
|
+
from handoff.adapters.base import BaseModelAdapter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GeminiAdapter(BaseModelAdapter):
|
|
18
|
+
"""
|
|
19
|
+
Handoff adapter tailored for Google Gemini models.
|
|
20
|
+
Leverages deep hierarchical ontology representation and comprehensive cross-referencing.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
super().__init__(target_model=TargetModel.GEMINI)
|
|
25
|
+
|
|
26
|
+
def generate_handoff(
|
|
27
|
+
self,
|
|
28
|
+
canonical_state: CanonicalProjectState,
|
|
29
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
30
|
+
) -> Dict[str, str]:
|
|
31
|
+
state_json = CanonicalStateSerializer.to_json(canonical_state, indent=2)
|
|
32
|
+
context_md = self._build_gemini_context(canonical_state)
|
|
33
|
+
handoff_md = self._build_gemini_handoff(canonical_state, context_selection)
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
"project-state.json": state_json,
|
|
37
|
+
"project-context.md": context_md,
|
|
38
|
+
"handoff.md": handoff_md
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def _build_gemini_context(self, state: CanonicalProjectState) -> str:
|
|
42
|
+
p_state = state.project_state
|
|
43
|
+
lines = [
|
|
44
|
+
f"# Project Continuum — Hierarchical Project Knowledge Graph (Gemini Engine)",
|
|
45
|
+
f"**Canonical State Container:** `{state.project_id}` (Schema: `{state.schema_version}`)",
|
|
46
|
+
"",
|
|
47
|
+
"## Tier 1: Ground Truth Project Topology",
|
|
48
|
+
"### Physical Environment & Manifests",
|
|
49
|
+
f"- Path: `{p_state.root_path}`",
|
|
50
|
+
f"- Polyglot Stack: {', '.join(p_state.detected_languages)}",
|
|
51
|
+
f"- Build Status: `[{p_state.build_status.value}]`",
|
|
52
|
+
"",
|
|
53
|
+
"### Domain Component Graph",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
for n in state.graph_nodes.values():
|
|
57
|
+
lines.append(f"- **{n.name}** (`{n.id}`) — Type: `{n.node_type.value}`, State: `{n.status.value}`, Verified Confidence: `{n.confidence_score:.1f}%`")
|
|
58
|
+
|
|
59
|
+
lines.extend([
|
|
60
|
+
"",
|
|
61
|
+
"## Tier 2: Empirical Verification & Evidence Matrix",
|
|
62
|
+
f"Total Verifiable Test Runs: {len(p_state.test_results)}",
|
|
63
|
+
])
|
|
64
|
+
|
|
65
|
+
for t in p_state.test_results:
|
|
66
|
+
status_symbol = "🟢" if t.status == Status.VERIFIED else "🔴"
|
|
67
|
+
lines.append(f"{status_symbol} **{t.name}** (`{t.suite}`) | Exit Code: {t.exit_code} | Duration: {t.duration_ms:.1f}ms")
|
|
68
|
+
if t.error_message:
|
|
69
|
+
lines.append(f" ↳ *Failure Reason:* `{t.error_message}`")
|
|
70
|
+
|
|
71
|
+
lines.extend([
|
|
72
|
+
"",
|
|
73
|
+
"## Tier 3: Invariant Architectural Principles",
|
|
74
|
+
])
|
|
75
|
+
|
|
76
|
+
for c in self._extract_constraints(state):
|
|
77
|
+
lines.append(f"• **Hard Constraint:** {c}")
|
|
78
|
+
|
|
79
|
+
return "\n".join(lines)
|
|
80
|
+
|
|
81
|
+
def _build_gemini_handoff(
|
|
82
|
+
self,
|
|
83
|
+
state: CanonicalProjectState,
|
|
84
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
85
|
+
) -> str:
|
|
86
|
+
exec_state = state.agent_execution_state
|
|
87
|
+
c_state = state.conversational_state
|
|
88
|
+
|
|
89
|
+
lines = [
|
|
90
|
+
"# Project Continuum — Google Gemini Agent Handoff & Continuity Instruction",
|
|
91
|
+
"",
|
|
92
|
+
"<!-- CONTINUUM_HANDOFF_METADATA",
|
|
93
|
+
"Target-Model: GOOGLE_GEMINI",
|
|
94
|
+
"Format: HIERARCHICAL_ONTOLOGY_TREE",
|
|
95
|
+
"-->",
|
|
96
|
+
"",
|
|
97
|
+
"> 🧠 **CONTINUUM AI HANDOFF NOTICE:**",
|
|
98
|
+
"> You are continuing an ongoing software engineering project with verified physical context.",
|
|
99
|
+
"",
|
|
100
|
+
"> 📌 **Epistemic Principle:**",
|
|
101
|
+
"> Strict demarcation between empirical facts (code, tests) and linguistic assertions (chat claims).",
|
|
102
|
+
"> Do not hallucinate task completion based on unverified conversational assertions.",
|
|
103
|
+
"",
|
|
104
|
+
"## 1. Tactical Execution Queue",
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
if exec_state.active_tasks:
|
|
108
|
+
for t in exec_state.active_tasks:
|
|
109
|
+
lines.append(f"* **Active Task [{t.status.value}]:** `{t.title}` (`{t.id}`)")
|
|
110
|
+
if t.target_files:
|
|
111
|
+
lines.append(f" * Scoped Files: {', '.join(f'`{f}`' for f in t.target_files)}")
|
|
112
|
+
else:
|
|
113
|
+
lines.append("* *No in-flight tactical tasks.*")
|
|
114
|
+
|
|
115
|
+
lines.extend([
|
|
116
|
+
"",
|
|
117
|
+
"## 2. Deterministic Next Action",
|
|
118
|
+
])
|
|
119
|
+
|
|
120
|
+
if exec_state.next_action:
|
|
121
|
+
na = exec_state.next_action
|
|
122
|
+
lines.append(f"* **Type:** `{na.action_type}`")
|
|
123
|
+
lines.append(f"* **Target:** `{na.target_uri}`")
|
|
124
|
+
lines.append(f"* **Description:** {na.description}")
|
|
125
|
+
if na.prerequisites:
|
|
126
|
+
lines.append(f"* **Prerequisites:** {', '.join(f'`{p}`' for p in na.prerequisites)}")
|
|
127
|
+
else:
|
|
128
|
+
lines.append("* **Type:** `RESUME_PRIORITY_TASK`")
|
|
129
|
+
|
|
130
|
+
lines.extend([
|
|
131
|
+
"",
|
|
132
|
+
"## 3. Discrepancy & Contradiction Registry",
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
active_contra = self._extract_active_contradictions(state)
|
|
136
|
+
if active_contra:
|
|
137
|
+
for c in active_contra:
|
|
138
|
+
lines.append(f"* ⚠️ **[{c['severity']}] Discrepancy:** {c['explanation']}")
|
|
139
|
+
lines.append(f" * Conflicting Assertion: \"{c['claim_text']}\"")
|
|
140
|
+
else:
|
|
141
|
+
lines.append("* ✅ *No unresolved discrepancies found.*")
|
|
142
|
+
|
|
143
|
+
lines.extend([
|
|
144
|
+
"",
|
|
145
|
+
"## 4. Subjective Claims Register (Level 5)",
|
|
146
|
+
])
|
|
147
|
+
|
|
148
|
+
for cl in c_state.agent_claims:
|
|
149
|
+
lines.append(f"* *Claim:* \"{cl.claim_text}\" (Agent: `{cl.source_agent}`, Claimed: `[{cl.claimed_status.value}]`)")
|
|
150
|
+
|
|
151
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project Continuum - Local LLM Handoff Adapter
|
|
3
|
+
==============================================
|
|
4
|
+
Milestone 6 - Phase 15: Model-Specific Handoff Adapters.
|
|
5
|
+
Formats handoff packages in high-density, compact token-budget-optimized formats
|
|
6
|
+
for local models (e.g. Llama-3, Mistral, Qwen, DeepSeek Coder) with smaller context windows.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
from core.enums import TargetModel, Status
|
|
12
|
+
from core.serializer import CanonicalStateSerializer
|
|
13
|
+
from core.state_models import CanonicalProjectState
|
|
14
|
+
from handoff.adapters.base import BaseModelAdapter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class LocalModelAdapter(BaseModelAdapter):
|
|
18
|
+
"""
|
|
19
|
+
Handoff adapter tailored for local open-source LLMs.
|
|
20
|
+
Prioritizes maximum information density and token frugality while strictly
|
|
21
|
+
preserving Tier 1 constraints, blockers, and next actions.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
super().__init__(target_model=TargetModel.LOCAL_LLM)
|
|
26
|
+
|
|
27
|
+
def generate_handoff(
|
|
28
|
+
self,
|
|
29
|
+
canonical_state: CanonicalProjectState,
|
|
30
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
31
|
+
) -> Dict[str, str]:
|
|
32
|
+
# Compact JSON serialization (no extra whitespace)
|
|
33
|
+
state_json = CanonicalStateSerializer.to_json(canonical_state, indent=2)
|
|
34
|
+
context_md = self._build_compact_context(canonical_state)
|
|
35
|
+
handoff_md = self._build_compact_handoff(canonical_state, context_selection)
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
"project-state.json": state_json,
|
|
39
|
+
"project-context.md": context_md,
|
|
40
|
+
"handoff.md": handoff_md
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def _build_compact_context(self, state: CanonicalProjectState) -> str:
|
|
44
|
+
p_state = state.project_state
|
|
45
|
+
lines = [
|
|
46
|
+
f"# Context: {state.project_id} | Root: {p_state.root_path} | Build: [{p_state.build_status.value}]",
|
|
47
|
+
"",
|
|
48
|
+
"## Components",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
for n in state.graph_nodes.values():
|
|
52
|
+
lines.append(f"- {n.name}({n.id}): [{n.status.value}] ({n.confidence_score:.0f}%)")
|
|
53
|
+
|
|
54
|
+
lines.extend([
|
|
55
|
+
"",
|
|
56
|
+
"## Test Baseline",
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
for t in p_state.test_results:
|
|
60
|
+
err = f" Err:{t.error_message}" if t.error_message else ""
|
|
61
|
+
lines.append(f"- {t.name}: [{t.status.value}] code:{t.exit_code}{err}")
|
|
62
|
+
|
|
63
|
+
lines.extend([
|
|
64
|
+
"",
|
|
65
|
+
"## Active Constraints",
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
for c in self._extract_constraints(state):
|
|
69
|
+
lines.append(f"- ! {c}")
|
|
70
|
+
|
|
71
|
+
return "\n".join(lines)
|
|
72
|
+
|
|
73
|
+
def _build_compact_handoff(
|
|
74
|
+
self,
|
|
75
|
+
state: CanonicalProjectState,
|
|
76
|
+
context_selection: Optional[Dict[str, Any]] = None
|
|
77
|
+
) -> str:
|
|
78
|
+
exec_state = state.agent_execution_state
|
|
79
|
+
c_state = state.conversational_state
|
|
80
|
+
|
|
81
|
+
lines = [
|
|
82
|
+
f"# Handoff | PrevAgent: {exec_state.model_name}",
|
|
83
|
+
"! RULE: Physical reality overrides chat claims. Tests define ground truth.",
|
|
84
|
+
"",
|
|
85
|
+
"## In-Flight Tasks",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
if exec_state.active_tasks:
|
|
89
|
+
for t in exec_state.active_tasks:
|
|
90
|
+
files = f" files={','.join(t.target_files)}" if t.target_files else ""
|
|
91
|
+
lines.append(f"- [{t.status.value}] {t.title} ({t.id}){files}")
|
|
92
|
+
else:
|
|
93
|
+
lines.append("- (none)")
|
|
94
|
+
|
|
95
|
+
lines.extend([
|
|
96
|
+
"",
|
|
97
|
+
"## Next Action",
|
|
98
|
+
])
|
|
99
|
+
|
|
100
|
+
if exec_state.next_action:
|
|
101
|
+
na = exec_state.next_action
|
|
102
|
+
lines.append(f"- Action: {na.action_type} | Target: {na.target_uri}")
|
|
103
|
+
lines.append(f" Note: {na.description}")
|
|
104
|
+
else:
|
|
105
|
+
lines.append("- Action: Continue incomplete components.")
|
|
106
|
+
|
|
107
|
+
lines.extend([
|
|
108
|
+
"",
|
|
109
|
+
"## Blockers & Discrepancies",
|
|
110
|
+
])
|
|
111
|
+
|
|
112
|
+
active_contra = self._extract_active_contradictions(state)
|
|
113
|
+
if active_contra:
|
|
114
|
+
for c in active_contra:
|
|
115
|
+
lines.append(f"- BLOCKER [{c['severity']}]: {c['explanation']}")
|
|
116
|
+
else:
|
|
117
|
+
lines.append("- (none)")
|
|
118
|
+
|
|
119
|
+
lines.extend([
|
|
120
|
+
"",
|
|
121
|
+
"## Unverified Claims",
|
|
122
|
+
])
|
|
123
|
+
|
|
124
|
+
if c_state.agent_claims:
|
|
125
|
+
for cl in c_state.agent_claims:
|
|
126
|
+
lines.append(f"- Claim: \"{cl.claim_text}\" (Agent:{cl.source_agent})")
|
|
127
|
+
else:
|
|
128
|
+
lines.append("- (none)")
|
|
129
|
+
|
|
130
|
+
return "\n".join(lines)
|