hypermind 0.11.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 (181) hide show
  1. hmctl/__init__.py +7 -0
  2. hmctl/cli.py +947 -0
  3. hypermind/__init__.py +208 -0
  4. hypermind/_deprecations.py +108 -0
  5. hypermind/agent.py +2896 -0
  6. hypermind/agent_card.py +127 -0
  7. hypermind/api/__init__.py +32 -0
  8. hypermind/api/app.py +686 -0
  9. hypermind/capability.py +923 -0
  10. hypermind/consult.py +493 -0
  11. hypermind/consult_bias.py +112 -0
  12. hypermind/contract_net.py +219 -0
  13. hypermind/crypto/__init__.py +21 -0
  14. hypermind/crypto/cose_encrypt.py +126 -0
  15. hypermind/crypto/dkg.py +246 -0
  16. hypermind/crypto/domain.py +59 -0
  17. hypermind/crypto/frost.py +771 -0
  18. hypermind/crypto/hashing.py +38 -0
  19. hypermind/crypto/hlc.py +163 -0
  20. hypermind/crypto/hpke.py +277 -0
  21. hypermind/crypto/kms.py +196 -0
  22. hypermind/crypto/kms_backends/__init__.py +56 -0
  23. hypermind/crypto/kms_backends/aws.py +128 -0
  24. hypermind/crypto/kms_backends/azure.py +114 -0
  25. hypermind/crypto/kms_backends/gcp.py +97 -0
  26. hypermind/crypto/kms_backends/vault.py +120 -0
  27. hypermind/crypto/namespace_root.py +204 -0
  28. hypermind/crypto/pq.py +152 -0
  29. hypermind/crypto/room_epoch.py +97 -0
  30. hypermind/crypto/signing.py +245 -0
  31. hypermind/deliberation.py +355 -0
  32. hypermind/did_web.py +256 -0
  33. hypermind/dispute.py +858 -0
  34. hypermind/errors.py +218 -0
  35. hypermind/eval/__init__.py +49 -0
  36. hypermind/eval/calibration.py +307 -0
  37. hypermind/eval/comparison.py +251 -0
  38. hypermind/eval/replay.py +202 -0
  39. hypermind/eval/swarm_iq.py +718 -0
  40. hypermind/knowledge/__init__.py +17 -0
  41. hypermind/knowledge/citation_graph.py +141 -0
  42. hypermind/knowledge/correlated_agreement.py +167 -0
  43. hypermind/knowledge/embedding_registry.py +115 -0
  44. hypermind/knowledge/kernel_store.py +197 -0
  45. hypermind/knowledge/rekor.py +173 -0
  46. hypermind/knowledge/reputation.py +364 -0
  47. hypermind/knowledge/swarm_memory.py +523 -0
  48. hypermind/knowledge/transparency.py +409 -0
  49. hypermind/mcp/__init__.py +60 -0
  50. hypermind/mcp/bridge.py +151 -0
  51. hypermind/mcp/client.py +142 -0
  52. hypermind/mcp/provenance.py +214 -0
  53. hypermind/mcp/relata_tools.py +152 -0
  54. hypermind/mcp/server.py +248 -0
  55. hypermind/mcp/transport.py +206 -0
  56. hypermind/mind/__init__.py +150 -0
  57. hypermind/mind/active.py +234 -0
  58. hypermind/mind/belief.py +369 -0
  59. hypermind/mind/deliberator.py +625 -0
  60. hypermind/mind/diversity.py +144 -0
  61. hypermind/mind/evolve.py +184 -0
  62. hypermind/mind/federation.py +154 -0
  63. hypermind/mind/goals.py +117 -0
  64. hypermind/mind/integration.py +190 -0
  65. hypermind/mind/mediator.py +74 -0
  66. hypermind/mind/memory_store.py +129 -0
  67. hypermind/mind/policy.py +307 -0
  68. hypermind/mind/records.py +260 -0
  69. hypermind/mind/roles.py +190 -0
  70. hypermind/mind/sybil_guard.py +41 -0
  71. hypermind/mind/world_model.py +166 -0
  72. hypermind/namespace.py +515 -0
  73. hypermind/namespace_policy.py +254 -0
  74. hypermind/observability/__init__.py +25 -0
  75. hypermind/observability/asgi.py +214 -0
  76. hypermind/observability/cost.py +277 -0
  77. hypermind/observability/otel_export.py +200 -0
  78. hypermind/observability/recorder.py +344 -0
  79. hypermind/observability/swarm_trace.py +438 -0
  80. hypermind/pin_policy.py +116 -0
  81. hypermind/py.typed +0 -0
  82. hypermind/responders/__init__.py +87 -0
  83. hypermind/responders/anthropic.py +159 -0
  84. hypermind/responders/base.py +162 -0
  85. hypermind/responders/openai.py +199 -0
  86. hypermind/responders/router.py +254 -0
  87. hypermind/responders/structured.py +287 -0
  88. hypermind/responders/tools.py +444 -0
  89. hypermind/revocation.py +270 -0
  90. hypermind/rule_ids.py +135 -0
  91. hypermind/schemas/encrypted_statement.cddl +28 -0
  92. hypermind/schemas/namespace_accept.cddl +20 -0
  93. hypermind/schemas/namespace_create.cddl +25 -0
  94. hypermind/schemas/namespace_founding_attest.cddl +30 -0
  95. hypermind/schemas/namespace_invite.cddl +22 -0
  96. hypermind/schemas/wire-v0.1.cddl +73 -0
  97. hypermind/simlab/__init__.py +15 -0
  98. hypermind/simlab/_persona_registry.py +93 -0
  99. hypermind/simlab/_scenario_impl.py +2778 -0
  100. hypermind/simlab/app.py +2538 -0
  101. hypermind/simlab/backends/__init__.py +27 -0
  102. hypermind/simlab/backends/anchor.py +88 -0
  103. hypermind/simlab/backends/local.py +32 -0
  104. hypermind/simlab/backends/server.py +79 -0
  105. hypermind/simlab/cli_command.py +108 -0
  106. hypermind/simlab/config.py +106 -0
  107. hypermind/simlab/deployment.py +26 -0
  108. hypermind/simlab/knowledge.py +716 -0
  109. hypermind/simlab/learning.py +295 -0
  110. hypermind/simlab/modes/__init__.py +115 -0
  111. hypermind/simlab/modes/_eval_real_llm.py +373 -0
  112. hypermind/simlab/modes/aar.py +611 -0
  113. hypermind/simlab/modes/backtest.py +610 -0
  114. hypermind/simlab/modes/binary_forecast.py +69 -0
  115. hypermind/simlab/modes/conformance.py +1869 -0
  116. hypermind/simlab/modes/evaluation.py +2271 -0
  117. hypermind/simlab/modes/governance.py +648 -0
  118. hypermind/simlab/modes/redteam.py +534 -0
  119. hypermind/simlab/modes/tabletop.py +797 -0
  120. hypermind/simlab/modes/tournament.py +448 -0
  121. hypermind/simlab/modes/whatif.py +523 -0
  122. hypermind/simlab/namespace.py +125 -0
  123. hypermind/simlab/personas.py +477 -0
  124. hypermind/simlab/prompt_generator.py +172 -0
  125. hypermind/simlab/question_sets/geopolitics_q20.json +122 -0
  126. hypermind/simlab/question_sets/governance_q5.json +67 -0
  127. hypermind/simlab/question_sets/msft_outlook_q10.json +62 -0
  128. hypermind/simlab/question_sets/whatif_q3.json +38 -0
  129. hypermind/simlab/registry.py +325 -0
  130. hypermind/simlab/runner.py +239 -0
  131. hypermind/simlab/scenario.py +147 -0
  132. hypermind/simlab/swarms.py +180 -0
  133. hypermind/simlab/tool_handlers/__init__.py +4 -0
  134. hypermind/simlab/tool_handlers/alpha_vantage.py +39 -0
  135. hypermind/simlab/tool_handlers/brave.py +46 -0
  136. hypermind/simlab/tool_handlers/newsapi.py +50 -0
  137. hypermind/simlab/tool_handlers/openweather.py +46 -0
  138. hypermind/simlab/tool_handlers/pinecone.py +52 -0
  139. hypermind/simlab/tool_handlers/qdrant.py +57 -0
  140. hypermind/simlab/tool_handlers/query_knowledge_base.py +21 -0
  141. hypermind/simlab/tool_handlers/relata_recall.py +61 -0
  142. hypermind/simlab/tool_handlers/retrieve_document.py +21 -0
  143. hypermind/simlab/tool_handlers/serper.py +46 -0
  144. hypermind/simlab/tool_handlers/tavily.py +53 -0
  145. hypermind/simlab/tool_handlers/weaviate.py +65 -0
  146. hypermind/simlab/tool_handlers/wikipedia.py +64 -0
  147. hypermind/simlab/tool_handlers/wolfram.py +48 -0
  148. hypermind/simlab/tool_handlers/yahoo_finance.py +49 -0
  149. hypermind/simlab/tool_registry.py +568 -0
  150. hypermind/simlab/topic_adapter.py +338 -0
  151. hypermind/simlab/topic_questions.py +259 -0
  152. hypermind/storage/__init__.py +69 -0
  153. hypermind/storage/backend.py +71 -0
  154. hypermind/storage/relata.py +245 -0
  155. hypermind/storage/sqlite.py +258 -0
  156. hypermind/sync.py +191 -0
  157. hypermind/tal.py +175 -0
  158. hypermind/tasks.py +334 -0
  159. hypermind/testing.py +16 -0
  160. hypermind/tools/__init__.py +32 -0
  161. hypermind/tools/registry.py +61 -0
  162. hypermind/transport/__init__.py +22 -0
  163. hypermind/transport/anti_entropy.py +708 -0
  164. hypermind/transport/bus.py +206 -0
  165. hypermind/transport/knows_delta.py +204 -0
  166. hypermind/transport/libp2p.py +298 -0
  167. hypermind/transport/placement.py +58 -0
  168. hypermind/transport/tcp.py +797 -0
  169. hypermind/transport/tls_profile.py +417 -0
  170. hypermind/types.py +59 -0
  171. hypermind/uncertainty.py +222 -0
  172. hypermind/wire.py +897 -0
  173. hypermind/workflow/__init__.py +72 -0
  174. hypermind/workflow/engine.py +655 -0
  175. hypermind/workflow/plan.py +182 -0
  176. hypermind/workflow/repair.py +203 -0
  177. hypermind-0.11.0.dist-info/METADATA +524 -0
  178. hypermind-0.11.0.dist-info/RECORD +181 -0
  179. hypermind-0.11.0.dist-info/WHEEL +4 -0
  180. hypermind-0.11.0.dist-info/entry_points.txt +2 -0
  181. hypermind-0.11.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,568 @@
