howler-agents-core 0.1.0__tar.gz

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 (82) hide show
  1. howler_agents_core-0.1.0/.gitignore +69 -0
  2. howler_agents_core-0.1.0/PKG-INFO +159 -0
  3. howler_agents_core-0.1.0/README.md +112 -0
  4. howler_agents_core-0.1.0/pyproject.toml +42 -0
  5. howler_agents_core-0.1.0/src/howler_agents/__init__.py +7 -0
  6. howler_agents_core-0.1.0/src/howler_agents/agents/__init__.py +1 -0
  7. howler_agents_core-0.1.0/src/howler_agents/agents/base.py +82 -0
  8. howler_agents_core-0.1.0/src/howler_agents/agents/pool.py +50 -0
  9. howler_agents_core-0.1.0/src/howler_agents/benchmarks/__init__.py +1 -0
  10. howler_agents_core-0.1.0/src/howler_agents/benchmarks/swe_bench_agent.py +1157 -0
  11. howler_agents_core-0.1.0/src/howler_agents/benchmarks/swe_bench_harness.py +404 -0
  12. howler_agents_core-0.1.0/src/howler_agents/benchmarks/swe_bench_runner.py +804 -0
  13. howler_agents_core-0.1.0/src/howler_agents/claude_agent.md +269 -0
  14. howler_agents_core-0.1.0/src/howler_agents/cli.py +1016 -0
  15. howler_agents_core-0.1.0/src/howler_agents/config.py +48 -0
  16. howler_agents_core-0.1.0/src/howler_agents/evolution/__init__.py +1 -0
  17. howler_agents_core-0.1.0/src/howler_agents/evolution/directive.py +16 -0
  18. howler_agents_core-0.1.0/src/howler_agents/evolution/loop.py +183 -0
  19. howler_agents_core-0.1.0/src/howler_agents/evolution/reproducer.py +159 -0
  20. howler_agents_core-0.1.0/src/howler_agents/experience/__init__.py +1 -0
  21. howler_agents_core-0.1.0/src/howler_agents/experience/pool.py +68 -0
  22. howler_agents_core-0.1.0/src/howler_agents/experience/store/__init__.py +1 -0
  23. howler_agents_core-0.1.0/src/howler_agents/experience/store/base.py +17 -0
  24. howler_agents_core-0.1.0/src/howler_agents/experience/store/memory.py +30 -0
  25. howler_agents_core-0.1.0/src/howler_agents/experience/store/postgres.py +117 -0
  26. howler_agents_core-0.1.0/src/howler_agents/experience/store/redis.py +70 -0
  27. howler_agents_core-0.1.0/src/howler_agents/experience/store/sqlite.py +119 -0
  28. howler_agents_core-0.1.0/src/howler_agents/experience/trace.py +28 -0
  29. howler_agents_core-0.1.0/src/howler_agents/hivemind/__init__.py +13 -0
  30. howler_agents_core-0.1.0/src/howler_agents/hivemind/consensus.py +180 -0
  31. howler_agents_core-0.1.0/src/howler_agents/hivemind/coordinator.py +174 -0
  32. howler_agents_core-0.1.0/src/howler_agents/hivemind/memory.py +163 -0
  33. howler_agents_core-0.1.0/src/howler_agents/llm/__init__.py +1 -0
  34. howler_agents_core-0.1.0/src/howler_agents/llm/claude_code.py +620 -0
  35. howler_agents_core-0.1.0/src/howler_agents/llm/roles.py +5 -0
  36. howler_agents_core-0.1.0/src/howler_agents/llm/router.py +148 -0
  37. howler_agents_core-0.1.0/src/howler_agents/local_runner.py +656 -0
  38. howler_agents_core-0.1.0/src/howler_agents/mcp_server.py +1444 -0
  39. howler_agents_core-0.1.0/src/howler_agents/orchestration/__init__.py +22 -0
  40. howler_agents_core-0.1.0/src/howler_agents/orchestration/claude_flow.py +251 -0
  41. howler_agents_core-0.1.0/src/howler_agents/orchestration/detector.py +75 -0
  42. howler_agents_core-0.1.0/src/howler_agents/orchestration/interface.py +100 -0
  43. howler_agents_core-0.1.0/src/howler_agents/orchestration/local.py +147 -0
  44. howler_agents_core-0.1.0/src/howler_agents/persistence/__init__.py +15 -0
  45. howler_agents_core-0.1.0/src/howler_agents/persistence/db.py +101 -0
  46. howler_agents_core-0.1.0/src/howler_agents/persistence/migrations.py +153 -0
  47. howler_agents_core-0.1.0/src/howler_agents/persistence/repo.py +58 -0
  48. howler_agents_core-0.1.0/src/howler_agents/persistence/sync_client.py +140 -0
  49. howler_agents_core-0.1.0/src/howler_agents/probes/__init__.py +1 -0
  50. howler_agents_core-0.1.0/src/howler_agents/probes/evaluator.py +24 -0
  51. howler_agents_core-0.1.0/src/howler_agents/probes/registry.py +66 -0
  52. howler_agents_core-0.1.0/src/howler_agents/py.typed +0 -0
  53. howler_agents_core-0.1.0/src/howler_agents/selection/__init__.py +1 -0
  54. howler_agents_core-0.1.0/src/howler_agents/selection/criterion.py +81 -0
  55. howler_agents_core-0.1.0/src/howler_agents/selection/novelty.py +47 -0
  56. howler_agents_core-0.1.0/src/howler_agents/selection/performance.py +27 -0
  57. howler_agents_core-0.1.0/src/howler_agents/templates/agents/howler/actor.md +80 -0
  58. howler_agents_core-0.1.0/src/howler_agents/templates/agents/howler/coordinator.md +85 -0
  59. howler_agents_core-0.1.0/src/howler_agents/templates/agents/howler/evaluator.md +114 -0
  60. howler_agents_core-0.1.0/src/howler_agents/templates/agents/howler/reproducer.md +129 -0
  61. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-agents/SKILL.md +138 -0
  62. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-agents-wiggam/SKILL.md +165 -0
  63. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-agents-wiggam/scripts/setup-wiggam-loop.sh +150 -0
  64. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-auto-evolve/SKILL.md +154 -0
  65. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-evolve/SKILL.md +155 -0
  66. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-init/SKILL.md +177 -0
  67. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-memory/SKILL.md +131 -0
  68. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-setup/SKILL.md +191 -0
  69. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-status/SKILL.md +73 -0
  70. howler_agents_core-0.1.0/src/howler_agents/templates/skills/howler-sync/SKILL.md +134 -0
  71. howler_agents_core-0.1.0/tests/_helpers.py +32 -0
  72. howler_agents_core-0.1.0/tests/conftest.py +30 -0
  73. howler_agents_core-0.1.0/tests/test_e2e_evolution.py +838 -0
  74. howler_agents_core-0.1.0/tests/test_evolution_loop.py +60 -0
  75. howler_agents_core-0.1.0/tests/test_experience.py +75 -0
  76. howler_agents_core-0.1.0/tests/test_gea_mechanisms.py +658 -0
  77. howler_agents_core-0.1.0/tests/test_llm_router.py +502 -0
  78. howler_agents_core-0.1.0/tests/test_paper_validation.py +975 -0
  79. howler_agents_core-0.1.0/tests/test_pool.py +51 -0
  80. howler_agents_core-0.1.0/tests/test_probes.py +39 -0
  81. howler_agents_core-0.1.0/tests/test_selection.py +46 -0
  82. howler_agents_core-0.1.0/tests/test_swe_bench.py +721 -0
