agentevolution 0.1.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 (37) hide show
  1. agentevolution/__init__.py +9 -0
  2. agentevolution/__main__.py +6 -0
  3. agentevolution/config.py +85 -0
  4. agentevolution/dashboard/__init__.py +1 -0
  5. agentevolution/dashboard/app.py +242 -0
  6. agentevolution/dashboard/static/app.js +415 -0
  7. agentevolution/dashboard/static/index.html +246 -0
  8. agentevolution/dashboard/static/style.css +1248 -0
  9. agentevolution/fitness/__init__.py +1 -0
  10. agentevolution/fitness/scorer.py +129 -0
  11. agentevolution/forge/__init__.py +1 -0
  12. agentevolution/forge/normalizer.py +53 -0
  13. agentevolution/forge/publisher.py +143 -0
  14. agentevolution/forge/schema_gen.py +175 -0
  15. agentevolution/gauntlet/__init__.py +1 -0
  16. agentevolution/gauntlet/profiler.py +58 -0
  17. agentevolution/gauntlet/sandbox.py +180 -0
  18. agentevolution/gauntlet/security.py +179 -0
  19. agentevolution/gauntlet/signer.py +20 -0
  20. agentevolution/hivemind/__init__.py +1 -0
  21. agentevolution/hivemind/discovery.py +111 -0
  22. agentevolution/hivemind/recipes.py +74 -0
  23. agentevolution/provenance/__init__.py +1 -0
  24. agentevolution/provenance/chain.py +76 -0
  25. agentevolution/provenance/trust.py +44 -0
  26. agentevolution/server.py +657 -0
  27. agentevolution/storage/__init__.py +1 -0
  28. agentevolution/storage/database.py +384 -0
  29. agentevolution/storage/models.py +195 -0
  30. agentevolution/storage/vector_store.py +140 -0
  31. agentevolution/utils/__init__.py +1 -0
  32. agentevolution/utils/hashing.py +32 -0
  33. agentevolution-0.1.0.dist-info/METADATA +215 -0
  34. agentevolution-0.1.0.dist-info/RECORD +37 -0
  35. agentevolution-0.1.0.dist-info/WHEEL +4 -0
  36. agentevolution-0.1.0.dist-info/entry_points.txt +3 -0
  37. agentevolution-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,9 @@
