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,276 @@
1
+ """Environment-driven configuration helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from dataclasses import dataclass, field
7
+ from functools import lru_cache
8
+ from typing import Any, Dict
9
+
10
+ from .backends import (
11
+ AnthropicLLMBackend,
12
+ CustomHTTPLLMBackend,
13
+ GoogleLLMBackend,
14
+ LLMBackend,
15
+ OllamaLLMBackend,
16
+ OpenAILLMBackend,
17
+ )
18
+
19
+
20
+ class ConfigurationError(RuntimeError):
21
+ """Raised when the server is misconfigured."""
22
+
23
+
24
+ @dataclass
25
+ class EngineSettings:
26
+ """Settings for the Hegelion engine."""
27
+
28
+ model: str
29
+ synthesis_threshold: float
30
+ max_tokens_per_phase: int
31
+ validate_results: bool
32
+ cache_enabled: bool
33
+ cache_ttl_seconds: int
34
+ cache_dir: str
35
+
36
+
37
+ @dataclass
38
+ class Config:
39
+ """Mutable runtime configuration for Hegelion."""
40
+
41
+ provider: str
42
+ model: str
43
+ synthesis_threshold: float
44
+ max_tokens_per_phase: int
45
+ validate_results: bool
46
+ cache_enabled: bool
47
+ cache_ttl_seconds: int
48
+ cache_dir: str
49
+
50
+ # Backend-specific settings
51
+ openai_key: str | None
52
+ openai_base_url: str | None
53
+ openai_org: str | None
54
+ anthropic_key: str | None
55
+ anthropic_base_url: str
56
+ google_key: str | None
57
+ google_base_url: str | None
58
+ moonshot_key: str | None
59
+ moonshot_base_url: str
60
+ ollama_url: str
61
+ custom_base_url: str | None
62
+ custom_api_key: str | None
63
+ custom_timeout: float
64
+
65
+ debug: bool = False
66
+
67
+ # Internal state
68
+ _initial_env: Dict[str, Any] = field(default_factory=dict, repr=False)
69
+
70
+
71
+ def _get_env_float(name: str, default: float) -> float:
72
+ raw = os.getenv(name)
73
+ if raw is None:
74
+ return default
75
+ try:
76
+ return float(raw)
77
+ except ValueError as exc:
78
+ raise ConfigurationError(f"Environment variable {name} must be a float.") from exc
79
+
80
+
81
+ def _get_env_int(name: str, default: int) -> int:
82
+ raw = os.getenv(name)
83
+ if raw is None:
84
+ return default
85
+ try:
86
+ return int(raw)
87
+ except ValueError as exc:
88
+ raise ConfigurationError(f"Environment variable {name} must be an integer.") from exc
89
+
90
+
91
+ def _get_env_bool(name: str, default: bool) -> bool:
92
+ raw = os.getenv(name)
93
+ if raw is None:
94
+ return default
95
+ return raw.strip().lower() not in {"0", "false", "no"}
96
+
97
+
98
+ DEFAULT_ANTHROPIC_BASE_URL = "https://api.anthropic.com"
99
+
100
+
101
+ @lru_cache(maxsize=1)
102
+ def get_config() -> Config:
103
+ """Return the global, mutable configuration object."""
104
+ return Config(
105
+ provider=os.getenv("HEGELION_PROVIDER", "anthropic").lower(),
106
+ model=os.getenv("HEGELION_MODEL", "claude-sonnet-4-5-20250929"),
107
+ synthesis_threshold=_get_env_float("HEGELION_SYNTHESIS_THRESHOLD", 0.85),
108
+ max_tokens_per_phase=_get_env_int("HEGELION_MAX_TOKENS_PER_PHASE", 10_000),
109
+ validate_results=_get_env_bool("HEGELION_VALIDATE_RESULTS", True),
110
+ cache_enabled=_get_env_bool("HEGELION_CACHE", True),
111
+ cache_ttl_seconds=_get_env_int("HEGELION_CACHE_TTL_SECONDS", 86_400),
112
+ cache_dir=os.path.expanduser(os.getenv("HEGELION_CACHE_DIR", "~/.cache/hegelion")),
113
+ openai_key=os.getenv("OPENAI_API_KEY"),
114
+ openai_base_url=os.getenv("OPENAI_BASE_URL"),
115
+ openai_org=os.getenv("OPENAI_ORG_ID"),
116
+ anthropic_key=os.getenv("ANTHROPIC_API_KEY"),
117
+ anthropic_base_url=os.getenv("ANTHROPIC_BASE_URL", DEFAULT_ANTHROPIC_BASE_URL),
118
+ google_key=os.getenv("GOOGLE_API_KEY"),
119
+ google_base_url=os.getenv("GOOGLE_API_BASE_URL"),
120
+ moonshot_key=os.getenv("MOONSHOT_API_KEY"),
121
+ moonshot_base_url=os.getenv("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
122
+ ollama_url=os.getenv("OLLAMA_BASE_URL", "http://localhost:11434"),
123
+ custom_base_url=os.getenv("CUSTOM_API_BASE_URL"),
124
+ custom_api_key=os.getenv("CUSTOM_API_KEY"),
125
+ custom_timeout=_get_env_float("CUSTOM_API_TIMEOUT", 60.0),
126
+ )
127
+
128
+
129
+ def set_config_value(key: str, value: Any) -> None:
130
+ """Update a value in the global configuration."""
131
+ config = get_config()
132
+ if hasattr(config, key):
133
+ setattr(config, key, value)
134
+ # When backend-related config changes, we must clear the backend cache
135
+ if key in {
136
+ "provider",
137
+ "model",
138
+ "openai_key",
139
+ "anthropic_key",
140
+ "google_key",
141
+ "moonshot_key",
142
+ }:
143
+ get_backend_from_env.cache_clear()
144
+ else:
145
+ raise AttributeError(f"'{type(config).__name__}' has no attribute '{key}'")
146
+
147
+
148
+ def resolve_backend_for_model(model: str) -> LLMBackend:
149
+ """Resolve an LLM backend based on the model name."""
150
+ lowered = model.lower()
151
+ config = get_config()
152
+
153
+ if "claude" in lowered:
154
+ if not config.anthropic_key:
155
+ raise ConfigurationError("ANTHROPIC_API_KEY must be set.")
156
+ return AnthropicLLMBackend(
157
+ model=model,
158
+ api_key=config.anthropic_key,
159
+ base_url=config.anthropic_base_url,
160
+ )
161
+
162
+ if lowered.startswith(("gpt-", "o1-")) or "glm" in lowered:
163
+ if not config.openai_key:
164
+ raise ConfigurationError("OPENAI_API_KEY must be set.")
165
+ return OpenAILLMBackend(
166
+ model=(
167
+ model if model != "gpt-5.1-chat-latest" else "gpt-5.1-chat-latest"
168
+ ), # Ensure we use the exact model string
169
+ api_key=config.openai_key,
170
+ base_url=config.openai_base_url,
171
+ organization=config.openai_org,
172
+ )
173
+
174
+ if "gemini" in lowered or lowered.startswith("g-"):
175
+ if not config.google_key:
176
+ raise ConfigurationError("GOOGLE_API_KEY must be set.")
177
+ return GoogleLLMBackend(
178
+ model=(
179
+ model if "gemini" in model else "gemini-3-pro-preview"
180
+ ), # Default to new model if generic g- prefix
181
+ api_key=config.google_key,
182
+ base_url=config.google_base_url,
183
+ )
184
+
185
+ if "kimi" in lowered:
186
+ if not config.moonshot_key:
187
+ raise ConfigurationError("MOONSHOT_API_KEY must be set for Kimi models.")
188
+ return OpenAILLMBackend(
189
+ model=model,
190
+ api_key=config.moonshot_key,
191
+ base_url=config.moonshot_base_url,
192
+ )
193
+
194
+ if lowered.startswith("local-"):
195
+ actual_model = model.split("local-", 1)[1] or "llama3.3"
196
+ return OllamaLLMBackend(model=actual_model, base_url=config.ollama_url)
197
+
198
+ raise ConfigurationError(f"Cannot infer backend for model '{model}'.")
199
+
200
+
201
+ @lru_cache(maxsize=1)
202
+ def get_backend_from_env() -> LLMBackend:
203
+ """Instantiate the configured backend from the global config."""
204
+ config = get_config()
205
+
206
+ if config.provider in {"anthropic", "auto"} and config.anthropic_key:
207
+ return AnthropicLLMBackend(
208
+ model=config.model,
209
+ api_key=config.anthropic_key,
210
+ base_url=config.anthropic_base_url,
211
+ )
212
+
213
+ if config.provider in {"openai", "auto"} and config.openai_key:
214
+ return OpenAILLMBackend(
215
+ model=config.model,
216
+ api_key=config.openai_key,
217
+ base_url=config.openai_base_url,
218
+ organization=config.openai_org,
219
+ )
220
+
221
+ if config.provider in {"google", "auto"} and config.google_key:
222
+ return GoogleLLMBackend(
223
+ model=config.model,
224
+ api_key=config.google_key,
225
+ base_url=config.google_base_url,
226
+ )
227
+
228
+ if config.provider in {"moonshot", "kimi", "auto"} and config.moonshot_key:
229
+ return OpenAILLMBackend(
230
+ model=config.model,
231
+ api_key=config.moonshot_key,
232
+ base_url=config.moonshot_base_url,
233
+ )
234
+
235
+ if config.provider == "ollama":
236
+ return OllamaLLMBackend(model=config.model, base_url=config.ollama_url)
237
+
238
+ if config.provider == "custom_http":
239
+ if not config.custom_base_url:
240
+ raise ConfigurationError("CUSTOM_API_BASE_URL must be set for custom_http provider.")
241
+ return CustomHTTPLLMBackend(
242
+ model=config.model,
243
+ api_base_url=config.custom_base_url,
244
+ api_key=config.custom_api_key,
245
+ timeout=config.custom_timeout,
246
+ )
247
+
248
+ raise ConfigurationError(
249
+ "Unable to configure LLM backend. Set HEGELION_PROVIDER and corresponding API keys."
250
+ )
251
+
252
+
253
+ def get_engine_settings() -> EngineSettings:
254
+ """Load engine configuration values from the global config."""
255
+ config = get_config()
256
+ return EngineSettings(
257
+ model=config.model,
258
+ synthesis_threshold=config.synthesis_threshold,
259
+ max_tokens_per_phase=config.max_tokens_per_phase,
260
+ validate_results=config.validate_results,
261
+ cache_enabled=config.cache_enabled,
262
+ cache_ttl_seconds=config.cache_ttl_seconds,
263
+ cache_dir=config.cache_dir,
264
+ )
265
+
266
+
267
+ __all__ = [
268
+ "Config",
269
+ "EngineSettings",
270
+ "ConfigurationError",
271
+ "get_config",
272
+ "set_config_value",
273
+ "get_backend_from_env",
274
+ "get_engine_settings",
275
+ "resolve_backend_for_model",
276
+ ]