1
+ """Tool registry — catalog of available tools + namespace activation records.
2
+
3
+ Two layers:
4
+ TOOL_CATALOG — global, in-memory, immutable Python dict of all known tools.
5
+ ActivatedTool — per-namespace activation records persisted to disk.
6
+
7
+ Activation lifecycle: (not activated) → pending → verified → active
8
+ ↑ (credentials updated resets to pending)
9
+ active → disabled (soft-delete; record preserved)
10
+
11
+ # SECURITY NOTE
12
+ # Credentials are base64-encoded at rest in ~/.hypermind/tools/activated.json.
13
+ # Base64 is encoding, not encryption. The file is written with mode 0o600
14
+ # (owner read/write only) to limit exposure on shared systems, but this is
15
+ # NOT a substitute for proper secret management. For production deployments
16
+ # replace encode_credential / decode_credential with calls to your secret
17
+ # manager (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, etc.).
18
+
19
+ Public API:
20
+ ToolDef — catalog entry dataclass
21
+ ActivatedTool — namespace activation record dataclass
22
+ TOOL_CATALOG — dict[slug → ToolDef]
23
+ list_catalog() — list[ToolDef], sorted by category then name
24
+ get_tool_def(slug) — ToolDef | None
25
+ tools_dir() — Path to ~/.hypermind/tools/
26
+ load_activated_tools() — list[ActivatedTool] from disk
27
+ get_activated_tool(slug) — ActivatedTool | None
28
+ save_activated_tool(t) — atomic write
29
+ delete_activated_tool(slug) — remove record
30
+ list_active_tool_slugs() — list[str] where status == "active"
31
+ encode_credential(v) — base64 encode
32
+ decode_credential(v) — base64 decode
33
+ mask_credential(v) — first2…last2 of decoded value
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import base64
39
+ import json
40
+ import threading
41
+ from dataclasses import asdict, dataclass, field
42
+ from pathlib import Path
43
+ from typing import Any
44
+
45
+ from .registry import _write_json_atomic, home
46
+
47
+ # Module-level lock — guards all read-modify-write operations on activated.json
48
+ _registry_lock = threading.Lock()
49
+
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Data classes
53
+ # ---------------------------------------------------------------------------
54
+
55
+
56
+ @dataclass
57
+ class ToolDef:
58
+ slug: str
59
+ name: str
60
+ description: str
61
+ category: str # "knowledge" | "action" | "hybrid"
62
+ auth_type: str # "api_key" | "none"
63
+ parameters_schema: dict[str, Any]
64
+ handler_module: str # dotted import path
65
+ docs_url: str
66
+ icon: str # emoji
67
+ version: str
68
+ author: str
69
+ credentials_schema: dict[str, Any] # {field: {type, label, required, placeholder?}}
70
+
71
+ def to_dict(self) -> dict[str, Any]:
72
+ return asdict(self)
73
+
74
+
75
+ @dataclass
76
+ class ActivatedTool:
77
+ tool_slug: str
78
+ status: str # "pending" | "verified" | "active" | "disabled"
79
+ credentials: dict[str, str] = field(default_factory=dict) # base64-encoded values
80
+ label: str = ""
81
+ activated_at_ms: int | None = None
82
+ last_tested_ms: int | None = None
83
+ error_msg: str | None = None
84
+
85
+ def to_dict(self) -> dict[str, Any]:
86
+ return asdict(self)
87
+
88
+ def to_api_dict(self) -> dict[str, Any]:
89
+ """Return dict safe for HTTP responses — credentials masked, never raw."""
90
+ d = self.to_dict()
91
+ d["credentials_masked"] = {k: mask_credential(v) for k, v in self.credentials.items()}
92
+ del d["credentials"]
93
+ return d
94
+
95
+ @classmethod
96
+ def from_dict(cls, d: dict[str, Any]) -> ActivatedTool:
97
+ known = {f.name for f in cls.__dataclass_fields__.values()} # type: ignore[attr-defined]
98
+ clean = {k: v for k, v in d.items() if k in known}
99
+ return cls(**clean)
100
+
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # Credential helpers
104
+ # ---------------------------------------------------------------------------
105
+
106
+
107
+ def encode_credential(value: str) -> str:
108
+ return base64.b64encode(value.encode()).decode()
109
+
110
+
111
+ def decode_credential(encoded: str) -> str:
112
+ try:
113
+ return base64.b64decode(encoded.encode()).decode()
114
+ except Exception:
115
+ return ""
116
+
117
+
118
+ def mask_credential(encoded: str) -> str:
119
+ decoded = decode_credential(encoded)
120
+ if len(decoded) < 8:
121
+ return "*" * len(decoded)
122
+ return decoded[:2] + "****" + decoded[-2:]
123
+
124
+
125
+ # ---------------------------------------------------------------------------
126
+ # Built-in tool catalog
127
+ # ---------------------------------------------------------------------------
128
+
129
+
130
+ def _web_search_schema() -> dict[str, Any]:
131
+ return {
132
+ "type": "object",
133
+ "properties": {
134
+ "query": {"type": "string", "description": "Search query"},
135
+ "max_results": {"type": "integer", "default": 5},
136
+ },
137
+ "required": ["query"],
138
+ }
139
+
140
+
141
+ def _doc_id_schema() -> dict[str, Any]:
142
+ return {
143
+ "type": "object",
144
+ "properties": {
145
+ "doc_id": {"type": "string", "description": "Document identifier"},
146
+ },
147
+ "required": ["doc_id"],
148
+ }
149
+
150
+
151
+ def _kb_query_schema() -> dict[str, Any]:
152
+ return {
153
+ "type": "object",
154
+ "properties": {
155
+ "query": {"type": "string", "description": "Semantic search query"},
156
+ "top_k": {"type": "integer", "default": 5},
157
+ },
158
+ "required": ["query"],
159
+ }
160
+
161
+
162
+ def _finance_schema() -> dict[str, Any]:
163
+ return {
164
+ "type": "object",
165
+ "properties": {
166
+ "symbol": {"type": "string", "description": "Stock ticker symbol e.g. AAPL"},
167
+ "function": {"type": "string", "default": "GLOBAL_QUOTE"},
168
+ },
169
+ "required": ["symbol"],
170
+ }
171
+
172
+
173
+ def _news_schema() -> dict[str, Any]:
174
+ return {
175
+ "type": "object",
176
+ "properties": {
177
+ "query": {"type": "string", "description": "News search query or topic"},
178
+ "page_size": {"type": "integer", "default": 5},
179
+ },
180
+ "required": ["query"],
181
+ }
182
+
183
+
184
+ def _api_key_cred() -> dict[str, Any]:
185
+ return {
186
+ "api_key": {
187
+ "type": "password",
188
+ "label": "API Key",
189
+ "required": True,
190
+ "placeholder": "sk-...",
191
+ }
192
+ }
193
+
194
+
195
+ def _api_key_and_url_cred(url_label: str = "API URL", url_required: bool = False) -> dict[str, Any]:
196
+ return {
197
+ "api_key": {
198
+ "type": "password",
199
+ "label": "API Key",
200
+ "required": True,
201
+ "placeholder": "...",
202
+ },
203
+ "base_url": {
204
+ "type": "url",
205
+ "label": url_label,
206
+ "required": url_required,
207
+ "placeholder": "https://...",
208
+ },
209
+ }
210
+
211
+
212
+ TOOL_CATALOG: dict[str, ToolDef] = {
213
+ # ---- Web search ----------------------------------------------------------
214
+ "brave_web_search": ToolDef(
215
+ slug="brave_web_search",
216
+ name="Brave Web Search",
217
+ description="Search the public web via Brave's privacy-preserving search API. Returns titles, URLs, and snippets.",
218
+ category="knowledge",
219
+ auth_type="api_key",
220
+ parameters_schema=_web_search_schema(),
221
+ handler_module="hypermind.simlab.tool_handlers.brave",
222
+ docs_url="https://api.search.brave.com/app/documentation/web-search",
223
+ icon="🦁",
224
+ version="1.0",
225
+ author="hypermind",
226
+ credentials_schema=_api_key_cred(),
227
+ ),
228
+ "tavily_search": ToolDef(
229
+ slug="tavily_search",
230
+ name="Tavily AI Search",
231
+ description="AI-optimised web search designed for LLM agents. Returns cleaned, answer-ready results.",
232
+ category="knowledge",
233
+ auth_type="api_key",
234
+ parameters_schema=_web_search_schema(),
235
+ handler_module="hypermind.simlab.tool_handlers.tavily",
236
+ docs_url="https://docs.tavily.com/docs/tavily-api/rest_api",
237
+ icon="🔍",
238
+ version="1.0",
239
+ author="hypermind",
240
+ credentials_schema=_api_key_cred(),
241
+ ),
242
+ "serper_web_search": ToolDef(
243
+ slug="serper_web_search",
244
+ name="Serper Web Search",
245
+ description="Google search results via the Serper API. Affordable, fast, broad coverage.",
246
+ category="knowledge",
247
+ auth_type="api_key",
248
+ parameters_schema=_web_search_schema(),
249
+ handler_module="hypermind.simlab.tool_handlers.serper",
250
+ docs_url="https://serper.dev/",
251
+ icon="🌐",
252
+ version="1.0",
253
+ author="hypermind",
254
+ credentials_schema=_api_key_cred(),
255
+ ),
256
+ # ---- Finance & news ------------------------------------------------------
257
+ "alpha_vantage": ToolDef(
258
+ slug="alpha_vantage",
259
+ name="Alpha Vantage",
260
+ description="Real-time and historical financial data: equities, forex, crypto, and macroeconomic indicators.",
261
+ category="knowledge",
262
+ auth_type="api_key",
263
+ parameters_schema=_finance_schema(),
264
+ handler_module="hypermind.simlab.tool_handlers.alpha_vantage",
265
+ docs_url="https://www.alphavantage.co/documentation/",
266
+ icon="📈",
267
+ version="1.0",
268
+ author="hypermind",
269
+ credentials_schema=_api_key_cred(),
270
+ ),
271
+ "newsapi_headlines": ToolDef(
272
+ slug="newsapi_headlines",
273
+ name="NewsAPI Headlines",
274
+ description="Top headlines and article search from 80,000+ news sources worldwide.",
275
+ category="knowledge",
276
+ auth_type="api_key",
277
+ parameters_schema=_news_schema(),
278
+ handler_module="hypermind.simlab.tool_handlers.newsapi",
279
+ docs_url="https://newsapi.org/docs",
280
+ icon="📰",
281
+ version="1.0",
282
+ author="hypermind",
283
+ credentials_schema=_api_key_cred(),
284
+ ),
285
+ "yahoo_finance": ToolDef(
286
+ slug="yahoo_finance",
287
+ name="Yahoo Finance",
288
+ description="Free financial data via Yahoo Finance — stock quotes, price history, company info. No API key required.",
289
+ category="knowledge",
290
+ auth_type="none",
291
+ parameters_schema={
292
+ "type": "object",
293
+ "properties": {
294
+ "symbol": {"type": "string", "description": "Stock ticker e.g. AAPL"},
295
+ "period": {
296
+ "type": "string",
297
+ "default": "1mo",
298
+ "description": "e.g. 1d, 5d, 1mo, 3mo, 1y",
299
+ },
300
+ },
301
+ "required": ["symbol"],
302
+ },
303
+ handler_module="hypermind.simlab.tool_handlers.yahoo_finance",
304
+ docs_url="https://finance.yahoo.com/",
305
+ icon="💹",
306
+ version="1.0",
307
+ author="hypermind",
308
+ credentials_schema={},
309
+ ),
310
+ # ---- Reference -----------------------------------------------------------
311
+ "wikipedia_search": ToolDef(
312
+ slug="wikipedia_search",
313
+ name="Wikipedia Search",
314
+ description="Search and retrieve Wikipedia article summaries. No API key required.",
315
+ category="knowledge",
316
+ auth_type="none",
317
+ parameters_schema=_web_search_schema(),
318
+ handler_module="hypermind.simlab.tool_handlers.wikipedia",
319
+ docs_url="https://en.wikipedia.org/api/rest_v1/",
320
+ icon="📚",
321
+ version="1.0",
322
+ author="hypermind",
323
+ credentials_schema={},
324
+ ),
325
+ "wolfram_alpha": ToolDef(
326
+ slug="wolfram_alpha",
327
+ name="Wolfram Alpha",
328
+ description="Computational knowledge engine — maths, science, statistics, unit conversions, factual queries.",
329
+ category="knowledge",
330
+ auth_type="api_key",
331
+ parameters_schema={
332
+ "type": "object",
333
+ "properties": {
334
+ "query": {
335
+ "type": "string",
336
+ "description": "Natural language or mathematical query",
337
+ },
338
+ },
339
+ "required": ["query"],
340
+ },
341
+ handler_module="hypermind.simlab.tool_handlers.wolfram",
342
+ docs_url="https://products.wolframalpha.com/api/documentation/",
343
+ icon="🧮",
344
+ version="1.0",
345
+ author="hypermind",
346
+ credentials_schema=_api_key_cred(),
347
+ ),
348
+ "openweathermap": ToolDef(
349
+ slug="openweathermap",
350
+ name="OpenWeatherMap",
351
+ description="Current weather and 5-day forecast for any city or coordinates worldwide.",
352
+ category="knowledge",
353
+ auth_type="api_key",
354
+ parameters_schema={
355
+ "type": "object",
356
+ "properties": {
357
+ "location": {"type": "string", "description": "City name or 'lat,lon'"},
358
+ "units": {
359
+ "type": "string",
360
+ "default": "metric",
361
+ "description": "metric | imperial | standard",
362
+ },
363
+ },
364
+ "required": ["location"],
365
+ },
366
+ handler_module="hypermind.simlab.tool_handlers.openweather",
367
+ docs_url="https://openweathermap.org/api",
368
+ icon="🌤",
369
+ version="1.0",
370
+ author="hypermind",
371
+ credentials_schema=_api_key_cred(),
372
+ ),
373
+ # ---- Vector databases ----------------------------------------------------
374
+ "pinecone_search": ToolDef(
375
+ slug="pinecone_search",
376
+ name="Pinecone Vector Search",
377
+ description="Semantic search against a Pinecone index. Requires a configured index and embedding model.",
378
+ category="knowledge",
379
+ auth_type="api_key",
380
+ parameters_schema=_kb_query_schema(),
381
+ handler_module="hypermind.simlab.tool_handlers.pinecone",
382
+ docs_url="https://docs.pinecone.io/",
383
+ icon="🌲",
384
+ version="1.0",
385
+ author="hypermind",
386
+ credentials_schema={
387
+ "api_key": {
388
+ "type": "password",
389
+ "label": "API Key",
390
+ "required": True,
391
+ "placeholder": "",
392
+ },
393
+ "index_name": {
394
+ "type": "string",
395
+ "label": "Index Name",
396
+ "required": True,
397
+ "placeholder": "my-index",
398
+ },
399
+ "environment": {
400
+ "type": "string",
401
+ "label": "Environment",
402
+ "required": False,
403
+ "placeholder": "us-east-1-aws",
404
+ },
405
+ },
406
+ ),
407
+ "qdrant_search": ToolDef(
408
+ slug="qdrant_search",
409
+ name="Qdrant Vector Search",
410
+ description="Semantic search against a Qdrant collection. Self-hosted or Qdrant Cloud.",
411
+ category="knowledge",
412
+ auth_type="api_key",
413
+ parameters_schema=_kb_query_schema(),
414
+ handler_module="hypermind.simlab.tool_handlers.qdrant",
415
+ docs_url="https://qdrant.tech/documentation/",
416
+ icon="🔷",
417
+ version="1.0",
418
+ author="hypermind",
419
+ credentials_schema={
420
+ "api_key": {
421
+ "type": "password",
422
+ "label": "API Key",
423
+ "required": False,
424
+ "placeholder": "(leave blank for local)",
425
+ },
426
+ "base_url": {
427
+ "type": "url",
428
+ "label": "Qdrant URL",
429
+ "required": True,
430
+ "placeholder": "http://localhost:6333",
431
+ },
432
+ "collection": {
433
+ "type": "string",
434
+ "label": "Collection Name",
435
+ "required": True,
436
+ "placeholder": "my-collection",
437
+ },
438
+ },
439
+ ),
440
+ "weaviate_search": ToolDef(
441
+ slug="weaviate_search",
442
+ name="Weaviate Semantic Search",
443
+ description="Semantic search against a Weaviate schema class. Supports hybrid BM25+vector search.",
444
+ category="knowledge",
445
+ auth_type="api_key",
446
+ parameters_schema=_kb_query_schema(),
447
+ handler_module="hypermind.simlab.tool_handlers.weaviate",
448
+ docs_url="https://weaviate.io/developers/weaviate",
449
+ icon="🕸",
450
+ version="1.0",
451
+ author="hypermind",
452
+ credentials_schema={
453
+ "api_key": {
454
+ "type": "password",
455
+ "label": "API Key",
456
+ "required": False,
457
+ "placeholder": "(leave blank for local)",
458
+ },
459
+ "base_url": {
460
+ "type": "url",
461
+ "label": "Weaviate URL",
462
+ "required": True,
463
+ "placeholder": "http://localhost:8080",
464
+ },
465
+ "class_name": {
466
+ "type": "string",
467
+ "label": "Class Name",
468
+ "required": True,
469
+ "placeholder": "Document",
470
+ },
471
+ },
472
+ ),
473
+ # ---- Built-in stubs (backwards-compat) -----------------------------------
474
+ "retrieve_document": ToolDef(
475
+ slug="retrieve_document",
476
+ name="Document Retrieval",
477
+ description="Retrieve a document by ID from a configured store. Built-in stub — override the handler to connect a real backend.",
478
+ category="knowledge",
479
+ auth_type="none",
480
+ parameters_schema=_doc_id_schema(),
481
+ handler_module="hypermind.simlab.tool_handlers.retrieve_document",
482
+ docs_url="",
483
+ icon="📄",
484
+ version="1.0",
485
+ author="hypermind",
486
+ credentials_schema={},
487
+ ),
488
+ "query_knowledge_base": ToolDef(
489
+ slug="query_knowledge_base",
490
+ name="HyperMind Knowledge Base",
491
+ description="Vector-search the HyperMind federation knowledge base for relevant sealed claims.",
492
+ category="knowledge",
493
+ auth_type="none",
494
+ parameters_schema=_kb_query_schema(),
495
+ handler_module="hypermind.simlab.tool_handlers.query_knowledge_base",
496
+ docs_url="",
497
+ icon="🧠",
498
+ version="1.0",
499
+ author="hypermind",
500
+ credentials_schema={},
501
+ ),
502
+ }
503
+
504
+
505
+ # ---------------------------------------------------------------------------
506
+ # Catalog accessors
507
+ # ---------------------------------------------------------------------------
508
+
509
+
510
+ def list_catalog() -> list[ToolDef]:
511
+ return sorted(TOOL_CATALOG.values(), key=lambda t: (t.category, t.name))
512
+
513
+
514
+ def get_tool_def(slug: str) -> ToolDef | None:
515
+ return TOOL_CATALOG.get(slug)
516
+
517
+
518
+ # ---------------------------------------------------------------------------
519
+ # Disk storage
520
+ # ---------------------------------------------------------------------------
521
+
522
+
523
+ def tools_dir() -> Path:
524
+ d = home() / "tools"
525
+ d.mkdir(parents=True, exist_ok=True)
526
+ return d
527
+
528
+
529
+ def _activated_path() -> Path:
530
+ return tools_dir() / "activated.json"
531
+
532
+
533
+ def load_activated_tools() -> list[ActivatedTool]:
534
+ p = _activated_path()
535
+ if not p.exists():
536
+ return []
537
+ try:
538
+ data = json.loads(p.read_text())
539
+ return [ActivatedTool.from_dict(d) for d in data]
540
+ except Exception:
541
+ return []
542
+
543
+
544
+ def get_activated_tool(slug: str) -> ActivatedTool | None:
545
+ for t in load_activated_tools():
546
+ if t.tool_slug == slug:
547
+ return t
548
+ return None
549
+
550
+
551
+ def save_activated_tool(t: ActivatedTool) -> None:
552
+ with _registry_lock:
553
+ tools = load_activated_tools()
554
+ tools = [x for x in tools if x.tool_slug != t.tool_slug]
555
+ tools.append(t)
556
+ path = _activated_path()
557
+ _write_json_atomic(path, [x.to_dict() for x in tools], mode=0o600)
558
+
559
+
560
+ def delete_activated_tool(slug: str) -> None:
561
+ with _registry_lock:
562
+ tools = [t for t in load_activated_tools() if t.tool_slug != slug]
563
+ path = _activated_path()
564
+ _write_json_atomic(path, [t.to_dict() for t in tools], mode=0o600)
565
+
566
+
567
+ def list_active_tool_slugs() -> list[str]:
568
+ return [t.tool_slug for t in load_activated_tools() if t.status == "active"]