hegelion 0.4.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.
- hegelion/__init__.py +45 -0
- hegelion/core/__init__.py +29 -0
- hegelion/core/agent.py +166 -0
- hegelion/core/autocoding_state.py +293 -0
- hegelion/core/backends.py +442 -0
- hegelion/core/cache.py +92 -0
- hegelion/core/config.py +276 -0
- hegelion/core/core.py +649 -0
- hegelion/core/engine.py +865 -0
- hegelion/core/logging_utils.py +67 -0
- hegelion/core/models.py +293 -0
- hegelion/core/parsing.py +271 -0
- hegelion/core/personas.py +81 -0
- hegelion/core/prompt_autocoding.py +353 -0
- hegelion/core/prompt_dialectic.py +414 -0
- hegelion/core/prompts.py +127 -0
- hegelion/core/schema.py +67 -0
- hegelion/core/validation.py +68 -0
- hegelion/council.py +254 -0
- hegelion/examples_data/__init__.py +6 -0
- hegelion/examples_data/glm4_6_examples.jsonl +2 -0
- hegelion/judge.py +230 -0
- hegelion/mcp/__init__.py +3 -0
- hegelion/mcp/server.py +918 -0
- hegelion/scripts/hegelion_agent_cli.py +90 -0
- hegelion/scripts/hegelion_bench.py +117 -0
- hegelion/scripts/hegelion_cli.py +497 -0
- hegelion/scripts/hegelion_dataset.py +99 -0
- hegelion/scripts/hegelion_eval.py +137 -0
- hegelion/scripts/mcp_setup.py +150 -0
- hegelion/search_providers.py +151 -0
- hegelion/training/__init__.py +7 -0
- hegelion/training/datasets.py +123 -0
- hegelion/training/generator.py +232 -0
- hegelion/training/mlx_scu_trainer.py +379 -0
- hegelion/training/mlx_trainer.py +181 -0
- hegelion/training/unsloth_trainer.py +136 -0
- hegelion-0.4.0.dist-info/METADATA +295 -0
- hegelion-0.4.0.dist-info/RECORD +43 -0
- hegelion-0.4.0.dist-info/WHEEL +5 -0
- hegelion-0.4.0.dist-info/entry_points.txt +8 -0
- hegelion-0.4.0.dist-info/licenses/LICENSE +21 -0
- hegelion-0.4.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""Prompt-driven dialectical reasoning for any LLM via MCP.
|
|
2
|
+
|
|
3
|
+
This module provides a way to run dialectical reasoning without making external API calls.
|
|
4
|
+
Instead, it returns structured prompts that guide the calling LLM through the process.
|
|
5
|
+
Perfect for Cursor, Claude Desktop, or any MCP-compatible environment.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Dict, List, Optional, Any
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class DialecticalPrompt:
|
|
16
|
+
"""A structured prompt for dialectical reasoning."""
|
|
17
|
+
|
|
18
|
+
phase: str
|
|
19
|
+
prompt: str
|
|
20
|
+
instructions: str
|
|
21
|
+
expected_format: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PromptDrivenDialectic:
|
|
25
|
+
"""Orchestrates dialectical reasoning using prompts instead of API calls."""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self.conversation_state = {}
|
|
29
|
+
|
|
30
|
+
def generate_thesis_prompt(self, query: str) -> DialecticalPrompt:
|
|
31
|
+
"""Generate a prompt for the thesis phase."""
|
|
32
|
+
return DialecticalPrompt(
|
|
33
|
+
phase="thesis",
|
|
34
|
+
prompt=f"""You are in the THESIS phase of Hegelian dialectical reasoning.
|
|
35
|
+
|
|
36
|
+
QUERY: {query}
|
|
37
|
+
|
|
38
|
+
Your task:
|
|
39
|
+
1. Provide a comprehensive, well-reasoned initial position on this query
|
|
40
|
+
2. Consider multiple perspectives and build a strong foundational argument
|
|
41
|
+
3. Be thorough but clear in your reasoning
|
|
42
|
+
4. Acknowledge uncertainty where appropriate
|
|
43
|
+
5. Think step by step, then present a polished thesis
|
|
44
|
+
|
|
45
|
+
Generate your THESIS response now.""",
|
|
46
|
+
instructions="Respond with a clear, well-structured thesis that establishes your initial position on the query.",
|
|
47
|
+
expected_format="Free-form text thesis response",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def generate_antithesis_prompt(
|
|
51
|
+
self, query: str, thesis: str, use_search_context: bool = False
|
|
52
|
+
) -> DialecticalPrompt:
|
|
53
|
+
"""Generate a prompt for the antithesis phase."""
|
|
54
|
+
|
|
55
|
+
search_instruction = ""
|
|
56
|
+
if use_search_context:
|
|
57
|
+
search_instruction = """
|
|
58
|
+
IMPORTANT: Before critiquing, use available search tools to find current information about this topic. Ground your critique in real-world evidence and recent developments."""
|
|
59
|
+
|
|
60
|
+
return DialecticalPrompt(
|
|
61
|
+
phase="antithesis",
|
|
62
|
+
prompt=f"""You are in the ANTITHESIS phase of Hegelian dialectical reasoning.
|
|
63
|
+
|
|
64
|
+
ORIGINAL QUERY: {query}
|
|
65
|
+
|
|
66
|
+
THESIS TO CRITIQUE: {thesis}
|
|
67
|
+
{search_instruction}
|
|
68
|
+
|
|
69
|
+
Your task as the critical voice:
|
|
70
|
+
1. Find contradictions, inconsistencies, or logical gaps in the thesis
|
|
71
|
+
2. Identify unexamined assumptions and hidden premises
|
|
72
|
+
3. Propose alternative framings that challenge the thesis
|
|
73
|
+
4. Find edge cases or scenarios where the thesis breaks down
|
|
74
|
+
5. Be adversarial but intellectually honest
|
|
75
|
+
|
|
76
|
+
For each significant problem you identify, use this EXACT format:
|
|
77
|
+
CONTRADICTION: [brief description]
|
|
78
|
+
EVIDENCE: [detailed explanation of why this is problematic]
|
|
79
|
+
|
|
80
|
+
Generate your ANTITHESIS critique now.""",
|
|
81
|
+
instructions="Respond with a rigorous critique that identifies specific contradictions and weaknesses in the thesis.",
|
|
82
|
+
expected_format="Text with embedded CONTRADICTION: and EVIDENCE: sections",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def generate_council_prompts(self, query: str, thesis: str) -> List[DialecticalPrompt]:
|
|
86
|
+
"""Generate prompts for multi-perspective council critique."""
|
|
87
|
+
|
|
88
|
+
council_members = [
|
|
89
|
+
{
|
|
90
|
+
"name": "The Logician",
|
|
91
|
+
"expertise": "Logical consistency and formal reasoning",
|
|
92
|
+
"focus": "logical fallacies, internal contradictions, invalid inferences, missing premises",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "The Empiricist",
|
|
96
|
+
"expertise": "Evidence, facts, and empirical grounding",
|
|
97
|
+
"focus": "factual errors, unsupported claims, missing evidence, contradictions with established science",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "The Ethicist",
|
|
101
|
+
"expertise": "Ethical implications and societal impact",
|
|
102
|
+
"focus": "potential harm, ethical blind spots, fairness issues, unintended consequences",
|
|
103
|
+
},
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
prompts = []
|
|
107
|
+
for member in council_members:
|
|
108
|
+
prompt = DialecticalPrompt(
|
|
109
|
+
phase=f"council_{member['name'].lower().replace(' ', '_')}",
|
|
110
|
+
prompt=f"""You are {member['name'].upper()}, an expert in {member['expertise']}.
|
|
111
|
+
|
|
112
|
+
ORIGINAL QUERY: {query}
|
|
113
|
+
|
|
114
|
+
THESIS TO CRITIQUE: {thesis}
|
|
115
|
+
|
|
116
|
+
Your expertise: {member['expertise']}
|
|
117
|
+
Focus specifically on: {member['focus']}
|
|
118
|
+
|
|
119
|
+
Examine the thesis from your specialized perspective and identify problems within your domain.
|
|
120
|
+
|
|
121
|
+
For each issue you identify, use this format:
|
|
122
|
+
CONTRADICTION: [brief description]
|
|
123
|
+
EVIDENCE: [detailed explanation from your expert perspective]
|
|
124
|
+
|
|
125
|
+
Generate your specialized critique now.""",
|
|
126
|
+
instructions=f"Respond as {member['name']} with critiques specific to {member['expertise']}",
|
|
127
|
+
expected_format="Text with embedded CONTRADICTION: and EVIDENCE: sections",
|
|
128
|
+
)
|
|
129
|
+
prompts.append(prompt)
|
|
130
|
+
|
|
131
|
+
return prompts
|
|
132
|
+
|
|
133
|
+
def generate_synthesis_prompt(
|
|
134
|
+
self,
|
|
135
|
+
query: str,
|
|
136
|
+
thesis: str,
|
|
137
|
+
antithesis: str,
|
|
138
|
+
contradictions: Optional[List[str]] = None,
|
|
139
|
+
) -> DialecticalPrompt:
|
|
140
|
+
"""Generate a prompt for the synthesis phase."""
|
|
141
|
+
|
|
142
|
+
contradictions_text = ""
|
|
143
|
+
if contradictions:
|
|
144
|
+
contradictions_text = f"""
|
|
145
|
+
|
|
146
|
+
IDENTIFIED CONTRADICTIONS:
|
|
147
|
+
{chr(10).join(f"- {contradiction}" for contradiction in contradictions)}"""
|
|
148
|
+
|
|
149
|
+
return DialecticalPrompt(
|
|
150
|
+
phase="synthesis",
|
|
151
|
+
prompt=f"""You are in the SYNTHESIS phase of Hegelian dialectical reasoning.
|
|
152
|
+
|
|
153
|
+
ORIGINAL QUERY: {query}
|
|
154
|
+
|
|
155
|
+
THESIS: {thesis}
|
|
156
|
+
|
|
157
|
+
ANTITHESIS (critique): {antithesis}
|
|
158
|
+
{contradictions_text}
|
|
159
|
+
|
|
160
|
+
Your task:
|
|
161
|
+
1. Generate a SYNTHESIS that TRANSCENDS both thesis and antithesis
|
|
162
|
+
2. Resolve or reframe the contradictions by finding a higher-level perspective
|
|
163
|
+
3. Make predictions that NEITHER thesis nor antithesis would make alone
|
|
164
|
+
4. Ensure your synthesis is testable or falsifiable when possible
|
|
165
|
+
5. Propose research directions or experiments if appropriate
|
|
166
|
+
|
|
167
|
+
Requirements for a valid SYNTHESIS:
|
|
168
|
+
- Must not simply say "the thesis is right" or "the antithesis is right"
|
|
169
|
+
- Must not just say "both have merit"
|
|
170
|
+
- Must offer a genuinely novel perspective
|
|
171
|
+
- Should be more sophisticated than either original position
|
|
172
|
+
|
|
173
|
+
If the synthesis suggests new research, use this format:
|
|
174
|
+
RESEARCH_PROPOSAL: [brief description]
|
|
175
|
+
TESTABLE_PREDICTION: [specific falsifiable claim]
|
|
176
|
+
|
|
177
|
+
Generate your SYNTHESIS now.""",
|
|
178
|
+
instructions="Respond with a synthesis that transcends both positions and offers novel insights",
|
|
179
|
+
expected_format="Text with optional RESEARCH_PROPOSAL: and TESTABLE_PREDICTION: sections",
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def generate_judge_prompt(
|
|
183
|
+
self, query: str, thesis: str, antithesis: str, synthesis: str
|
|
184
|
+
) -> DialecticalPrompt:
|
|
185
|
+
"""Generate a prompt for quality evaluation."""
|
|
186
|
+
|
|
187
|
+
return DialecticalPrompt(
|
|
188
|
+
phase="judge",
|
|
189
|
+
prompt=f"""You are the Iron Judge, evaluating dialectical reasoning quality.
|
|
190
|
+
|
|
191
|
+
ORIGINAL QUERY: {query}
|
|
192
|
+
THESIS: {thesis}
|
|
193
|
+
ANTITHESIS: {antithesis}
|
|
194
|
+
SYNTHESIS: {synthesis}
|
|
195
|
+
|
|
196
|
+
Evaluate this dialectical process on:
|
|
197
|
+
|
|
198
|
+
1. **Thesis Quality** (0-2 points): Is the initial position well-reasoned?
|
|
199
|
+
2. **Antithesis Rigor** (0-3 points): Does the critique identify genuine problems?
|
|
200
|
+
3. **Synthesis Innovation** (0-3 points): Does the synthesis transcend both positions?
|
|
201
|
+
4. **Critique Validity** (0-2 points): Were critiques actually addressed?
|
|
202
|
+
|
|
203
|
+
Score criteria:
|
|
204
|
+
- 0-3: Poor quality, major logical flaws
|
|
205
|
+
- 4-5: Below average, some good elements but significant issues
|
|
206
|
+
- 6-7: Good quality, solid reasoning with minor gaps
|
|
207
|
+
- 8-9: Excellent, sophisticated analysis with minimal flaws
|
|
208
|
+
- 10: Outstanding, exemplary dialectical reasoning
|
|
209
|
+
|
|
210
|
+
Respond with EXACTLY this format:
|
|
211
|
+
SCORE: [integer 0-10]
|
|
212
|
+
CRITIQUE_VALIDITY: [true/false]
|
|
213
|
+
REASONING: [detailed explanation]
|
|
214
|
+
STRENGTHS: [specific areas of excellence]
|
|
215
|
+
IMPROVEMENTS: [specific areas needing work]""",
|
|
216
|
+
instructions="Evaluate the dialectical quality and provide structured feedback",
|
|
217
|
+
expected_format="Structured response with SCORE:, CRITIQUE_VALIDITY:, REASONING:, STRENGTHS:, IMPROVEMENTS:",
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def create_dialectical_workflow(
|
|
222
|
+
query: str,
|
|
223
|
+
use_search: bool = False,
|
|
224
|
+
use_council: bool = False,
|
|
225
|
+
use_judge: bool = False,
|
|
226
|
+
) -> Dict[str, Any]:
|
|
227
|
+
"""Create a complete dialectical workflow as structured prompts.
|
|
228
|
+
|
|
229
|
+
Returns a workflow that can be executed by any LLM via MCP.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
dialectic = PromptDrivenDialectic()
|
|
233
|
+
workflow = {"query": query, "workflow_type": "prompt_driven_dialectic", "steps": []}
|
|
234
|
+
|
|
235
|
+
# Step 1: Thesis
|
|
236
|
+
workflow["steps"].append(
|
|
237
|
+
{
|
|
238
|
+
"step": 1,
|
|
239
|
+
"name": "Generate Thesis",
|
|
240
|
+
"prompt": dialectic.generate_thesis_prompt(query).__dict__,
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Step 2: Antithesis (standard or council-based)
|
|
245
|
+
if use_council:
|
|
246
|
+
council_prompts = dialectic.generate_council_prompts(query, "{{thesis_from_step_1}}")
|
|
247
|
+
antithesis_refs = []
|
|
248
|
+
for i, council_prompt in enumerate(council_prompts):
|
|
249
|
+
step_num = 2 + i
|
|
250
|
+
workflow["steps"].append(
|
|
251
|
+
{
|
|
252
|
+
"step": step_num,
|
|
253
|
+
"name": f"Council Critique: {council_prompt.phase}",
|
|
254
|
+
"prompt": council_prompt.__dict__,
|
|
255
|
+
}
|
|
256
|
+
)
|
|
257
|
+
antithesis_refs.append(
|
|
258
|
+
f"### {council_prompt.phase.replace('_', ' ').title()}\n{{{{{council_prompt.phase}_from_step_{step_num}}}}}"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
antithesis_step = 2 + len(council_prompts)
|
|
262
|
+
antithesis_output_ref = "\n\n".join(antithesis_refs)
|
|
263
|
+
else:
|
|
264
|
+
workflow["steps"].append(
|
|
265
|
+
{
|
|
266
|
+
"step": 2,
|
|
267
|
+
"name": "Generate Antithesis",
|
|
268
|
+
"prompt": dialectic.generate_antithesis_prompt(
|
|
269
|
+
query, "{{thesis_from_step_1}}", use_search
|
|
270
|
+
).__dict__,
|
|
271
|
+
}
|
|
272
|
+
)
|
|
273
|
+
antithesis_step = 3
|
|
274
|
+
antithesis_output_ref = "{{antithesis_from_step_2}}"
|
|
275
|
+
|
|
276
|
+
# Step 3: Synthesis
|
|
277
|
+
workflow["steps"].append(
|
|
278
|
+
{
|
|
279
|
+
"step": antithesis_step,
|
|
280
|
+
"name": "Generate Synthesis",
|
|
281
|
+
"prompt": dialectic.generate_synthesis_prompt(
|
|
282
|
+
query, "{{thesis_from_step_1}}", antithesis_output_ref
|
|
283
|
+
).__dict__,
|
|
284
|
+
}
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# Step 4: Judge (optional)
|
|
288
|
+
if use_judge:
|
|
289
|
+
workflow["steps"].append(
|
|
290
|
+
{
|
|
291
|
+
"step": antithesis_step + 1,
|
|
292
|
+
"name": "Evaluate Quality",
|
|
293
|
+
"prompt": dialectic.generate_judge_prompt(
|
|
294
|
+
query,
|
|
295
|
+
"{{thesis_from_step_1}}",
|
|
296
|
+
antithesis_output_ref,
|
|
297
|
+
f"{{synthesis_from_step_{antithesis_step}}}",
|
|
298
|
+
).__dict__,
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
workflow["instructions"] = {
|
|
303
|
+
"execution_mode": "sequential",
|
|
304
|
+
"description": "Execute each step in order, using outputs from previous steps as inputs to later steps",
|
|
305
|
+
"variable_substitution": "Replace {{variable_name}} with actual outputs from previous steps",
|
|
306
|
+
"final_output": "Combine all outputs into a structured HegelionResult",
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return workflow
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def create_single_shot_dialectic_prompt(
|
|
313
|
+
query: str,
|
|
314
|
+
use_search: bool = False,
|
|
315
|
+
use_council: bool = False,
|
|
316
|
+
response_style: str = "sections",
|
|
317
|
+
) -> str:
|
|
318
|
+
"""Create a single comprehensive prompt for dialectical reasoning.
|
|
319
|
+
|
|
320
|
+
This is for models that can handle complex multi-step reasoning in one go.
|
|
321
|
+
"""
|
|
322
|
+
|
|
323
|
+
search_instruction = ""
|
|
324
|
+
if use_search:
|
|
325
|
+
search_instruction = """
|
|
326
|
+
Before beginning, use available search tools to gather current information about this topic."""
|
|
327
|
+
|
|
328
|
+
council_instruction = ""
|
|
329
|
+
if use_council:
|
|
330
|
+
council_instruction = """
|
|
331
|
+
For the ANTITHESIS phase, adopt three distinct critical perspectives:
|
|
332
|
+
- THE LOGICIAN: Focus on logical consistency and formal reasoning
|
|
333
|
+
- THE EMPIRICIST: Focus on evidence, facts, and empirical grounding
|
|
334
|
+
- THE ETHICIST: Focus on ethical implications and societal impact
|
|
335
|
+
|
|
336
|
+
Generate critiques from each perspective, then synthesize them."""
|
|
337
|
+
if response_style == "json":
|
|
338
|
+
output_instructions = f"""Return ONLY a JSON object with this shape:
|
|
339
|
+
{{
|
|
340
|
+
"query": "{query}",
|
|
341
|
+
"thesis": "...",
|
|
342
|
+
"antithesis": "...",
|
|
343
|
+
"synthesis": "...",
|
|
344
|
+
"contradictions": [
|
|
345
|
+
{{"description": "...", "evidence": "..."}}
|
|
346
|
+
],
|
|
347
|
+
"research_proposals": [
|
|
348
|
+
{{"proposal": "...", "testable_prediction": "..."}}
|
|
349
|
+
]
|
|
350
|
+
}}
|
|
351
|
+
No markdown, no commentary outside the JSON."""
|
|
352
|
+
elif response_style == "synthesis_only":
|
|
353
|
+
output_instructions = """Return ONLY the SYNTHESIS as 2-3 tight paragraphs. Do not include thesis, antithesis, headings, or lists."""
|
|
354
|
+
elif response_style == "conversational":
|
|
355
|
+
output_instructions = """Adopt a natural, conversational tone. Present the dialectical analysis as if you are a thoughtful colleague explaining your reasoning.
|
|
356
|
+
|
|
357
|
+
Structure:
|
|
358
|
+
1. Start with your initial thoughts (Thesis)
|
|
359
|
+
2. Then, "but on the other hand..." (Antithesis)
|
|
360
|
+
3. Finally, "so perhaps the best way forward is..." (Synthesis)
|
|
361
|
+
|
|
362
|
+
Avoid rigid headings like ## THESIS. Use natural transitions."""
|
|
363
|
+
elif response_style == "bullet_points":
|
|
364
|
+
output_instructions = """Format the response as a concise set of bullet points.
|
|
365
|
+
|
|
366
|
+
* **Thesis**: [Key point]
|
|
367
|
+
* **Antithesis**: [Key counter-point]
|
|
368
|
+
* **Synthesis**: [Resolution]
|
|
369
|
+
|
|
370
|
+
Keep it brief and scannable."""
|
|
371
|
+
else:
|
|
372
|
+
output_instructions = f"""Structure your complete response as:
|
|
373
|
+
|
|
374
|
+
# DIALECTICAL ANALYSIS: {query}
|
|
375
|
+
|
|
376
|
+
## THESIS
|
|
377
|
+
[Your initial position]
|
|
378
|
+
|
|
379
|
+
## ANTITHESIS
|
|
380
|
+
[Your critical examination]
|
|
381
|
+
|
|
382
|
+
## SYNTHESIS
|
|
383
|
+
[Your transcendent resolution]
|
|
384
|
+
|
|
385
|
+
## CONTRADICTIONS IDENTIFIED
|
|
386
|
+
1. [Contradiction 1]: [Evidence]
|
|
387
|
+
2. [Contradiction 2]: [Evidence]
|
|
388
|
+
|
|
389
|
+
## RESEARCH PROPOSALS
|
|
390
|
+
1. [Proposal 1]: [Testable prediction]"""
|
|
391
|
+
|
|
392
|
+
return f"""You will now perform Hegelian dialectical reasoning on the following query using a three-phase process: THESIS → ANTITHESIS → SYNTHESIS.
|
|
393
|
+
{search_instruction}
|
|
394
|
+
|
|
395
|
+
QUERY: {query}
|
|
396
|
+
|
|
397
|
+
Execute the following phases:
|
|
398
|
+
|
|
399
|
+
**PHASE 1 - THESIS:**
|
|
400
|
+
Generate a comprehensive initial position on the query. Be thorough, well-reasoned, and consider multiple perspectives while establishing your foundational argument.
|
|
401
|
+
|
|
402
|
+
**PHASE 2 - ANTITHESIS:**{council_instruction}
|
|
403
|
+
Critically examine your thesis. Find contradictions, logical gaps, unexamined assumptions, and alternative framings. For each problem, use:
|
|
404
|
+
CONTRADICTION: [description]
|
|
405
|
+
EVIDENCE: [explanation]
|
|
406
|
+
|
|
407
|
+
**PHASE 3 - SYNTHESIS:**
|
|
408
|
+
Transcend both thesis and antithesis with a novel perspective that resolves the contradictions. Make predictions neither position would make alone. Include research proposals if appropriate:
|
|
409
|
+
RESEARCH_PROPOSAL: [description]
|
|
410
|
+
TESTABLE_PREDICTION: [falsifiable claim]
|
|
411
|
+
|
|
412
|
+
{output_instructions}
|
|
413
|
+
|
|
414
|
+
Begin your dialectical analysis now."""
|
hegelion/core/prompts.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""Prompt templates for the Hegelion dialectical phases."""
|
|
2
|
+
|
|
3
|
+
THESIS_PROMPT = """You are in the THESIS phase of Hegelian dialectical reasoning.
|
|
4
|
+
|
|
5
|
+
Original question:
|
|
6
|
+
{query}
|
|
7
|
+
|
|
8
|
+
Your task:
|
|
9
|
+
1. Provide a comprehensive, well-reasoned answer.
|
|
10
|
+
2. Consider multiple perspectives.
|
|
11
|
+
3. Be thorough but clear.
|
|
12
|
+
4. Acknowledge uncertainty where appropriate.
|
|
13
|
+
5. Think step by step, then present a polished answer.
|
|
14
|
+
|
|
15
|
+
Now produce your THESIS answer.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
ANTITHESIS_PROMPT = """You are in the ANTITHESIS phase of Hegelian dialectical reasoning.
|
|
19
|
+
|
|
20
|
+
Original question:
|
|
21
|
+
{query}
|
|
22
|
+
|
|
23
|
+
Thesis answer:
|
|
24
|
+
{thesis}
|
|
25
|
+
{search_instruction}
|
|
26
|
+
|
|
27
|
+
Your task:
|
|
28
|
+
1. Find contradictions, inconsistencies, or logical gaps in the thesis.
|
|
29
|
+
2. Identify unexamined assumptions.
|
|
30
|
+
3. Propose alternative framings that challenge the thesis.
|
|
31
|
+
4. Find edge cases or scenarios where the thesis breaks down.
|
|
32
|
+
5. Be adversarial but intellectually honest.
|
|
33
|
+
|
|
34
|
+
For each contradiction, use this format exactly:
|
|
35
|
+
CONTRADICTION: [brief description]
|
|
36
|
+
EVIDENCE: [why this is problematic]
|
|
37
|
+
|
|
38
|
+
Now produce your ANTITHESIS critique.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
PERSONA_ANTITHESIS_PROMPT = """You are {persona_name}.
|
|
42
|
+
{persona_description}
|
|
43
|
+
|
|
44
|
+
Original question:
|
|
45
|
+
{query}
|
|
46
|
+
|
|
47
|
+
Thesis answer:
|
|
48
|
+
{thesis}
|
|
49
|
+
{search_instruction}
|
|
50
|
+
|
|
51
|
+
Your expertise: {persona_focus}
|
|
52
|
+
Your instructions: {persona_instructions}
|
|
53
|
+
|
|
54
|
+
Examine the thesis from your specialized perspective. Identify problems within your domain.
|
|
55
|
+
|
|
56
|
+
For each issue you identify, use this format:
|
|
57
|
+
CONTRADICTION: [brief description]
|
|
58
|
+
EVIDENCE: [detailed explanation from your expert perspective]
|
|
59
|
+
|
|
60
|
+
Generate your specialized critique now.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
SYNTHESIS_PROMPT = """You are in the SYNTHESIS phase of Hegelian dialectical reasoning.
|
|
64
|
+
|
|
65
|
+
Original question:
|
|
66
|
+
{query}
|
|
67
|
+
|
|
68
|
+
Thesis:
|
|
69
|
+
{thesis}
|
|
70
|
+
|
|
71
|
+
Antithesis (critique):
|
|
72
|
+
{antithesis}
|
|
73
|
+
|
|
74
|
+
Identified contradictions:
|
|
75
|
+
{contradictions}
|
|
76
|
+
|
|
77
|
+
Your task:
|
|
78
|
+
1. Generate a SYNTHESIS that TRANSCENDS both thesis and antithesis.
|
|
79
|
+
2. Resolve or reframe the contradictions by finding a higher-level perspective.
|
|
80
|
+
3. Make predictions that NEITHER thesis nor antithesis would make alone.
|
|
81
|
+
4. Ensure your synthesis is testable or falsifiable when possible.
|
|
82
|
+
5. If appropriate, propose a research direction or experiment.
|
|
83
|
+
|
|
84
|
+
Requirements for a valid SYNTHESIS:
|
|
85
|
+
- Must not simply say "the thesis is right" or "the antithesis is right".
|
|
86
|
+
- Must not just say "both have merit".
|
|
87
|
+
- Must offer a genuinely novel perspective.
|
|
88
|
+
- Should be more sophisticated than either original position.
|
|
89
|
+
|
|
90
|
+
If the synthesis suggests new research, use this format:
|
|
91
|
+
RESEARCH_PROPOSAL: [brief description]
|
|
92
|
+
TESTABLE_PREDICTION: [specific falsifiable claim]
|
|
93
|
+
|
|
94
|
+
Now produce your SYNTHESIS.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
MULTI_PERSPECTIVE_SYNTHESIS_PROMPT = """You are in the SYNTHESIS phase of Hegelian dialectical reasoning.
|
|
98
|
+
|
|
99
|
+
Original question:
|
|
100
|
+
{query}
|
|
101
|
+
|
|
102
|
+
Thesis:
|
|
103
|
+
{thesis}
|
|
104
|
+
|
|
105
|
+
CRITIQUES (Multiple Perspectives):
|
|
106
|
+
{antithesis}
|
|
107
|
+
|
|
108
|
+
Identified contradictions:
|
|
109
|
+
{contradictions}
|
|
110
|
+
|
|
111
|
+
Your task:
|
|
112
|
+
1. Synthesize the thesis with ALL the critiques provided above.
|
|
113
|
+
2. Resolve the tensions between the initial position and the various critical perspectives.
|
|
114
|
+
3. Find a higher-level perspective that satisfies the valid points raised by all critics.
|
|
115
|
+
4. Make predictions that transcend the initial debate.
|
|
116
|
+
|
|
117
|
+
Requirements for a valid SYNTHESIS:
|
|
118
|
+
- Must not simply say "everyone is right".
|
|
119
|
+
- Must offer a genuinely novel perspective that integrates these diverse viewpoints.
|
|
120
|
+
- Should be more sophisticated than any single position.
|
|
121
|
+
|
|
122
|
+
If the synthesis suggests new research, use this format:
|
|
123
|
+
RESEARCH_PROPOSAL: [brief description]
|
|
124
|
+
TESTABLE_PREDICTION: [specific falsifiable claim]
|
|
125
|
+
|
|
126
|
+
Now produce your SYNTHESIS.
|
|
127
|
+
"""
|
hegelion/core/schema.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""JSON Schemas for Hegelion outputs."""
|
|
2
|
+
|
|
3
|
+
HEGELION_RESULT_SCHEMA = {
|
|
4
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
5
|
+
"title": "HegelionResult",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"query",
|
|
9
|
+
"thesis",
|
|
10
|
+
"antithesis",
|
|
11
|
+
"synthesis",
|
|
12
|
+
],
|
|
13
|
+
"properties": {
|
|
14
|
+
"query": {"type": "string"},
|
|
15
|
+
"mode": {"type": "string"},
|
|
16
|
+
"thesis": {"type": "string"},
|
|
17
|
+
"antithesis": {"type": "string"},
|
|
18
|
+
"synthesis": {"type": "string"},
|
|
19
|
+
"timestamp": {"type": ["string", "null"]},
|
|
20
|
+
"validation_score": {"type": ["number", "null"]},
|
|
21
|
+
"contradictions": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": ["description"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"description": {"type": "string"},
|
|
28
|
+
"evidence": {"type": "string"},
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": False,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
"research_proposals": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"items": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"required": ["description"],
|
|
38
|
+
"properties": {
|
|
39
|
+
"description": {"type": "string"},
|
|
40
|
+
"testable_prediction": {"type": "string"},
|
|
41
|
+
},
|
|
42
|
+
"additionalProperties": False,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
"metadata": {
|
|
46
|
+
"type": ["object", "null"],
|
|
47
|
+
"required": [
|
|
48
|
+
"thesis_time_ms",
|
|
49
|
+
"antithesis_time_ms",
|
|
50
|
+
"synthesis_time_ms",
|
|
51
|
+
"total_time_ms",
|
|
52
|
+
],
|
|
53
|
+
"properties": {
|
|
54
|
+
"thesis_time_ms": {"type": "number"},
|
|
55
|
+
"antithesis_time_ms": {"type": "number"},
|
|
56
|
+
"synthesis_time_ms": {"type": ["number", "null"]},
|
|
57
|
+
"total_time_ms": {"type": "number"},
|
|
58
|
+
"backend_provider": {"type": ["string", "null"]},
|
|
59
|
+
"backend_model": {"type": ["string", "null"]},
|
|
60
|
+
"debug": {"type": "object"},
|
|
61
|
+
"errors": {"type": "array"},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
"trace": {"type": ["object", "null"]},
|
|
65
|
+
},
|
|
66
|
+
"additionalProperties": False,
|
|
67
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Runtime validation helpers for Hegelion outputs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Union
|
|
6
|
+
|
|
7
|
+
from jsonschema import validate
|
|
8
|
+
from jsonschema.exceptions import ValidationError as JsonSchemaValidationError
|
|
9
|
+
|
|
10
|
+
from .models import HegelionResult, ValidationError
|
|
11
|
+
from .schema import HEGELION_RESULT_SCHEMA
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ResultValidationError(ValidationError, RuntimeError):
|
|
15
|
+
"""Raised when a result fails schema validation."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, message: str, original: JsonSchemaValidationError) -> None:
|
|
18
|
+
self.original = original
|
|
19
|
+
super().__init__(message)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def validate_hegelion_result(result: Union[HegelionResult, Dict[str, Any]]) -> None:
|
|
23
|
+
"""Validate a HegelionResult against the public schema."""
|
|
24
|
+
if hasattr(result, "to_dict"):
|
|
25
|
+
payload: Dict[str, Any] = result.to_dict()
|
|
26
|
+
else:
|
|
27
|
+
payload = result
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
validate(instance=payload, schema=HEGELION_RESULT_SCHEMA)
|
|
31
|
+
except JsonSchemaValidationError as exc: # pragma: no cover - defensive
|
|
32
|
+
msg = exc.message
|
|
33
|
+
field = ""
|
|
34
|
+
if exc.path:
|
|
35
|
+
field = f"Field '{exc.path[-1]}': "
|
|
36
|
+
|
|
37
|
+
if "required property" in msg:
|
|
38
|
+
msg = f"Missing required field(s): {msg}"
|
|
39
|
+
elif "not of type" in msg:
|
|
40
|
+
msg = f"{field}Invalid field type: {msg}"
|
|
41
|
+
raise ResultValidationError(f"Result failed schema validation: {msg}", exc) from exc
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def validate_prompt_workflow(workflow: Any) -> None:
|
|
45
|
+
"""Validate a PromptWorkflow."""
|
|
46
|
+
if not isinstance(workflow, dict):
|
|
47
|
+
raise ValidationError("Workflow must be a dictionary")
|
|
48
|
+
|
|
49
|
+
required = ["query", "thesis", "antithesis", "synthesis"]
|
|
50
|
+
missing = [field for field in required if field not in workflow]
|
|
51
|
+
if missing:
|
|
52
|
+
raise ValidationError(f"Missing required field(s): {', '.join(missing)}")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def validate_hegelion_result_list(results: List[Dict[str, Any]]) -> None:
|
|
56
|
+
"""Validate a list of HegelionResults."""
|
|
57
|
+
for i, item in enumerate(results):
|
|
58
|
+
try:
|
|
59
|
+
validate_hegelion_result(item)
|
|
60
|
+
except Exception as exc:
|
|
61
|
+
raise ValidationError(f"Item at index {i} is invalid: {exc}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def validate_dialectic_output(output: Any) -> None:
|
|
65
|
+
"""Validate a DialecticOutput."""
|
|
66
|
+
if isinstance(output, dict) and "query" not in output:
|
|
67
|
+
raise ValidationError("Missing required field(s): query")
|
|
68
|
+
validate_hegelion_result(output)
|