hyperagents 1.2.3rc5.post3__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 (361) hide show
  1. agents/__init__.py +31 -0
  2. agents/background_monitor.py +453 -0
  3. agents/learning.py +460 -0
  4. agents/planner.py +421 -0
  5. agents/transcriber.py +341 -0
  6. civilization/__init__.py +51 -0
  7. civilization/api/__init__.py +7 -0
  8. civilization/api/civilization_api.py +361 -0
  9. civilization/graph/__init__.py +19 -0
  10. civilization/graph/knowledge_linker.py +348 -0
  11. civilization/graph/org_graph.py +348 -0
  12. civilization/graph/process_graph.py +386 -0
  13. civilization/ingestion/__init__.py +20 -0
  14. civilization/ingestion/chunker.py +273 -0
  15. civilization/ingestion/document_ingestor.py +358 -0
  16. civilization/ingestion/embedder.py +262 -0
  17. civilization/ingestion/extractor.py +224 -0
  18. civilization/interview/__init__.py +19 -0
  19. civilization/interview/gap_detector.py +380 -0
  20. civilization/interview/interviewer.py +323 -0
  21. civilization/interview/questioner.py +363 -0
  22. civilization/retrieval/__init__.py +17 -0
  23. civilization/retrieval/civilization_rag.py +316 -0
  24. civilization/retrieval/context_injector.py +342 -0
  25. civilization/retrieval/relevance_ranker.py +287 -0
  26. civilization/schema.py +299 -0
  27. civilization/store.py +177 -0
  28. civilization/sync/__init__.py +16 -0
  29. civilization/sync/confluence_sync.py +317 -0
  30. civilization/sync/gdrive_sync.py +262 -0
  31. civilization/sync/notion_sync.py +237 -0
  32. civilization/versioning/__init__.py +19 -0
  33. civilization/versioning/diff_engine.py +351 -0
  34. civilization/versioning/staleness_detector.py +303 -0
  35. civilization/versioning/version_manager.py +293 -0
  36. cli/__init__.py +1 -0
  37. cli/doctor.py +334 -0
  38. cli/hyperclaw.py +1357 -0
  39. cli/onboarding.py +469 -0
  40. core/__init__.py +1 -0
  41. core/connectors/__init__.py +119 -0
  42. core/connectors/infrastructure.py +772 -0
  43. core/connectors/messaging.py +586 -0
  44. core/connectors/productivity.py +764 -0
  45. core/connectors/smarthome.py +528 -0
  46. core/connectors/social.py +730 -0
  47. core/hyperrouter/__init__.py +23 -0
  48. core/hyperrouter/bandit.py +218 -0
  49. core/hyperrouter/fast_loop.py +68 -0
  50. core/hyperrouter/slow_loop.py +143 -0
  51. core/hyperstate/__init__.py +24 -0
  52. core/hyperstate/certifier.py +154 -0
  53. core/hyperstate/schema.py +160 -0
  54. core/hyperstate/state_manager.py +103 -0
  55. core/hyperstate/store.py +163 -0
  56. core/providers/__init__.py +121 -0
  57. core/providers/embeddings.py +389 -0
  58. core/providers/image.py +534 -0
  59. core/providers/llm.py +1935 -0
  60. core/providers/search.py +608 -0
  61. core/providers/voice.py +474 -0
  62. hyperagents-1.2.3rc5.post3.dist-info/METADATA +469 -0
  63. hyperagents-1.2.3rc5.post3.dist-info/RECORD +361 -0
  64. hyperagents-1.2.3rc5.post3.dist-info/WHEEL +5 -0
  65. hyperagents-1.2.3rc5.post3.dist-info/entry_points.txt +6 -0
  66. hyperagents-1.2.3rc5.post3.dist-info/licenses/LICENSE +21 -0
  67. hyperagents-1.2.3rc5.post3.dist-info/top_level.txt +13 -0
  68. hyperclaw/__init__.py +67 -0
  69. hyperclaw/__main__.py +220 -0
  70. hyperclaw/agent.py +775 -0
  71. hyperclaw/agent_coordinator.py +577 -0
  72. hyperclaw/anthropic_params.py +225 -0
  73. hyperclaw/api_utils.py +85 -0
  74. hyperclaw/approval_telegram.py +209 -0
  75. hyperclaw/approval_terminal.py +80 -0
  76. hyperclaw/attachments.py +177 -0
  77. hyperclaw/branding.py +55 -0
  78. hyperclaw/brief/__init__.py +11 -0
  79. hyperclaw/brief/cli.py +204 -0
  80. hyperclaw/brief/collect.py +146 -0
  81. hyperclaw/brief/compose.py +333 -0
  82. hyperclaw/brief/diff.py +110 -0
  83. hyperclaw/brief/errors.py +99 -0
  84. hyperclaw/brief/google.py +269 -0
  85. hyperclaw/brief/google_auth.py +294 -0
  86. hyperclaw/brief/links.py +124 -0
  87. hyperclaw/brief/service.py +424 -0
  88. hyperclaw/brief/store.py +205 -0
  89. hyperclaw/brief/tasks.py +200 -0
  90. hyperclaw/chat_scope.py +115 -0
  91. hyperclaw/cli_tui.py +497 -0
  92. hyperclaw/client_guard.py +717 -0
  93. hyperclaw/connection_check.py +113 -0
  94. hyperclaw/cost_guard.py +1728 -0
  95. hyperclaw/default_config/agents.yaml +534 -0
  96. hyperclaw/default_config/hyperclaw.yaml +27 -0
  97. hyperclaw/default_config/models.yaml +161 -0
  98. hyperclaw/deployment.py +39 -0
  99. hyperclaw/digest/__init__.py +9 -0
  100. hyperclaw/digest/cli.py +117 -0
  101. hyperclaw/digest/errors.py +100 -0
  102. hyperclaw/digest/gitlab.py +187 -0
  103. hyperclaw/digest/http.py +113 -0
  104. hyperclaw/digest/redact.py +32 -0
  105. hyperclaw/digest/service.py +271 -0
  106. hyperclaw/digest/slack.py +223 -0
  107. hyperclaw/digest/state.py +124 -0
  108. hyperclaw/digest/summarize.py +198 -0
  109. hyperclaw/digest/tokens.py +143 -0
  110. hyperclaw/distribution.py +46 -0
  111. hyperclaw/documents.py +351 -0
  112. hyperclaw/feeds.py +339 -0
  113. hyperclaw/google_workspace/__init__.py +5 -0
  114. hyperclaw/google_workspace/api.py +151 -0
  115. hyperclaw/google_workspace/auth.py +397 -0
  116. hyperclaw/google_workspace/calendar.py +157 -0
  117. hyperclaw/google_workspace/cli.py +72 -0
  118. hyperclaw/google_workspace/drive.py +236 -0
  119. hyperclaw/google_workspace/errors.py +58 -0
  120. hyperclaw/google_workspace/gmail.py +295 -0
  121. hyperclaw/google_workspace/meet.py +122 -0
  122. hyperclaw/google_workspace/tools.py +319 -0
  123. hyperclaw/hyperspeed.py +57 -0
  124. hyperclaw/integrations_layer.py +1427 -0
  125. hyperclaw/live_state.py +188 -0
  126. hyperclaw/managed_config.py +245 -0
  127. hyperclaw/media_hub.py +179 -0
  128. hyperclaw/memory_manager.py +584 -0
  129. hyperclaw/model_catalog.py +551 -0
  130. hyperclaw/model_policy.py +211 -0
  131. hyperclaw/model_router.py +595 -0
  132. hyperclaw/model_selector.py +72 -0
  133. hyperclaw/naming.py +284 -0
  134. hyperclaw/notices.py +65 -0
  135. hyperclaw/oai_stream.py +106 -0
  136. hyperclaw/orchestrator.py +591 -0
  137. hyperclaw/outbox.py +82 -0
  138. hyperclaw/persona.py +367 -0
  139. hyperclaw/prometheus.py +219 -0
  140. hyperclaw/prompt_assembly.py +157 -0
  141. hyperclaw/provider_setup.py +146 -0
  142. hyperclaw/providers.py +340 -0
  143. hyperclaw/qualification.py +341 -0
  144. hyperclaw/qualification_keys/hyper-d292fd127cef5a3e.pub +1 -0
  145. hyperclaw/qualification_records/anthropic--claude-sonnet-5-5.json +14 -0
  146. hyperclaw/reasoning_display.py +35 -0
  147. hyperclaw/scheduler.py +454 -0
  148. hyperclaw/server.py +847 -0
  149. hyperclaw/setup.py +627 -0
  150. hyperclaw/skills.py +717 -0
  151. hyperclaw/solomon.py +442 -0
  152. hyperclaw/swarm.py +533 -0
  153. hyperclaw/taint.py +832 -0
  154. hyperclaw/team/__init__.py +28 -0
  155. hyperclaw/team/dispatcher.py +431 -0
  156. hyperclaw/team/genesis.py +106 -0
  157. hyperclaw/team/lead.py +110 -0
  158. hyperclaw/team/model.py +135 -0
  159. hyperclaw/team/morning.py +238 -0
  160. hyperclaw/team/repos.py +66 -0
  161. hyperclaw/team/roster.py +264 -0
  162. hyperclaw/team/specialist.py +235 -0
  163. hyperclaw/team/status.py +163 -0
  164. hyperclaw/team/watchers.py +112 -0
  165. hyperclaw/teamsetup/__init__.py +17 -0
  166. hyperclaw/teamsetup/checks.py +208 -0
  167. hyperclaw/teamsetup/item.py +391 -0
  168. hyperclaw/teamsetup/oauth_loopback.py +84 -0
  169. hyperclaw/teamsetup/onboard.py +550 -0
  170. hyperclaw/teamsetup/profile.py +82 -0
  171. hyperclaw/teamsetup/secrets.py +313 -0
  172. hyperclaw/teamsetup/selfcheck.py +295 -0
  173. hyperclaw/teamsetup/service.py +495 -0
  174. hyperclaw/teamsetup/slack_oauth.py +442 -0
  175. hyperclaw/teamsetup/tty.py +62 -0
  176. hyperclaw/telegram_bot.py +1106 -0
  177. hyperclaw/telegram_intake.py +126 -0
  178. hyperclaw/telegram_pairing.py +360 -0
  179. hyperclaw/terminal_provider.py +323 -0
  180. hyperclaw/tools/__init__.py +1 -0
  181. hyperclaw/tools/approval.py +949 -0
  182. hyperclaw/tools/args.py +212 -0
  183. hyperclaw/tools/catalog.py +244 -0
  184. hyperclaw/tools/classify.py +266 -0
  185. hyperclaw/tools/effects.py +724 -0
  186. hyperclaw/tools/egress.py +210 -0
  187. hyperclaw/tools/envelope.py +188 -0
  188. hyperclaw/tools/guard.py +367 -0
  189. hyperclaw/tools/ledger.py +339 -0
  190. hyperclaw/tools/receipts.py +70 -0
  191. hyperclaw/tools/registry.py +318 -0
  192. hyperclaw/tools/service_guard.py +151 -0
  193. hyperclaw/tools/surfaces.py +54 -0
  194. hyperclaw/tools/workspace.py +87 -0
  195. hyperclaw/trading/__init__.py +77 -0
  196. hyperclaw/truth_guard.py +791 -0
  197. hyperclaw/tts.py +124 -0
  198. hyperclaw/tui.py +4255 -0
  199. hyperclaw/tui_bridge.py +938 -0
  200. hyperclaw/unattended.py +60 -0
  201. hyperclaw/updates/__init__.py +54 -0
  202. hyperclaw/updates/check.py +131 -0
  203. hyperclaw/updates/index.py +178 -0
  204. hyperclaw/updates/install.py +110 -0
  205. hyperclaw/updates/managed.py +161 -0
  206. hyperclaw/updates/manifest.py +138 -0
  207. hyperclaw/updates/notices.py +86 -0
  208. hyperclaw/updates/paths.py +53 -0
  209. hyperclaw/updates/release.py +146 -0
  210. hyperclaw/updates/upgrade.py +253 -0
  211. hyperclaw/updates/versioning.py +104 -0
  212. hyperclaw/userconfig.py +119 -0
  213. hyperclaw/xai.py +83 -0
  214. integrations/__init__.py +31 -0
  215. integrations/automation/__init__.py +1 -0
  216. integrations/automation/make.py +87 -0
  217. integrations/automation/zapier.py +87 -0
  218. integrations/base.py +476 -0
  219. integrations/communication/__init__.py +1 -0
  220. integrations/communication/twilio.py +279 -0
  221. integrations/communication/zoom.py +290 -0
  222. integrations/data/__init__.py +1 -0
  223. integrations/data/google_analytics.py +135 -0
  224. integrations/data/postgres.py +182 -0
  225. integrations/data/supabase_connector.py +202 -0
  226. integrations/data/weather_feeds.py +450 -0
  227. integrations/developer/__init__.py +9 -0
  228. integrations/developer/github.py +406 -0
  229. integrations/developer/gitlab.py +298 -0
  230. integrations/enterprise/__init__.py +13 -0
  231. integrations/enterprise/confluence.py +266 -0
  232. integrations/enterprise/hubspot.py +293 -0
  233. integrations/enterprise/jira.py +314 -0
  234. integrations/enterprise/salesforce.py +286 -0
  235. integrations/finance/__init__.py +1 -0
  236. integrations/finance/polymarket_client.py +247 -0
  237. integrations/finance/quickbooks.py +281 -0
  238. integrations/finance/stripe.py +261 -0
  239. integrations/gateway.py +238 -0
  240. integrations/messaging/__init__.py +32 -0
  241. integrations/messaging/discord.py +159 -0
  242. integrations/messaging/email.py +401 -0
  243. integrations/messaging/imessage.py +443 -0
  244. integrations/messaging/signal.py +175 -0
  245. integrations/messaging/slack.py +217 -0
  246. integrations/messaging/sms.py +175 -0
  247. integrations/messaging/teams.py +208 -0
  248. integrations/messaging/telegram.py +260 -0
  249. integrations/messaging/whatsapp.py +203 -0
  250. integrations/productivity/__init__.py +17 -0
  251. integrations/productivity/airtable.py +217 -0
  252. integrations/productivity/asana.py +248 -0
  253. integrations/productivity/google/__init__.py +19 -0
  254. integrations/productivity/google/base.py +89 -0
  255. integrations/productivity/google/calendar.py +272 -0
  256. integrations/productivity/google/docs.py +202 -0
  257. integrations/productivity/google/drive.py +268 -0
  258. integrations/productivity/google/gmail.py +279 -0
  259. integrations/productivity/google/meet.py +218 -0
  260. integrations/productivity/google/sheets.py +222 -0
  261. integrations/productivity/google/tasks.py +199 -0
  262. integrations/productivity/linear.py +279 -0
  263. integrations/productivity/microsoft/__init__.py +13 -0
  264. integrations/productivity/microsoft/base.py +93 -0
  265. integrations/productivity/microsoft/calendar.py +207 -0
  266. integrations/productivity/microsoft/onedrive.py +222 -0
  267. integrations/productivity/microsoft/outlook.py +241 -0
  268. integrations/productivity/microsoft/sharepoint.py +211 -0
  269. integrations/productivity/notion.py +243 -0
  270. integrations/productivity/todoist.py +250 -0
  271. integrations/productivity/trello.py +244 -0
  272. integrations/storage/__init__.py +1 -0
  273. integrations/storage/box.py +279 -0
  274. integrations/storage/dropbox.py +215 -0
  275. integrations/telegram_inbound.py +179 -0
  276. integrations/telegram_poller.py +151 -0
  277. memory/__init__.py +1 -0
  278. memory/causal_graph.py +125 -0
  279. memory/impact_tracker.py +88 -0
  280. memory/vector_memory.py +436 -0
  281. models/__init__.py +12 -0
  282. models/chatjimmy_client.py +210 -0
  283. models/claude_client.py +235 -0
  284. models/claude_code_subagent.py +192 -0
  285. models/openai_client.py +120 -0
  286. models/router.py +162 -0
  287. recursive/discovery_loop.py +118 -0
  288. recursive/optimization_loop.py +135 -0
  289. recursive/validation_loop.py +38 -0
  290. security/__init__.py +1 -0
  291. security/audit_logger.py +106 -0
  292. security/filesystem_guard.py +100 -0
  293. security/hypershield.py +99 -0
  294. security/network_guard.py +97 -0
  295. security/policy_engine.py +198 -0
  296. swarm/__init__.py +1 -0
  297. swarm/agents/__init__.py +0 -0
  298. swarm/agents/base.py +230 -0
  299. swarm/agents/business/__init__.py +0 -0
  300. swarm/agents/business/counsel.py +31 -0
  301. swarm/agents/business/herald.py +32 -0
  302. swarm/agents/business/ledger.py +26 -0
  303. swarm/agents/business/nexus.py +30 -0
  304. swarm/agents/business/ops.py +30 -0
  305. swarm/agents/business/pipeline.py +28 -0
  306. swarm/agents/business/revenue.py +30 -0
  307. swarm/agents/business/sovereign.py +31 -0
  308. swarm/agents/business/strategos.py +27 -0
  309. swarm/agents/business/talent.py +27 -0
  310. swarm/agents/business/venture.py +32 -0
  311. swarm/agents/comms/__init__.py +1 -0
  312. swarm/agents/comms/cipher.py +32 -0
  313. swarm/agents/comms/echo_comms.py +31 -0
  314. swarm/agents/comms/envoy.py +31 -0
  315. swarm/agents/comms/herald_scheduler.py +33 -0
  316. swarm/agents/comms/pulse.py +29 -0
  317. swarm/agents/creative/__init__.py +0 -0
  318. swarm/agents/creative/author.py +27 -0
  319. swarm/agents/creative/lens.py +25 -0
  320. swarm/agents/executive/__init__.py +1 -0
  321. swarm/agents/intelligence/__init__.py +1 -0
  322. swarm/agents/intelligence/arbiter.py +30 -0
  323. swarm/agents/intelligence/sentinel.py +30 -0
  324. swarm/agents/media/__init__.py +0 -0
  325. swarm/agents/personal/__init__.py +0 -0
  326. swarm/agents/personal/atlas.py +27 -0
  327. swarm/agents/personal/hearth.py +26 -0
  328. swarm/agents/personal/midas.py +27 -0
  329. swarm/agents/personal/navigator.py +27 -0
  330. swarm/agents/personal/nourish.py +31 -0
  331. swarm/agents/personal/vitals.py +33 -0
  332. swarm/agents/recursive/__init__.py +0 -0
  333. swarm/agents/recursive/alchemist.py +73 -0
  334. swarm/agents/recursive/calibrator.py +45 -0
  335. swarm/agents/recursive/scout.py +97 -0
  336. swarm/agents/scientific/__init__.py +0 -0
  337. swarm/agents/scientific/cosmos.py +36 -0
  338. swarm/agents/scientific/gaia.py +26 -0
  339. swarm/agents/scientific/medicus.py +33 -0
  340. swarm/agents/scientific/oracle_agent.py +39 -0
  341. swarm/agents/scientific/scribe.py +39 -0
  342. swarm/agents/talent/__init__.py +0 -0
  343. swarm/agents/talent/deal.py +28 -0
  344. swarm/agents/talent/roster.py +29 -0
  345. swarm/agents/talent/scout.py +29 -0
  346. swarm/agents/talent/stage.py +27 -0
  347. swarm/agents/tech/__init__.py +0 -0
  348. swarm/agents/tech/aegis.py +28 -0
  349. swarm/agents/tech/bridge.py +28 -0
  350. swarm/agents/tech/forge.py +28 -0
  351. swarm/agents/trading/__init__.py +1 -0
  352. swarm/agents/trading/global_prediction_engine.py +611 -0
  353. swarm/agents/trading/polymarket_trader.py +165 -0
  354. swarm/agents/trading/prediction_strategist.py +218 -0
  355. swarm/autogen_bridge.py +68 -0
  356. swarm/bid_protocol.py +196 -0
  357. swarm/dispatcher.py +527 -0
  358. swarm/nexus.py +181 -0
  359. swarm/registry.py +112 -0
  360. telegram_listener.py +403 -0
  361. ui/tui/app.py +214 -0