@@ -0,0 +1,69 @@
1
+ # Environment
2
+ .env
3
+ .env.local
4
+ .env.*.local
5
+
6
+ # Python
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+ *.egg-info/
11
+ *.egg
12
+ dist/
13
+ build/
14
+ .eggs/
15
+ *.whl
16
+ .venv/
17
+ venv/
18
+ .mypy_cache/
19
+ .ruff_cache/
20
+ .pytest_cache/
21
+ htmlcov/
22
+ .coverage
23
+ .coverage.*
24
+
25
+ # Node
26
+ node_modules/
27
+ .pnpm-store/
28
+ *.tsbuildinfo
29
+
30
+ # Proto generated
31
+ packages/howler-agents-service/src/howler_agents_service/generated/
32
+ packages/howler-agents-ts/src/generated/
33
+ packages/howler-agents-ui/src/generated/
34
+
35
+ # Build output
36
+ packages/howler-agents-ts/dist/
37
+ packages/howler-agents-ui/.output/
38
+ packages/howler-agents-ui/.vinxi/
39
+ packages/howler-agents-docs/.output/
40
+ packages/howler-agents-docs/.vinxi/
41
+
42
+ # Docker
43
+ .docker/
44
+
45
+ # IDE
46
+ .idea/
47
+ .vscode/
48
+ *.swp
49
+ *.swo
50
+ *~
51
+ .DS_Store
52
+
53
+ # Claude Flow
54
+ .claude-flow/
55
+ .swarm/
56
+
57
+ # Howler Agents local DB
58
+ .howler-agents/
59
+
60
+ # SWE-bench Docker evaluation reports (local artifacts)
61
+ howler-agents__*.json
62
+ logs/
63
+
64
+ # Claude local DB
65
+ .claude/memory.db
66
+
67
+ # Misc
68
+ *.log
69
+ tmp/
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.4
2
+ Name: howler-agents-core
3
+ Version: 0.1.0
4
+ Summary: Core library for Group-Evolving Agents
5
+ Project-URL: Homepage, https://github.com/jbeck018/howler-agents
6
+ Project-URL: Repository, https://github.com/jbeck018/howler-agents
7
+ Project-URL: Documentation, https://github.com/jbeck018/howler-agents
8
+ Project-URL: Bug Tracker, https://github.com/jbeck018/howler-agents/issues
9
+ License: MIT
10
+ Keywords: agent-evolution,gea,howler-agents,llm,multi-agent
11
+ Requires-Python: >=3.12
12
+ Requires-Dist: aiosqlite>=0.20
13
+ Requires-Dist: claude-agent-sdk>=0.1.41
14
+ Requires-Dist: click>=8.0
15
+ Requires-Dist: litellm>=1.50.0
16
+ Requires-Dist: numpy>=1.26
17
+ Requires-Dist: pydantic>=2.0
18
+ Requires-Dist: scikit-learn>=1.4
19
+ Requires-Dist: structlog>=24.0
20
+ Provides-Extra: all
21
+ Requires-Dist: asyncpg>=0.29; extra == 'all'
22
+ Requires-Dist: datasets>=2.0; extra == 'all'
23
+ Requires-Dist: httpx>=0.27; extra == 'all'
24
+ Requires-Dist: mcp>=1.0; extra == 'all'
25
+ Requires-Dist: pgvector>=0.3; extra == 'all'
26
+ Requires-Dist: redis[hiredis]>=5.0; extra == 'all'
27
+ Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'all'
28
+ Requires-Dist: swebench>=4.0; extra == 'all'
29
+ Provides-Extra: bench
30
+ Requires-Dist: datasets>=2.0; extra == 'bench'
31
+ Requires-Dist: swebench>=4.0; extra == 'bench'
32
+ Provides-Extra: dev
33
+ Requires-Dist: coverage>=7.0; extra == 'dev'
34
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
35
+ Requires-Dist: pytest-mock>=3.12; extra == 'dev'
36
+ Requires-Dist: pytest>=8.0; extra == 'dev'
37
+ Provides-Extra: mcp
38
+ Requires-Dist: httpx>=0.27; extra == 'mcp'
39
+ Requires-Dist: mcp>=1.0; extra == 'mcp'
40
+ Provides-Extra: postgres
41
+ Requires-Dist: asyncpg>=0.29; extra == 'postgres'
42
+ Requires-Dist: pgvector>=0.3; extra == 'postgres'
43
+ Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'postgres'
44
+ Provides-Extra: redis
45
+ Requires-Dist: redis[hiredis]>=5.0; extra == 'redis'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # howler-agents-core
49
+
50
+ Core Python library for Group-Evolving Agents (GEA) -- an evolutionary framework for open-ended self-improvement via experience sharing (arXiv:2602.04837).
51
+
52
+ This package implements the full GEA algorithm: agent pool management, performance-novelty parent selection, shared experience aggregation, group reproduction via meta-LLM, and probe-based capability characterization. It can be used standalone or as the engine behind `howler-agents-service`.
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install howler-agents-core
58
+ ```
59
+
60
+ ### Optional dependencies
61
+
62
+ For production use with Postgres (experience store + pgvector KNN) and Redis (hot cache):
63
+
64
+ ```bash
65
+ pip install howler-agents-core[postgres] # SQLAlchemy + asyncpg + pgvector
66
+ pip install howler-agents-core[redis] # redis with hiredis
67
+ pip install howler-agents-core[all] # both
68
+ ```
69
+
70
+ ## Quick Usage
71
+
72
+ ```python
73
+ import asyncio
74
+ import uuid
75
+
76
+ from howler_agents import HowlerConfig, EvolutionLoop
77
+ from howler_agents.agents.base import Agent, AgentConfig, FrameworkPatch, TaskResult
78
+ from howler_agents.agents.pool import AgentPool
79
+ from howler_agents.evolution.reproducer import GroupReproducer
80
+ from howler_agents.experience.pool import SharedExperiencePool
81
+ from howler_agents.experience.store.memory import InMemoryStore
82
+ from howler_agents.llm.router import LLMRouter
83
+ from howler_agents.probes.evaluator import ProbeEvaluator
84
+ from howler_agents.probes.registry import ProbeRegistry
85
+ from howler_agents.selection.criterion import PerformanceNoveltySelector
86
+
87
+
88
+ class MyAgent(Agent):
89
+ """Implement your agent by subclassing Agent."""
90
+
91
+ async def run_task(self, task: dict) -> TaskResult:
92
+ # Your task execution logic here
93
+ return TaskResult(success=True, score=0.8, output="done")
94
+
95
+ async def apply_patch(self, patch: FrameworkPatch) -> None:
96
+ self.patches.append(patch)
97
+
98
+
99
+ async def main() -> None:
100
+ config = HowlerConfig(
101
+ population_size=10,
102
+ group_size=3,
103
+ num_iterations=5,
104
+ alpha=0.5,
105
+ num_probes=20,
106
+ )
107
+
108
+ store = InMemoryStore()
109
+ experience = SharedExperiencePool(store)
110
+ llm = LLMRouter(config)
111
+ selector = PerformanceNoveltySelector(alpha=config.alpha)
112
+ reproducer = GroupReproducer(llm, experience, config)
113
+ registry = ProbeRegistry()
114
+ registry.register_default_probes(num_probes=config.num_probes)
115
+ probes = ProbeEvaluator(registry)
116
+
117
+ pool = AgentPool()
118
+ for _ in range(config.population_size):
119
+ pool.add(MyAgent(AgentConfig(id=str(uuid.uuid4()))))
120
+
121
+ loop = EvolutionLoop(config, pool, selector, reproducer, experience, probes)
122
+
123
+ tasks = [{"description": "solve a coding problem", "type": "general"}]
124
+ results = await loop.run("my-run", tasks)
125
+ print(f"Best score: {results['best_score']:.3f}")
126
+
127
+
128
+ asyncio.run(main())
129
+ ```
130
+
131
+ ## Core Modules
132
+
133
+ | Module | Description |
134
+ |---|---|
135
+ | `howler_agents.agents` | Agent base class, AgentPool, FrameworkPatch |
136
+ | `howler_agents.selection` | Performance scorer, KNN novelty estimator, combined criterion |
137
+ | `howler_agents.experience` | Evolutionary traces, shared experience pool, pluggable stores |
138
+ | `howler_agents.evolution` | Evolution directives, group reproducer, main evolution loop |
139
+ | `howler_agents.probes` | Probe task interface, evaluator, registry |
140
+ | `howler_agents.llm` | LiteLLM-backed router with role-based model dispatch |
141
+ | `howler_agents.config` | `HowlerConfig` with all GEA parameters (K, M, alpha, iterations) |
142
+
143
+ ## Configuration
144
+
145
+ `HowlerConfig` accepts all GEA parameters:
146
+
147
+ | Parameter | Default | Description |
148
+ |---|---|---|
149
+ | `population_size` (K) | 10 | Total agents in population |
150
+ | `group_size` (M) | 3 | Agents per parent group |
151
+ | `num_iterations` | 5 | Evolution generations |
152
+ | `alpha` | 0.5 | Performance vs novelty weight (0=novelty, 1=performance) |
153
+ | `num_probes` | 20 | Probe tasks for capability vector |
154
+ | `task_domain` | "general" | Domain identifier (e.g., "swe-bench", "polyglot") |
155
+ | `role_models` | Claude Sonnet defaults | Per-role LLM model configuration |
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,112 @@
1
+ # howler-agents-core
2
+
3
+ Core Python library for Group-Evolving Agents (GEA) -- an evolutionary framework for open-ended self-improvement via experience sharing (arXiv:2602.04837).
4
+
5
+ This package implements the full GEA algorithm: agent pool management, performance-novelty parent selection, shared experience aggregation, group reproduction via meta-LLM, and probe-based capability characterization. It can be used standalone or as the engine behind `howler-agents-service`.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install howler-agents-core
11
+ ```
12
+
13
+ ### Optional dependencies
14
+
15
+ For production use with Postgres (experience store + pgvector KNN) and Redis (hot cache):
16
+
17
+ ```bash
18
+ pip install howler-agents-core[postgres] # SQLAlchemy + asyncpg + pgvector
19
+ pip install howler-agents-core[redis] # redis with hiredis
20
+ pip install howler-agents-core[all] # both
21
+ ```
22
+
23
+ ## Quick Usage
24
+
25
+ ```python
26
+ import asyncio
27
+ import uuid
28
+
29
+ from howler_agents import HowlerConfig, EvolutionLoop
30
+ from howler_agents.agents.base import Agent, AgentConfig, FrameworkPatch, TaskResult
31
+ from howler_agents.agents.pool import AgentPool
32
+ from howler_agents.evolution.reproducer import GroupReproducer
33
+ from howler_agents.experience.pool import SharedExperiencePool
34
+ from howler_agents.experience.store.memory import InMemoryStore
35
+ from howler_agents.llm.router import LLMRouter
36
+ from howler_agents.probes.evaluator import ProbeEvaluator
37
+ from howler_agents.probes.registry import ProbeRegistry
38
+ from howler_agents.selection.criterion import PerformanceNoveltySelector
39
+
40
+
41
+ class MyAgent(Agent):
42
+ """Implement your agent by subclassing Agent."""
43
+
44
+ async def run_task(self, task: dict) -> TaskResult:
45
+ # Your task execution logic here
46
+ return TaskResult(success=True, score=0.8, output="done")
47
+
48
+ async def apply_patch(self, patch: FrameworkPatch) -> None:
49
+ self.patches.append(patch)
50
+
51
+
52
+ async def main() -> None:
53
+ config = HowlerConfig(
54
+ population_size=10,
55
+ group_size=3,
56
+ num_iterations=5,
57
+ alpha=0.5,
58
+ num_probes=20,
59
+ )
60
+
61
+ store = InMemoryStore()
62
+ experience = SharedExperiencePool(store)
63
+ llm = LLMRouter(config)
64
+ selector = PerformanceNoveltySelector(alpha=config.alpha)
65
+ reproducer = GroupReproducer(llm, experience, config)
66
+ registry = ProbeRegistry()
67
+ registry.register_default_probes(num_probes=config.num_probes)
68
+ probes = ProbeEvaluator(registry)
69
+
70
+ pool = AgentPool()
71
+ for _ in range(config.population_size):
72
+ pool.add(MyAgent(AgentConfig(id=str(uuid.uuid4()))))
73
+
74
+ loop = EvolutionLoop(config, pool, selector, reproducer, experience, probes)
75
+
76
+ tasks = [{"description": "solve a coding problem", "type": "general"}]
77
+ results = await loop.run("my-run", tasks)
78
+ print(f"Best score: {results['best_score']:.3f}")
79
+
80
+
81
+ asyncio.run(main())
82
+ ```
83
+
84
+ ## Core Modules
85
+
86
+ | Module | Description |
87
+ |---|---|
88
+ | `howler_agents.agents` | Agent base class, AgentPool, FrameworkPatch |
89
+ | `howler_agents.selection` | Performance scorer, KNN novelty estimator, combined criterion |
90
+ | `howler_agents.experience` | Evolutionary traces, shared experience pool, pluggable stores |
91
+ | `howler_agents.evolution` | Evolution directives, group reproducer, main evolution loop |
92
+ | `howler_agents.probes` | Probe task interface, evaluator, registry |
93
+ | `howler_agents.llm` | LiteLLM-backed router with role-based model dispatch |
94
+ | `howler_agents.config` | `HowlerConfig` with all GEA parameters (K, M, alpha, iterations) |
95
+
96
+ ## Configuration
97
+
98
+ `HowlerConfig` accepts all GEA parameters:
99
+
100
+ | Parameter | Default | Description |
101
+ |---|---|---|
102
+ | `population_size` (K) | 10 | Total agents in population |
103
+ | `group_size` (M) | 3 | Agents per parent group |
104
+ | `num_iterations` | 5 | Evolution generations |
105
+ | `alpha` | 0.5 | Performance vs novelty weight (0=novelty, 1=performance) |
106
+ | `num_probes` | 20 | Probe tasks for capability vector |
107
+ | `task_domain` | "general" | Domain identifier (e.g., "swe-bench", "polyglot") |
108
+ | `role_models` | Claude Sonnet defaults | Per-role LLM model configuration |
109
+
110
+ ## License
111
+
112
+ MIT
@@ -0,0 +1,42 @@
1
+ [project]
2
+ name = "howler-agents-core"
3
+ version = "0.1.0"
4
+ description = "Core library for Group-Evolving Agents"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.12"
8
+ keywords = ["howler-agents", "gea", "agent-evolution", "llm", "multi-agent"]
9
+ dependencies = [
10
+ "litellm>=1.50.0",
11
+ "numpy>=1.26",
12
+ "scikit-learn>=1.4",
13
+ "pydantic>=2.0",
14
+ "structlog>=24.0",
15
+ "click>=8.0",
16
+ "aiosqlite>=0.20",
17
+ "claude-agent-sdk>=0.1.41",
18
+ ]
19
+
20
+ [project.scripts]
21
+ howler-agents = "howler_agents.cli:cli"
22
+
23
+ [project.optional-dependencies]
24
+ postgres = ["sqlalchemy[asyncio]>=2.0", "asyncpg>=0.29", "pgvector>=0.3"]
25
+ redis = ["redis[hiredis]>=5.0"]
26
+ mcp = ["mcp>=1.0", "httpx>=0.27"]
27
+ bench = ["datasets>=2.0", "swebench>=4.0"]
28
+ all = ["howler-agents-core[postgres,redis,mcp,bench]"]
29
+ dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "pytest-mock>=3.12", "coverage>=7.0"]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/jbeck018/howler-agents"
33
+ Repository = "https://github.com/jbeck018/howler-agents"
34
+ Documentation = "https://github.com/jbeck018/howler-agents"
35
+ "Bug Tracker" = "https://github.com/jbeck018/howler-agents/issues"
36
+
37
+ [build-system]
38
+ requires = ["hatchling"]
39
+ build-backend = "hatchling.build"
40
+
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["src/howler_agents"]
@@ -0,0 +1,7 @@
1
+ """Howler Agents - Group-Evolving Agents core library."""
2
+
3
+ from howler_agents.config import HowlerConfig
4
+ from howler_agents.evolution.loop import EvolutionLoop
5
+
6
+ __all__ = ["EvolutionLoop", "HowlerConfig"]
7
+ __version__ = "0.1.0"
@@ -0,0 +1,82 @@
1
+ """Abstract base agent and configuration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from abc import ABC, abstractmethod
7
+ from dataclasses import dataclass, field
8
+ from typing import Any
9
+
10
+
11
+ @dataclass
12
+ class AgentConfig:
13
+ """Configuration state of a single agent."""
14
+
15
+ id: str = field(default_factory=lambda: str(uuid.uuid4()))
16
+ generation: int = 0
17
+ parent_id: str | None = None
18
+ group_id: str | None = None
19
+ framework_config: dict[str, Any] = field(default_factory=dict)
20
+ lineage: list[str] = field(default_factory=list) # full ancestor chain, newest first
21
+
22
+
23
+ @dataclass
24
+ class TaskResult:
25
+ """Result from an agent performing a task."""
26
+
27
+ success: bool
28
+ score: float
29
+ output: str = ""
30
+ key_decisions: list[str] = field(default_factory=list)
31
+ lessons_learned: list[str] = field(default_factory=list)
32
+
33
+
34
+ class Agent(ABC):
35
+ """Abstract base for an evolvable agent."""
36
+
37
+ def __init__(self, config: AgentConfig) -> None:
38
+ self.config = config
39
+ self.performance_score: float = 0.0
40
+ self.novelty_score: float = 0.0
41
+ self.combined_score: float = 0.0
42
+ self.capability_vector: list[float] = []
43
+ self.patches: list[FrameworkPatch] = []
44
+
45
+ @property
46
+ def id(self) -> str:
47
+ return self.config.id
48
+
49
+ @abstractmethod
50
+ async def run_task(self, task: dict[str, Any]) -> TaskResult:
51
+ """Execute a task and return the result."""
52
+ ...
53
+
54
+ @abstractmethod
55
+ async def apply_patch(self, patch: FrameworkPatch) -> None:
56
+ """Apply an evolutionary mutation to this agent."""
57
+ ...
58
+
59
+ def clone(self, new_id: str | None = None) -> AgentConfig:
60
+ """Create a child config from this agent."""
61
+ new_lineage = [self.config.id, *list(self.config.lineage)]
62
+ return AgentConfig(
63
+ id=new_id or str(uuid.uuid4()),
64
+ generation=self.config.generation + 1,
65
+ parent_id=self.config.id,
66
+ group_id=self.config.group_id,
67
+ framework_config=dict(self.config.framework_config),
68
+ lineage=new_lineage,
69
+ )
70
+
71
+
72
+ @dataclass
73
+ class FrameworkPatch:
74
+ """A code/workflow mutation applied to an agent."""
75
+
76
+ id: str = field(default_factory=lambda: str(uuid.uuid4()))
77
+ agent_id: str = ""
78
+ generation: int = 0
79
+ intent: str = ""
80
+ diff: str = ""
81
+ category: str = "general"
82
+ config_updates: dict[str, Any] = field(default_factory=dict)
@@ -0,0 +1,50 @@
1
+ """Agent population pool management."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import heapq
6
+ from collections.abc import Sequence
7
+
8
+ from howler_agents.agents.base import Agent
9
+
10
+
11
+ class AgentPool:
12
+ """Manages a living population of agents."""
13
+
14
+ def __init__(self) -> None:
15
+ self._agents: dict[str, Agent] = {}
16
+
17
+ def add(self, agent: Agent) -> None:
18
+ self._agents[agent.id] = agent
19
+
20
+ def remove(self, agent_id: str) -> Agent | None:
21
+ return self._agents.pop(agent_id, None)
22
+
23
+ def get(self, agent_id: str) -> Agent | None:
24
+ return self._agents.get(agent_id)
25
+
26
+ @property
27
+ def agents(self) -> list[Agent]:
28
+ return list(self._agents.values())
29
+
30
+ @property
31
+ def size(self) -> int:
32
+ return len(self._agents)
33
+
34
+ def top_k(self, k: int, key: str = "combined_score") -> list[Agent]:
35
+ """Return the top-K agents by the given score attribute."""
36
+ return heapq.nlargest(k, self._agents.values(), key=lambda a: getattr(a, key, 0.0))
37
+
38
+ def by_generation(self, generation: int) -> list[Agent]:
39
+ return [a for a in self._agents.values() if a.config.generation == generation]
40
+
41
+ def partition_groups(self, group_size: int) -> list[list[Agent]]:
42
+ """Partition current population into groups of given size."""
43
+ agents = list(self._agents.values())
44
+ return [agents[i : i + group_size] for i in range(0, len(agents), group_size)]
45
+
46
+ def replace_population(self, new_agents: Sequence[Agent]) -> None:
47
+ """Replace the entire population."""
48
+ self._agents.clear()
49
+ for agent in new_agents:
50
+ self._agents[agent.id] = agent
@@ -0,0 +1 @@
1
+ """SWE-Bench and other benchmark harnesses for howler-agents."""