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.
Files changed (43) hide show
  1. hegelion/__init__.py +45 -0
  2. hegelion/core/__init__.py +29 -0
  3. hegelion/core/agent.py +166 -0
  4. hegelion/core/autocoding_state.py +293 -0
  5. hegelion/core/backends.py +442 -0
  6. hegelion/core/cache.py +92 -0
  7. hegelion/core/config.py +276 -0
  8. hegelion/core/core.py +649 -0
  9. hegelion/core/engine.py +865 -0
  10. hegelion/core/logging_utils.py +67 -0
  11. hegelion/core/models.py +293 -0
  12. hegelion/core/parsing.py +271 -0
  13. hegelion/core/personas.py +81 -0
  14. hegelion/core/prompt_autocoding.py +353 -0
  15. hegelion/core/prompt_dialectic.py +414 -0
  16. hegelion/core/prompts.py +127 -0
  17. hegelion/core/schema.py +67 -0
  18. hegelion/core/validation.py +68 -0
  19. hegelion/council.py +254 -0
  20. hegelion/examples_data/__init__.py +6 -0
  21. hegelion/examples_data/glm4_6_examples.jsonl +2 -0
  22. hegelion/judge.py +230 -0
  23. hegelion/mcp/__init__.py +3 -0
  24. hegelion/mcp/server.py +918 -0
  25. hegelion/scripts/hegelion_agent_cli.py +90 -0
  26. hegelion/scripts/hegelion_bench.py +117 -0
  27. hegelion/scripts/hegelion_cli.py +497 -0
  28. hegelion/scripts/hegelion_dataset.py +99 -0
  29. hegelion/scripts/hegelion_eval.py +137 -0
  30. hegelion/scripts/mcp_setup.py +150 -0
  31. hegelion/search_providers.py +151 -0
  32. hegelion/training/__init__.py +7 -0
  33. hegelion/training/datasets.py +123 -0
  34. hegelion/training/generator.py +232 -0
  35. hegelion/training/mlx_scu_trainer.py +379 -0
  36. hegelion/training/mlx_trainer.py +181 -0
  37. hegelion/training/unsloth_trainer.py +136 -0
  38. hegelion-0.4.0.dist-info/METADATA +295 -0
  39. hegelion-0.4.0.dist-info/RECORD +43 -0
  40. hegelion-0.4.0.dist-info/WHEEL +5 -0
  41. hegelion-0.4.0.dist-info/entry_points.txt +8 -0
  42. hegelion-0.4.0.dist-info/licenses/LICENSE +21 -0
  43. hegelion-0.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env python
