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.
Files changed (72) hide show
  1. cli/__init__.py +12 -0
  2. cli/main.py +415 -0
  3. confidence/__init__.py +13 -0
  4. confidence/calculator.py +308 -0
  5. confidence/models.py +40 -0
  6. context/__init__.py +17 -0
  7. context/models.py +108 -0
  8. context/pruner.py +228 -0
  9. context/selector.py +193 -0
  10. continuum_toolkit-1.0.0.dist-info/METADATA +511 -0
  11. continuum_toolkit-1.0.0.dist-info/RECORD +72 -0
  12. continuum_toolkit-1.0.0.dist-info/WHEEL +5 -0
  13. continuum_toolkit-1.0.0.dist-info/entry_points.txt +2 -0
  14. continuum_toolkit-1.0.0.dist-info/licenses/LICENSE +21 -0
  15. continuum_toolkit-1.0.0.dist-info/top_level.txt +13 -0
  16. contradictions/__init__.py +19 -0
  17. contradictions/detector.py +442 -0
  18. contradictions/models.py +75 -0
  19. core/__init__.py +97 -0
  20. core/enums.py +130 -0
  21. core/evidence.py +117 -0
  22. core/interfaces.py +209 -0
  23. core/schema.py +391 -0
  24. core/serializer.py +84 -0
  25. core/state_models.py +530 -0
  26. daemon/__init__.py +12 -0
  27. daemon/service.py +170 -0
  28. extractors/__init__.py +51 -0
  29. extractors/base.py +117 -0
  30. extractors/config/parsers.py +288 -0
  31. extractors/config/secret_sanitizer.py +91 -0
  32. extractors/config_extractor.py +172 -0
  33. extractors/conversation/analyzers.py +193 -0
  34. extractors/conversation/models.py +148 -0
  35. extractors/conversation_extractor.py +166 -0
  36. extractors/git_extractor.py +305 -0
  37. extractors/parsers/base.py +91 -0
  38. extractors/parsers/comment_parser.py +51 -0
  39. extractors/parsers/js_ts_parser.py +171 -0
  40. extractors/parsers/python_parser.py +180 -0
  41. extractors/verification/runners.py +278 -0
  42. extractors/verification_extractor.py +263 -0
  43. extractors/workspace_extractor.py +221 -0
  44. graph/__init__.py +24 -0
  45. graph/diff.py +109 -0
  46. graph/manager.py +473 -0
  47. graph/models.py +62 -0
  48. graph/propagator.py +194 -0
  49. graph/query.py +86 -0
  50. graph/snapshot.py +85 -0
  51. handoff/__init__.py +28 -0
  52. handoff/adapters/__init__.py +45 -0
  53. handoff/adapters/base.py +90 -0
  54. handoff/adapters/claude_adapter.py +176 -0
  55. handoff/adapters/codex_gpt_adapter.py +151 -0
  56. handoff/adapters/gemini_adapter.py +151 -0
  57. handoff/adapters/local_model_adapter.py +130 -0
  58. handoff/models.py +88 -0
  59. handoff/packager.py +288 -0
  60. pipeline/__init__.py +9 -0
  61. pipeline/orchestrator.py +260 -0
  62. resolution/__init__.py +15 -0
  63. resolution/resolver.py +311 -0
  64. storage/__init__.py +18 -0
  65. storage/hooks.py +125 -0
  66. storage/manager.py +127 -0
  67. storage/models.py +39 -0
  68. storage/recovery.py +98 -0
  69. watcher/__init__.py +17 -0
  70. watcher/detector.py +136 -0
  71. watcher/models.py +62 -0
  72. 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)