1
+ """
2
+ AgentVerse — The Self-Evolving MCP Tool Ecosystem
3
+
4
+ Where AI agents forge, verify, and share tools autonomously.
5
+ Every problem an agent solves becomes a reusable tool for all agents.
6
+ """
7
+
8
+ __version__ = "0.1.0"
9
+ __app_name__ = "AgentVerse"
@@ -0,0 +1,6 @@
1
+ """Allow running AgentVerse as a module: python -m agentverse"""
2
+
3
+ from agentverse.server import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,85 @@
1
+ """AgentEvolution Configuration Management."""
2
+
3
+ from pathlib import Path
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+ class ForgeConfig(BaseModel):
8
+ """Configuration for The Forge (tool publishing)."""
9
+ max_code_size_bytes: int = Field(default=50_000, description="Max code size in bytes")
10
+ max_description_length: int = Field(default=2000, description="Max description length")
11
+ blocked_imports: list[str] = Field(
12
+ default_factory=lambda: [
13
+ "subprocess", "shutil", "ctypes", "multiprocessing",
14
+ "signal", "resource", "pty", "termios",
15
+ ],
16
+ description="Python imports blocked for security",
17
+ )
18
+
19
+
20
+ class GauntletConfig(BaseModel):
21
+ """Configuration for The Gauntlet (verification)."""
22
+ execution_timeout_seconds: int = Field(default=30, description="Max execution time")
23
+ max_memory_mb: int = Field(default=256, description="Max memory usage in MB")
24
+ max_output_size_bytes: int = Field(default=10_000, description="Max output size")
25
+ allowed_network: bool = Field(default=False, description="Allow network access in sandbox")
26
+
27
+
28
+ class HiveMindConfig(BaseModel):
29
+ """Configuration for The Hive Mind (discovery)."""
30
+ embedding_model: str = Field(
31
+ default="all-MiniLM-L6-v2",
32
+ description="Sentence-transformers model for embeddings",
33
+ )
34
+ collection_name: str = Field(default="agentevolution_tools", description="ChromaDB collection")
35
+ max_results: int = Field(default=10, description="Max search results")
36
+ min_similarity: float = Field(default=0.3, description="Min cosine similarity threshold")
37
+
38
+
39
+ class FitnessConfig(BaseModel):
40
+ """Configuration for the Fitness Engine."""
41
+ weight_success_rate: float = 0.35
42
+ weight_token_efficiency: float = 0.25
43
+ weight_latency: float = 0.20
44
+ weight_adoption: float = 0.10
45
+ weight_freshness: float = 0.10
46
+ decay_days: int = Field(default=30, description="Days before staleness decay begins")
47
+ delist_threshold: float = Field(default=0.2, description="Score below which tools get delisted")
48
+
49
+
50
+ class AgentEvolutionConfig(BaseModel):
51
+ """Root configuration for AgentEvolution."""
52
+ data_dir: Path = Field(default=Path("./data"), description="Data directory")
53
+ db_name: str = Field(default="agentevolution.db", description="SQLite database filename")
54
+ host: str = Field(default="0.0.0.0", description="Server host")
55
+ port: int = Field(default=8080, description="Server port")
56
+ forge: ForgeConfig = Field(default_factory=ForgeConfig)
57
+ gauntlet: GauntletConfig = Field(default_factory=GauntletConfig)
58
+ hivemind: HiveMindConfig = Field(default_factory=HiveMindConfig)
59
+ fitness: FitnessConfig = Field(default_factory=FitnessConfig)
60
+
61
+ @property
62
+ def db_path(self) -> Path:
63
+ return self.data_dir / self.db_name
64
+
65
+ def ensure_dirs(self) -> None:
66
+ """Create necessary directories."""
67
+ self.data_dir.mkdir(parents=True, exist_ok=True)
68
+
69
+
70
+ # Global default config
71
+ _config: AgentEvolutionConfig | None = None
72
+
73
+
74
+ def get_config() -> AgentEvolutionConfig:
75
+ """Get the global configuration instance."""
76
+ global _config
77
+ if _config is None:
78
+ _config = AgentEvolutionConfig()
79
+ return _config
80
+
81
+
82
+ def set_config(config: AgentEvolutionConfig) -> None:
83
+ """Set the global configuration instance."""
84
+ global _config
85
+ _config = config
@@ -0,0 +1 @@
1
+ """AgentVerse Dashboard — Web UI."""
@@ -0,0 +1,242 @@
1
+ """AgentEvolution Dashboard — FastAPI backend serving the web UI.
2
+
3
+ Provides REST API endpoints and serves the static dashboard.
4
+ Run: agentevolution-dashboard (or python -m agentevolution.dashboard.app)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ from fastapi import FastAPI, HTTPException
15
+ from fastapi.middleware.cors import CORSMiddleware
16
+ from fastapi.responses import HTMLResponse, FileResponse
17
+ from fastapi.staticfiles import StaticFiles
18
+ from pydantic import BaseModel
19
+
20
+ from agentevolution.config import AgentEvolutionConfig, get_config, set_config
21
+ from agentevolution.storage.database import Database
22
+ from agentevolution.storage.vector_store import VectorStore
23
+ from agentevolution.fitness.scorer import FitnessScorer
24
+ from agentevolution.storage.models import ToolStatus
25
+
26
+ logging.basicConfig(level=logging.INFO, stream=sys.stderr)
27
+ logger = logging.getLogger("agentevolution.dashboard")
28
+
29
+ # ─── Static files path ───
30
+ STATIC_DIR = Path(__file__).parent / "static"
31
+
32
+ # ─── App State ───
33
+
34
+ db: Database | None = None
35
+ vector_store: VectorStore | None = None
36
+ fitness: FitnessScorer | None = None
37
+
38
+
39
+ def create_app() -> FastAPI:
40
+ """Create the FastAPI dashboard application."""
41
+ app = FastAPI(
42
+ title="AgentEvolution Dashboard",
43
+ description="The Self-Evolving MCP Tool Ecosystem — Visual Dashboard",
44
+ version="0.1.0",
45
+ )
46
+
47
+ app.add_middleware(
48
+ CORSMiddleware,
49
+ allow_origins=["*"],
50
+ allow_methods=["*"],
51
+ allow_headers=["*"],
52
+ )
53
+
54
+ # ─── Lifecycle ───
55
+
56
+ @app.on_event("startup")
57
+ async def startup():
58
+ global db, vector_store, fitness
59
+ config = get_config()
60
+ config.ensure_dirs()
61
+ db = Database(config.db_path)
62
+ await db.connect()
63
+ vector_store = VectorStore(config.data_dir, config.hivemind.collection_name)
64
+ vector_store.connect()
65
+ fitness = FitnessScorer()
66
+ logger.info("🖥️ Dashboard connected to AgentEvolution data at %s", config.data_dir)
67
+
68
+ @app.on_event("shutdown")
69
+ async def shutdown():
70
+ if db:
71
+ await db.close()
72
+
73
+ # ─── Dashboard Page ───
74
+
75
+ @app.get("/", response_class=HTMLResponse)
76
+ async def dashboard():
77
+ index = STATIC_DIR / "index.html"
78
+ return HTMLResponse(content=index.read_text(encoding="utf-8"))
79
+
80
+ @app.get("/style.css")
81
+ async def css():
82
+ return FileResponse(STATIC_DIR / "style.css", media_type="text/css")
83
+
84
+ @app.get("/app.js")
85
+ async def js():
86
+ return FileResponse(STATIC_DIR / "app.js", media_type="application/javascript")
87
+
88
+ # ─── API Endpoints ───
89
+
90
+ @app.get("/api/stats")
91
+ async def get_stats():
92
+ """Get ecosystem-wide statistics."""
93
+ all_tools = await db.list_tools(status=ToolStatus.ACTIVE, limit=1000)
94
+ total_uses = sum(t.total_uses for t in all_tools)
95
+ total_agents = len(set(t.author_agent_id for t in all_tools))
96
+ avg_fitness = sum(t.fitness_score for t in all_tools) / len(all_tools) if all_tools else 0
97
+
98
+ return {
99
+ "total_tools": len(all_tools),
100
+ "total_uses": total_uses,
101
+ "unique_agents": total_agents,
102
+ "avg_fitness": round(avg_fitness, 4),
103
+ }
104
+
105
+ @app.get("/api/tools")
106
+ async def list_tools(limit: int = 50, status: str = "active"):
107
+ """List all tools with details."""
108
+ tool_status = ToolStatus.ACTIVE if status == "active" else None
109
+ tools = await db.list_tools(status=tool_status, limit=limit)
110
+
111
+ return {
112
+ "tools": [
113
+ {
114
+ "id": t.id,
115
+ "name": t.name,
116
+ "description": t.description,
117
+ "fitness_score": t.fitness_score,
118
+ "trust_level": t.trust_level.value if hasattr(t.trust_level, 'value') else t.trust_level,
119
+ "status": t.status.value if hasattr(t.status, 'value') else t.status,
120
+ "total_uses": t.total_uses,
121
+ "successful_uses": t.successful_uses,
122
+ "unique_agents": t.unique_agents,
123
+ "tags": t.tags,
124
+ "version": t.version,
125
+ "parent_tool_id": t.parent_tool_id,
126
+ "author_agent_id": t.author_agent_id,
127
+ "avg_execution_time_ms": t.avg_execution_time_ms,
128
+ "content_hash": t.content_hash[:16] + "..." if t.content_hash else "",
129
+ "created_at": t.created_at.isoformat() if t.created_at else "",
130
+ }
131
+ for t in tools
132
+ ],
133
+ "total": len(tools),
134
+ }
135
+
136
+ @app.get("/api/tools/{tool_id}")
137
+ async def get_tool(tool_id: str):
138
+ """Get full tool details including code."""
139
+ tool = await db.get_tool(tool_id)
140
+ if not tool:
141
+ raise HTTPException(status_code=404, detail="Tool not found")
142
+
143
+ return {
144
+ "id": tool.id,
145
+ "name": tool.name,
146
+ "description": tool.description,
147
+ "code": tool.code,
148
+ "test_case": tool.test_case,
149
+ "input_schema": tool.input_schema,
150
+ "fitness_score": tool.fitness_score,
151
+ "trust_level": tool.trust_level.value if hasattr(tool.trust_level, 'value') else tool.trust_level,
152
+ "status": tool.status.value if hasattr(tool.status, 'value') else tool.status,
153
+ "total_uses": tool.total_uses,
154
+ "successful_uses": tool.successful_uses,
155
+ "unique_agents": tool.unique_agents,
156
+ "tags": tool.tags,
157
+ "version": tool.version,
158
+ "parent_tool_id": tool.parent_tool_id,
159
+ "content_hash": tool.content_hash,
160
+ "author_agent_id": tool.author_agent_id,
161
+ "created_at": tool.created_at.isoformat() if tool.created_at else "",
162
+ }
163
+
164
+ @app.get("/api/tools/{tool_id}/provenance")
165
+ async def get_provenance(tool_id: str):
166
+ """Get provenance chain for a tool."""
167
+ chain = await db.get_provenance_chain(tool_id)
168
+ return {
169
+ "chain": [
170
+ {
171
+ "tool_id": p.tool_id,
172
+ "version": p.version,
173
+ "content_hash": p.content_hash[:16] + "...",
174
+ "parent_hash": (p.parent_hash[:16] + "...") if p.parent_hash else None,
175
+ "security_scan": p.security_scan.value if hasattr(p.security_scan, 'value') else p.security_scan,
176
+ "execution_time_ms": p.performance.execution_time_ms if p.performance else 0,
177
+ "memory_peak_mb": p.performance.memory_peak_mb if p.performance else 0,
178
+ "signature": p.signature[:16] + "..." if p.signature else "",
179
+ "created_at": p.created_at.isoformat() if p.created_at else "",
180
+ }
181
+ for p in chain
182
+ ],
183
+ }
184
+
185
+ @app.get("/api/activity")
186
+ async def get_activity(limit: int = 20):
187
+ """Get recent activity feed."""
188
+ # Get recent tools as activity
189
+ tools = await db.list_tools(limit=limit)
190
+ activities = []
191
+ for t in tools:
192
+ activities.append({
193
+ "type": "tool_published",
194
+ "tool_name": t.name,
195
+ "tool_id": t.id,
196
+ "agent_id": t.author_agent_id,
197
+ "fitness_score": t.fitness_score,
198
+ "timestamp": t.created_at.isoformat() if t.created_at else "",
199
+ "tags": t.tags,
200
+ })
201
+
202
+ return {"activities": sorted(activities, key=lambda a: a["timestamp"], reverse=True)}
203
+
204
+ @app.get("/api/leaderboard")
205
+ async def get_leaderboard(limit: int = 10):
206
+ """Get top tools by fitness score."""
207
+ tools = await db.list_tools(status=ToolStatus.ACTIVE, limit=limit)
208
+ # Sort by fitness
209
+ tools.sort(key=lambda t: t.fitness_score, reverse=True)
210
+
211
+ return {
212
+ "leaderboard": [
213
+ {
214
+ "rank": i + 1,
215
+ "name": t.name,
216
+ "id": t.id,
217
+ "fitness_score": t.fitness_score,
218
+ "total_uses": t.total_uses,
219
+ "trust_level": t.trust_level.value if hasattr(t.trust_level, 'value') else t.trust_level,
220
+ "author": t.author_agent_id,
221
+ }
222
+ for i, t in enumerate(tools[:limit])
223
+ ],
224
+ }
225
+
226
+ return app
227
+
228
+
229
+ # ─── CLI Entry Point ───
230
+
231
+ def main():
232
+ """Run the dashboard server."""
233
+ import uvicorn
234
+ config = AgentEvolutionConfig()
235
+ set_config(config)
236
+ print("🖥️ AgentEvolution Dashboard", file=sys.stderr)
237
+ print(f" http://localhost:8080", file=sys.stderr)
238
+ uvicorn.run(create_app(), host="0.0.0.0", port=8080, log_level="info")
239
+
240
+
241
+ if __name__ == "__main__":
242
+ main()