2
+ """CLI for the adversarial Hegelion agent (thesis → antithesis → synthesis before acting)."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import asyncio
8
+ import json
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Optional, Sequence
12
+
13
+ if __package__ is None or __package__ == "": # pragma: no cover - direct execution fallback
14
+ sys.path.insert(0, str(Path(__file__).parent.parent))
15
+
16
+ from hegelion.core.agent import HegelionAgent
17
+
18
+
19
+ def build_parser() -> argparse.ArgumentParser:
20
+ parser = argparse.ArgumentParser(
21
+ description="Adversarial reflexion agent: critiques plans before acting."
22
+ )
23
+ parser.add_argument("observation", help="Current observation/state to act on")
24
+ parser.add_argument("--goal", help="Optional high-level goal", default=None)
25
+ parser.add_argument("--personas", help="Critic persona preset (e.g., council)")
26
+ parser.add_argument("--iterations", type=int, default=1, help="Refinement loops")
27
+ parser.add_argument("--use-search", action="store_true", help="Allow search in critique")
28
+ parser.add_argument("--coding", action="store_true", help="Use coding-focused guidance")
29
+ parser.add_argument("--format", choices=["json", "text"], default="text")
30
+ parser.add_argument("--debug", action="store_true", help="Include debug output")
31
+ parser.add_argument("--log-file", help="Path to append raw agent traces (JSONL)", default=None)
32
+ return parser
33
+
34
+
35
+ def parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
36
+ return build_parser().parse_args(argv)
37
+
38
+
39
+ async def run(args: argparse.Namespace) -> int:
40
+ agent = (
41
+ HegelionAgent.for_coding(
42
+ goal=args.goal,
43
+ personas=args.personas,
44
+ iterations=args.iterations,
45
+ use_search=args.use_search,
46
+ debug=args.debug,
47
+ )
48
+ if args.coding
49
+ else HegelionAgent(
50
+ goal=args.goal,
51
+ personas=args.personas,
52
+ iterations=args.iterations,
53
+ use_search=args.use_search,
54
+ debug=args.debug,
55
+ )
56
+ )
57
+
58
+ step = await agent.act(args.observation)
59
+
60
+ if args.log_file:
61
+ try:
62
+ log_path = Path(args.log_file)
63
+ log_path.parent.mkdir(parents=True, exist_ok=True)
64
+ with open(log_path, "a", encoding="utf-8") as f:
65
+ f.write(json.dumps(step.result.to_dict(), ensure_ascii=False) + "\n")
66
+ except Exception as e:
67
+ print(f"Warning: Failed to write to log file {args.log_file}: {e}", file=sys.stderr)
68
+
69
+ if args.format == "json":
70
+ payload = {"action": step.action, "result": step.result.to_dict()}
71
+ print(json.dumps(payload, indent=2, ensure_ascii=False))
72
+ else:
73
+ print(f"Action: {step.action}\n")
74
+ print("=== THESIS ===")
75
+ print(step.result.thesis)
76
+ print("\n=== ANTITHESIS ===")
77
+ print(step.result.antithesis)
78
+ print("\n=== SYNTHESIS ===")
79
+ print(step.result.synthesis)
80
+
81
+ return 0
82
+
83
+
84
+ def main(argv: Optional[Sequence[str]] = None) -> int: # pragma: no cover - CLI entrypoint
85
+ args = parse_args(argv)
86
+ return asyncio.run(run(args))
87
+
88
+
89
+ if __name__ == "__main__":
90
+ raise SystemExit(main())
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env python
2
+ """Benchmark CLI for Hegelion dialectical reasoning."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import asyncio
8
+ import json
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Optional, Sequence
12
+
13
+ if __package__ is None or __package__ == "": # pragma: no cover - direct execution fallback
14
+ sys.path.insert(0, str(Path(__file__).parent.parent))
15
+
16
+ from hegelion import run_benchmark
17
+
18
+
19
+ def build_parser() -> argparse.ArgumentParser:
20
+ parser = argparse.ArgumentParser(
21
+ description="Run Hegelion dialectical reasoning on multiple prompts."
22
+ )
23
+ parser.add_argument(
24
+ "prompts_file",
25
+ type=Path,
26
+ help="Path to JSONL file containing prompts (one JSON object per line)",
27
+ )
28
+ parser.add_argument(
29
+ "--output",
30
+ type=Path,
31
+ default=None,
32
+ help="Optional path to write results as JSONL",
33
+ )
34
+ parser.add_argument(
35
+ "--debug",
36
+ action="store_true",
37
+ help="Include debug information and internal diagnostics",
38
+ )
39
+ parser.add_argument(
40
+ "--summary",
41
+ action="store_true",
42
+ help="Print aggregate statistics to stdout after the run",
43
+ )
44
+ return parser
45
+
46
+
47
+ def parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
48
+ return build_parser().parse_args(argv)
49
+
50
+
51
+ def _safe_time(result, key: str) -> float:
52
+ metadata = result.metadata if isinstance(result.metadata, dict) else {}
53
+ value = metadata.get(key)
54
+ if isinstance(value, (int, float)):
55
+ return float(value)
56
+ return 0.0
57
+
58
+
59
+ def print_summary(results: list) -> None:
60
+ """Print a summary of benchmark results."""
61
+ if not results:
62
+ print("No results to summarize")
63
+ return
64
+
65
+ total = len(results)
66
+ total_contradictions = sum(len(r.contradictions) for r in results)
67
+ total_proposals = sum(len(r.research_proposals) for r in results)
68
+ total_time = sum(_safe_time(r, "total_time_ms") for r in results)
69
+ thesis_time = sum(_safe_time(r, "thesis_time_ms") for r in results)
70
+ antithesis_time = sum(_safe_time(r, "antithesis_time_ms") for r in results)
71
+ synthesis_time = sum(_safe_time(r, "synthesis_time_ms") for r in results)
72
+
73
+ def _avg(total_value: float) -> float:
74
+ return total_value / total if total else 0.0
75
+
76
+ print("HEGELION BENCHMARK SUMMARY")
77
+ print(f"Total queries processed: {total}")
78
+ print(f"Contradictions: {total_contradictions} (avg: {_avg(total_contradictions):.1f})")
79
+ print(f"Research proposals: {total_proposals} (avg: {_avg(total_proposals):.1f})")
80
+ print(f"Total time: {total_time:.0f}ms (avg: {_avg(total_time):.0f}ms per query)")
81
+ print(f"Thesis time total/avg: {thesis_time:.0f}ms / {_avg(thesis_time):.0f}ms")
82
+ print(f"Antithesis time total/avg: {antithesis_time:.0f}ms / {_avg(antithesis_time):.0f}ms")
83
+ print(f"Synthesis time total/avg: {synthesis_time:.0f}ms / {_avg(synthesis_time):.0f}ms")
84
+ print("")
85
+
86
+
87
+ async def _run(args: argparse.Namespace) -> None:
88
+ if not args.prompts_file.exists():
89
+ raise FileNotFoundError(f"Prompts file not found: {args.prompts_file}")
90
+
91
+ results = await run_benchmark(
92
+ prompts=args.prompts_file,
93
+ output_file=args.output,
94
+ debug=args.debug,
95
+ )
96
+
97
+ if args.summary:
98
+ print_summary(results)
99
+
100
+ if not args.output:
101
+ for result in results:
102
+ print(json.dumps(result.to_dict(), ensure_ascii=False))
103
+
104
+ print(f"Processed {len(results)} queries", file=sys.stderr)
105
+
106
+
107
+ def main(argv: Optional[Sequence[str]] = None) -> None:
108
+ args = parse_args(argv)
109
+ try:
110
+ asyncio.run(_run(args))
111
+ except Exception as exc: # pragma: no cover - CLI error surface
112
+ print(f"Error: {exc}", file=sys.stderr)
113
+ sys.exit(1)
114
+
115
+
116
+ if __name__ == "__main__": # pragma: no cover - CLI entrypoint
117
+ main()