@@ -0,0 +1,389 @@
1
+ """
2
+ Embedding Provider Abstraction Layer.
3
+ Unified interface for text embedding providers.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ import os
9
+ import logging
10
+ from abc import ABC, abstractmethod
11
+
12
+ import httpx
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class EmbeddingProvider(ABC):
18
+ """Abstract base for embedding providers."""
19
+
20
+ name: str = "base"
21
+
22
+ @abstractmethod
23
+ async def embed(self, text: str) -> list[float]:
24
+ """Generate embedding for a single text."""
25
+ pass
26
+
27
+ @abstractmethod
28
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
29
+ """Generate embeddings for multiple texts."""
30
+ pass
31
+
32
+ @property
33
+ @abstractmethod
34
+ def dimension(self) -> int:
35
+ """Return the embedding dimension."""
36
+ pass
37
+
38
+
39
+ # ═══════════════════════════════════════════════════════════════════════════════
40
+ # OPENAI EMBEDDINGS
41
+ # ═══════════════════════════════════════════════════════════════════════════════
42
+
43
+ class OpenAIEmbedder(EmbeddingProvider):
44
+ """OpenAI text embeddings."""
45
+
46
+ name = "openai"
47
+
48
+ MODELS = {
49
+ "text-embedding-3-small": 1536,
50
+ "text-embedding-3-large": 3072,
51
+ "text-embedding-ada-002": 1536,
52
+ }
53
+
54
+ def __init__(self, api_key: str | None = None, model: str = "text-embedding-3-small"):
55
+ self.api_key = api_key or os.environ.get("OPENAI_API_KEY")
56
+ self.model = model
57
+ self._dimension = self.MODELS.get(model, 1536)
58
+ self.base_url = "https://api.openai.com/v1"
59
+
60
+ async def embed(self, text: str) -> list[float]:
61
+ async with httpx.AsyncClient() as client:
62
+ response = await client.post(
63
+ f"{self.base_url}/embeddings",
64
+ headers={"Authorization": f"Bearer {self.api_key}"},
65
+ json={"input": text, "model": self.model},
66
+ timeout=30.0,
67
+ )
68
+ response.raise_for_status()
69
+ data = response.json()
70
+ return data["data"][0]["embedding"]
71
+
72
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
73
+ async with httpx.AsyncClient() as client:
74
+ response = await client.post(
75
+ f"{self.base_url}/embeddings",
76
+ headers={"Authorization": f"Bearer {self.api_key}"},
77
+ json={"input": texts, "model": self.model},
78
+ timeout=60.0,
79
+ )
80
+ response.raise_for_status()
81
+ data = response.json()
82
+ sorted_data = sorted(data["data"], key=lambda x: x["index"])
83
+ return [item["embedding"] for item in sorted_data]
84
+
85
+ @property
86
+ def dimension(self) -> int:
87
+ return self._dimension
88
+
89
+
90
+ # ═══════════════════════════════════════════════════════════════════════════════
91
+ # VOYAGE EMBEDDINGS
92
+ # ═══════════════════════════════════════════════════════════════════════════════
93
+
94
+ class VoyageEmbedder(EmbeddingProvider):
95
+ """Voyage AI embeddings."""
96
+
97
+ name = "voyage"
98
+
99
+ MODELS = {
100
+ "voyage-3": 1024,
101
+ "voyage-3-lite": 512,
102
+ "voyage-code-3": 1024,
103
+ "voyage-2": 1024,
104
+ }
105
+
106
+ def __init__(self, api_key: str | None = None, model: str = "voyage-3"):
107
+ self.api_key = api_key or os.environ.get("VOYAGE_API_KEY")
108
+ self.model = model
109
+ self._dimension = self.MODELS.get(model, 1024)
110
+ self.base_url = "https://api.voyageai.com/v1"
111
+
112
+ async def embed(self, text: str) -> list[float]:
113
+ async with httpx.AsyncClient() as client:
114
+ response = await client.post(
115
+ f"{self.base_url}/embeddings",
116
+ headers={"Authorization": f"Bearer {self.api_key}"},
117
+ json={"input": text, "model": self.model},
118
+ timeout=30.0,
119
+ )
120
+ response.raise_for_status()
121
+ data = response.json()
122
+ return data["data"][0]["embedding"]
123
+
124
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
125
+ async with httpx.AsyncClient() as client:
126
+ response = await client.post(
127
+ f"{self.base_url}/embeddings",
128
+ headers={"Authorization": f"Bearer {self.api_key}"},
129
+ json={"input": texts, "model": self.model},
130
+ timeout=60.0,
131
+ )
132
+ response.raise_for_status()
133
+ data = response.json()
134
+ sorted_data = sorted(data["data"], key=lambda x: x["index"])
135
+ return [item["embedding"] for item in sorted_data]
136
+
137
+ @property
138
+ def dimension(self) -> int:
139
+ return self._dimension
140
+
141
+
142
+ # ═══════════════════════════════════════════════════════════════════════════════
143
+ # GEMINI EMBEDDINGS
144
+ # ═══════════════════════════════════════════════════════════════════════════════
145
+
146
+ class GeminiEmbedder(EmbeddingProvider):
147
+ """Google Gemini embeddings."""
148
+
149
+ name = "gemini"
150
+
151
+ def __init__(self, api_key: str | None = None, model: str = "text-embedding-004"):
152
+ self.api_key = api_key or os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY")
153
+ self.model = model
154
+ self._dimension = 768
155
+ self.base_url = "https://generativelanguage.googleapis.com/v1beta"
156
+
157
+ async def embed(self, text: str) -> list[float]:
158
+ async with httpx.AsyncClient() as client:
159
+ response = await client.post(
160
+ f"{self.base_url}/models/{self.model}:embedContent",
161
+ params={"key": self.api_key},
162
+ json={"content": {"parts": [{"text": text}]}},
163
+ timeout=30.0,
164
+ )
165
+ response.raise_for_status()
166
+ data = response.json()
167
+ return data["embedding"]["values"]
168
+
169
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
170
+ # Gemini doesn't have native batch embedding, so we process sequentially
171
+ results = []
172
+ for text in texts:
173
+ embedding = await self.embed(text)
174
+ results.append(embedding)
175
+ return results
176
+
177
+ @property
178
+ def dimension(self) -> int:
179
+ return self._dimension
180
+
181
+
182
+ # ═══════════════════════════════════════════════════════════════════════════════
183
+ # MISTRAL EMBEDDINGS
184
+ # ═══════════════════════════════════════════════════════════════════════════════
185
+
186
+ class MistralEmbedder(EmbeddingProvider):
187
+ """Mistral AI embeddings."""
188
+
189
+ name = "mistral"
190
+
191
+ def __init__(self, api_key: str | None = None, model: str = "mistral-embed"):
192
+ self.api_key = api_key or os.environ.get("MISTRAL_API_KEY")
193
+ self.model = model
194
+ self._dimension = 1024
195
+ self.base_url = "https://api.mistral.ai/v1"
196
+
197
+ async def embed(self, text: str) -> list[float]:
198
+ async with httpx.AsyncClient() as client:
199
+ response = await client.post(
200
+ f"{self.base_url}/embeddings",
201
+ headers={"Authorization": f"Bearer {self.api_key}"},
202
+ json={"input": [text], "model": self.model},
203
+ timeout=30.0,
204
+ )
205
+ response.raise_for_status()
206
+ data = response.json()
207
+ return data["data"][0]["embedding"]
208
+
209
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
210
+ async with httpx.AsyncClient() as client:
211
+ response = await client.post(
212
+ f"{self.base_url}/embeddings",
213
+ headers={"Authorization": f"Bearer {self.api_key}"},
214
+ json={"input": texts, "model": self.model},
215
+ timeout=60.0,
216
+ )
217
+ response.raise_for_status()
218
+ data = response.json()
219
+ sorted_data = sorted(data["data"], key=lambda x: x["index"])
220
+ return [item["embedding"] for item in sorted_data]
221
+
222
+ @property
223
+ def dimension(self) -> int:
224
+ return self._dimension
225
+
226
+
227
+ # ═══════════════════════════════════════════════════════════════════════════════
228
+ # COHERE EMBEDDINGS
229
+ # ═══════════════════════════════════════════════════════════════════════════════
230
+
231
+ class CohereEmbedder(EmbeddingProvider):
232
+ """Cohere embeddings."""
233
+
234
+ name = "cohere"
235
+
236
+ MODELS = {
237
+ "embed-english-v3.0": 1024,
238
+ "embed-multilingual-v3.0": 1024,
239
+ "embed-english-light-v3.0": 384,
240
+ "embed-multilingual-light-v3.0": 384,
241
+ }
242
+
243
+ def __init__(self, api_key: str | None = None, model: str = "embed-english-v3.0"):
244
+ self.api_key = api_key or os.environ.get("COHERE_API_KEY")
245
+ self.model = model
246
+ self._dimension = self.MODELS.get(model, 1024)
247
+ self.base_url = "https://api.cohere.ai/v1"
248
+
249
+ async def embed(self, text: str) -> list[float]:
250
+ async with httpx.AsyncClient() as client:
251
+ response = await client.post(
252
+ f"{self.base_url}/embed",
253
+ headers={"Authorization": f"Bearer {self.api_key}"},
254
+ json={
255
+ "texts": [text],
256
+ "model": self.model,
257
+ "input_type": "search_document",
258
+ },
259
+ timeout=30.0,
260
+ )
261
+ response.raise_for_status()
262
+ data = response.json()
263
+ return data["embeddings"][0]
264
+
265
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
266
+ async with httpx.AsyncClient() as client:
267
+ response = await client.post(
268
+ f"{self.base_url}/embed",
269
+ headers={"Authorization": f"Bearer {self.api_key}"},
270
+ json={
271
+ "texts": texts,
272
+ "model": self.model,
273
+ "input_type": "search_document",
274
+ },
275
+ timeout=60.0,
276
+ )
277
+ response.raise_for_status()
278
+ data = response.json()
279
+ return data["embeddings"]
280
+
281
+ @property
282
+ def dimension(self) -> int:
283
+ return self._dimension
284
+
285
+
286
+ # ═══════════════════════════════════════════════════════════════════════════════
287
+ # JINA EMBEDDINGS
288
+ # ═══════════════════════════════════════════════════════════════════════════════
289
+
290
+ class JinaEmbedder(EmbeddingProvider):
291
+ """Jina AI embeddings."""
292
+
293
+ name = "jina"
294
+
295
+ def __init__(self, api_key: str | None = None, model: str = "jina-embeddings-v3"):
296
+ self.api_key = api_key or os.environ.get("JINA_API_KEY")
297
+ self.model = model
298
+ self._dimension = 1024
299
+ self.base_url = "https://api.jina.ai/v1"
300
+
301
+ async def embed(self, text: str) -> list[float]:
302
+ async with httpx.AsyncClient() as client:
303
+ response = await client.post(
304
+ f"{self.base_url}/embeddings",
305
+ headers={"Authorization": f"Bearer {self.api_key}"},
306
+ json={"input": [text], "model": self.model},
307
+ timeout=30.0,
308
+ )
309
+ response.raise_for_status()
310
+ data = response.json()
311
+ return data["data"][0]["embedding"]
312
+
313
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
314
+ async with httpx.AsyncClient() as client:
315
+ response = await client.post(
316
+ f"{self.base_url}/embeddings",
317
+ headers={"Authorization": f"Bearer {self.api_key}"},
318
+ json={"input": texts, "model": self.model},
319
+ timeout=60.0,
320
+ )
321
+ response.raise_for_status()
322
+ data = response.json()
323
+ return [item["embedding"] for item in data["data"]]
324
+
325
+ @property
326
+ def dimension(self) -> int:
327
+ return self._dimension
328
+
329
+
330
+ # ═══════════════════════════════════════════════════════════════════════════════
331
+ # AMAZON BEDROCK EMBEDDINGS
332
+ # ═══════════════════════════════════════════════════════════════════════════════
333
+
334
+ class BedrockEmbedder(EmbeddingProvider):
335
+ """Amazon Bedrock Titan Embeddings V2."""
336
+
337
+ name = "bedrock"
338
+
339
+ def __init__(self, model: str = "amazon.titan-embed-text-v2:0"):
340
+ import boto3
341
+ self.model = model
342
+ self._dimension = 1024
343
+ self._client = boto3.client("bedrock-runtime")
344
+
345
+ async def embed(self, text: str) -> list[float]:
346
+ response = self._client.invoke_model(
347
+ modelId=self.model,
348
+ body=json.dumps({"inputText": text, "dimensions": self._dimension}),
349
+ contentType="application/json",
350
+ accept="application/json",
351
+ )
352
+ data = json.loads(response["body"].read())
353
+ return data["embedding"]
354
+
355
+ async def embed_batch(self, texts: list[str]) -> list[list[float]]:
356
+ # Titan V2 invoke_model is single-text only — no batch endpoint exists for this model
357
+ return [await self.embed(text) for text in texts]
358
+
359
+ @property
360
+ def dimension(self) -> int:
361
+ return self._dimension
362
+
363
+
364
+ # ═══════════════════════════════════════════════════════════════════════════════
365
+ # PROVIDER FACTORY
366
+ # ═══════════════════════════════════════════════════════════════════════════════
367
+
368
+ EMBEDDING_PROVIDERS: dict[str, type[EmbeddingProvider]] = {
369
+ "openai": OpenAIEmbedder,
370
+ "voyage": VoyageEmbedder,
371
+ "gemini": GeminiEmbedder,
372
+ "google": GeminiEmbedder,
373
+ "mistral": MistralEmbedder,
374
+ "cohere": CohereEmbedder,
375
+ "jina": JinaEmbedder,
376
+ "bedrock": BedrockEmbedder,
377
+ }
378
+
379
+
380
+ def get_embedding_provider(name: str | None = None, **kwargs) -> EmbeddingProvider:
381
+ """Get an embedding provider by name."""
382
+ name = name or os.environ.get("HYPERCLAW_EMBEDDING_PROVIDER", "openai")
383
+ name = name.lower()
384
+
385
+ if name not in EMBEDDING_PROVIDERS:
386
+ available = ", ".join(sorted(EMBEDDING_PROVIDERS.keys()))
387
+ raise ValueError(f"Unknown embedding provider: {name}. Available: {available}")
388
+
389
+ return EMBEDDING_PROVIDERS[name](**kwargs)