hyperaim-sdk 1.0.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.
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperaim-sdk
3
+ Version: 1.0.0
4
+ Summary: HyperSDK — AIM Intelligence Middleware. Add telemetry, quality scoring, rate limiting, anomaly detection, and demand prediction to any HyperCycle AIM with 2 lines of code.
5
+ Author-email: QyraTech <info@qyratech.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/qyratech/hyperaim-sdk
8
+ Project-URL: Documentation, http://62.171.162.38:8095/docs
9
+ Project-URL: Repository, https://github.com/qyratech/hyperaim-sdk
10
+ Keywords: hypercycle,aim,ai,telemetry,intelligence,sdk,hypersdk,middleware
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Libraries
16
+ Classifier: Topic :: System :: Monitoring
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: httpx>=0.27.0
20
+ Requires-Dist: fastapi>=0.100.0
21
+
22
+ # HyperSDK
23
+
24
+ **AIM Intelligence Middleware for the HyperCycle IoAI Network.**
25
+
26
+ Add intelligence to any AIM with 2 lines of code.
27
+
28
+ ```python
29
+ from hyperaim_sdk import HyperSDK
30
+ hs = HyperSDK(app, api_key="qt_your_key_here", aim_name="my-aim")
31
+ ```
32
+
33
+ ## What You Get (Free Tier)
34
+
35
+ - **Automatic telemetry** — every request tracked: latency, errors, callers, endpoints
36
+ - **Live /health endpoint** — uptime, error rate, avg latency, unique callers
37
+ - **Live /qt/stats endpoint** — detailed rolling metrics with percentiles
38
+ - **Per-caller rate limiting** — protect your AIM from abuse
39
+ - **Request ID tracking** — trace any request via response headers
40
+ - **Batched telemetry upload** — minimal overhead, flushes every 60s
41
+
42
+ ## Intelligence Engine (powered by QyraTech)
43
+
44
+ Your telemetry feeds the QyraTech Intelligence Server, which provides:
45
+
46
+ - **Quality scoring** — reliability, performance, demand, consistency (0-100 each)
47
+ - **Anomaly detection** — latency spikes, error bursts, traffic drops detected automatically
48
+ - **Demand prediction** — peak hours, trend direction, future call volume
49
+ - **Network rankings** — how your AIM compares to all others on the IoAI
50
+ - **Cross-AIM patterns** — which AIMs are frequently used together
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install hyperaim-sdk
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ```python
61
+ from fastapi import FastAPI
62
+ from hyperaim_sdk import HyperSDK
63
+
64
+ app = FastAPI(title="My AIM")
65
+
66
+ # Register at http://62.171.162.38:8095/register to get your API key
67
+ hs = HyperSDK(
68
+ app,
69
+ api_key="qt_your_key_here",
70
+ aim_name="my-awesome-aim",
71
+ )
72
+
73
+ @app.post("/my-endpoint")
74
+ async def my_endpoint():
75
+ # Your AIM logic here — HyperSDK tracks everything automatically
76
+ return {"result": "hello"}
77
+ ```
78
+
79
+ ## Configuration
80
+
81
+ ```python
82
+ hs = HyperSDK(
83
+ app,
84
+ api_key="qt_...", # Required: your API key
85
+ aim_name="my-aim", # Name shown in dashboards
86
+ server_url="http://62.171.162.38:8095", # Intelligence server
87
+ rate_limit=100, # Max requests per window per caller
88
+ rate_window=60, # Rate limit window in seconds
89
+ flush_interval=60, # Telemetry flush interval in seconds
90
+ enable_telemetry=True, # Send telemetry to server
91
+ enable_rate_limiting=True, # Enable per-caller rate limiting
92
+ enable_health=True, # Add /health endpoint
93
+ enable_stats=True, # Add /qt/stats endpoint
94
+ excluded_paths=["/health", "/docs"], # Paths to skip tracking
95
+ )
96
+ ```
97
+
98
+ ## Response Headers
99
+
100
+ Every tracked request gets these headers:
101
+
102
+ | Header | Description |
103
+ |--------|-------------|
104
+ | `X-Request-ID` | Unique request identifier |
105
+ | `X-HyperSDK` | SDK version |
106
+ | `X-Response-Time-Ms` | Request latency in milliseconds |
107
+
108
+ ## Endpoints Added
109
+
110
+ | Endpoint | Description |
111
+ |----------|-------------|
112
+ | `GET /health` | Health check with live stats |
113
+ | `GET /qt/stats` | Detailed rolling metrics |
114
+ | `GET /qt/rate-limit` | Current rate limit status for caller |
115
+
116
+ ## Get Your API Key
117
+
118
+ ```bash
119
+ curl -X POST http://62.171.162.38:8095/register \
120
+ -H 'Content-Type: application/json' \
121
+ -d '{"name": "my-aim", "owner": "your-name", "url": "http://your-server:port"}'
122
+ ```
123
+
124
+ ## View Your Dashboard
125
+
126
+ ```
127
+ http://62.171.162.38:8095/dashboard/{your_aim_id}
128
+ ```
129
+
130
+ ## Built By
131
+
132
+ **QyraTech** — AI Agent Intelligence Infrastructure on the HyperCycle IoAI Network.
133
+
134
+ - Intelligence Server: http://62.171.162.38:8095
135
+ - QyraTech Home: http://62.171.162.38:8085
136
+ - HyperCycle: https://www.hypercycle.ai
@@ -0,0 +1,5 @@
1
+ hyperaim_sdk.py,sha256=rUXEY5J4RQ1MMfsDanBvTwt8cdwIAiuQj9Htp1Tg9r4,12978
2
+ hyperaim_sdk-1.0.0.dist-info/METADATA,sha256=kWPa3G8oHKoireM01KOhGlksUEB7JKOvqduN93_fqUg,4536
3
+ hyperaim_sdk-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
4
+ hyperaim_sdk-1.0.0.dist-info/top_level.txt,sha256=KX5AIpd0HEnm-kgb_IyV2Z8fqovTmMf9n-CjD1Pv-oM,13
5
+ hyperaim_sdk-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ hyperaim_sdk
hyperaim_sdk.py ADDED
@@ -0,0 +1,380 @@
1
+ """
2
+ HyperSDK v1.0.0 — AIM Intelligence Middleware
3
+
4
+ Add intelligence to any HyperCycle AIM with 2 lines of code:
5
+
6
+ from hypersdk import HyperSDK
7
+ hs = HyperSDK(app, api_key="qt_your_key_here")
8
+
9
+ What you get for free:
10
+ - Automatic request telemetry (latency, errors, callers)
11
+ - /health endpoint with live stats
12
+ - /qt/stats endpoint with detailed metrics
13
+ - Rate limiting per caller
14
+ - Request ID tracking
15
+ - Automatic batched telemetry upload
16
+
17
+ What the intelligence server does with your data:
18
+ - Quality scoring (reliability, performance, demand, consistency)
19
+ - Anomaly detection (latency spikes, error bursts, traffic drops)
20
+ - Demand prediction (when your peak hours are, trend direction)
21
+ - Network-wide AIM rankings
22
+ - Cross-AIM correlation patterns
23
+
24
+ Published by QyraTech — AI Agent Intelligence Infrastructure
25
+ https://github.com/qyratech/hypersdk
26
+ """
27
+
28
+ import time
29
+ import uuid
30
+ import hashlib
31
+ import asyncio
32
+ import threading
33
+ import statistics
34
+ from collections import deque, defaultdict
35
+ from datetime import datetime, timezone
36
+ from typing import Optional, Callable
37
+
38
+ try:
39
+ import httpx
40
+ except ImportError:
41
+ httpx = None
42
+
43
+ __version__ = "1.0.0"
44
+ __author__ = "QyraTech"
45
+
46
+ # Default intelligence server
47
+ DEFAULT_SERVER = "http://62.171.162.38:8095"
48
+
49
+
50
+ class TelemetryBuffer:
51
+ """Thread-safe buffer that batches telemetry events and flushes periodically."""
52
+
53
+ def __init__(self, server_url: str, api_key: str, flush_interval: int = 60,
54
+ max_buffer: int = 500):
55
+ self.server_url = server_url
56
+ self.api_key = api_key
57
+ self.flush_interval = flush_interval
58
+ self.max_buffer = max_buffer
59
+ self.buffer = deque(maxlen=max_buffer)
60
+ self._running = False
61
+ self._flush_task = None
62
+
63
+ def add(self, event: dict):
64
+ self.buffer.append(event)
65
+ if len(self.buffer) >= self.max_buffer:
66
+ asyncio.ensure_future(self.flush())
67
+
68
+ async def flush(self):
69
+ if not self.buffer or not httpx:
70
+ return
71
+
72
+ events = []
73
+ while self.buffer:
74
+ try:
75
+ events.append(self.buffer.popleft())
76
+ except IndexError:
77
+ break
78
+
79
+ if not events:
80
+ return
81
+
82
+ try:
83
+ async with httpx.AsyncClient() as client:
84
+ await client.post(
85
+ f"{self.server_url}/telemetry",
86
+ json={"events": events},
87
+ headers={"Authorization": f"Bearer {self.api_key}"},
88
+ timeout=10,
89
+ )
90
+ except Exception:
91
+ # Re-add failed events (best effort)
92
+ for e in events[:50]:
93
+ self.buffer.appendleft(e)
94
+
95
+ async def start_periodic_flush(self):
96
+ self._running = True
97
+ while self._running:
98
+ await asyncio.sleep(self.flush_interval)
99
+ await self.flush()
100
+
101
+ def stop(self):
102
+ self._running = False
103
+
104
+
105
+ class RateLimiter:
106
+ """Per-caller sliding window rate limiter."""
107
+
108
+ def __init__(self, max_requests: int = 100, window_seconds: int = 60):
109
+ self.max_requests = max_requests
110
+ self.window = window_seconds
111
+ self.callers = defaultdict(deque)
112
+
113
+ def is_allowed(self, caller_id: str) -> bool:
114
+ now = time.time()
115
+ window = self.callers[caller_id]
116
+
117
+ # Remove expired entries
118
+ while window and window[0] < now - self.window:
119
+ window.popleft()
120
+
121
+ if len(window) >= self.max_requests:
122
+ return False
123
+
124
+ window.append(now)
125
+ return True
126
+
127
+ def get_usage(self, caller_id: str) -> dict:
128
+ now = time.time()
129
+ window = self.callers[caller_id]
130
+ while window and window[0] < now - self.window:
131
+ window.popleft()
132
+ return {
133
+ "used": len(window),
134
+ "limit": self.max_requests,
135
+ "remaining": max(0, self.max_requests - len(window)),
136
+ "window_seconds": self.window,
137
+ }
138
+
139
+
140
+ class LiveStats:
141
+ """Real-time rolling statistics for the AIM."""
142
+
143
+ def __init__(self, window_size: int = 1000):
144
+ self.window_size = window_size
145
+ self.latencies = deque(maxlen=window_size)
146
+ self.status_codes = deque(maxlen=window_size)
147
+ self.endpoints = defaultdict(int)
148
+ self.callers = set()
149
+ self.total_requests = 0
150
+ self.total_errors = 0
151
+ self.start_time = time.time()
152
+ self._hourly_calls = defaultdict(int)
153
+
154
+ def record(self, latency_ms: float, status_code: int, endpoint: str, caller: str):
155
+ self.latencies.append(latency_ms)
156
+ self.status_codes.append(status_code)
157
+ self.endpoints[endpoint] += 1
158
+ self.callers.add(caller)
159
+ self.total_requests += 1
160
+ if status_code >= 400:
161
+ self.total_errors += 1
162
+
163
+ hour = datetime.now(timezone.utc).strftime("%H")
164
+ self._hourly_calls[hour] += 1
165
+
166
+ def get_stats(self) -> dict:
167
+ uptime = time.time() - self.start_time
168
+ lats = list(self.latencies)
169
+ sorted_lats = sorted(lats) if lats else [0]
170
+
171
+ return {
172
+ "uptime_seconds": round(uptime),
173
+ "total_requests": self.total_requests,
174
+ "total_errors": self.total_errors,
175
+ "error_rate_pct": round(self.total_errors / max(self.total_requests, 1) * 100, 2),
176
+ "unique_callers": len(self.callers),
177
+ "requests_per_minute": round(self.total_requests / max(uptime / 60, 1), 2),
178
+ "latency": {
179
+ "avg_ms": round(statistics.mean(lats), 1) if lats else 0,
180
+ "p50_ms": round(sorted_lats[len(sorted_lats) // 2], 1) if sorted_lats else 0,
181
+ "p95_ms": round(sorted_lats[int(len(sorted_lats) * 0.95)], 1) if len(sorted_lats) > 1 else 0,
182
+ "p99_ms": round(sorted_lats[int(len(sorted_lats) * 0.99)], 1) if len(sorted_lats) > 1 else 0,
183
+ "min_ms": round(min(lats), 1) if lats else 0,
184
+ "max_ms": round(max(lats), 1) if lats else 0,
185
+ },
186
+ "top_endpoints": dict(sorted(self.endpoints.items(),
187
+ key=lambda x: x[1], reverse=True)[:10]),
188
+ "hourly_distribution": dict(self._hourly_calls),
189
+ }
190
+
191
+
192
+ class HyperSDK:
193
+ """
194
+ HyperSDK — AIM Intelligence Middleware.
195
+
196
+ Wraps a FastAPI app with automatic telemetry, rate limiting,
197
+ health endpoints, and intelligence server reporting.
198
+
199
+ Usage:
200
+ from fastapi import FastAPI
201
+ from hypersdk import HyperSDK
202
+
203
+ app = FastAPI()
204
+ hs = HyperSDK(
205
+ app,
206
+ api_key="qt_your_key_here",
207
+ aim_name="my-awesome-aim",
208
+ )
209
+ """
210
+
211
+ def __init__(
212
+ self,
213
+ app,
214
+ api_key: str,
215
+ aim_name: str = "unknown",
216
+ server_url: str = DEFAULT_SERVER,
217
+ rate_limit: int = 100,
218
+ rate_window: int = 60,
219
+ flush_interval: int = 60,
220
+ enable_telemetry: bool = True,
221
+ enable_rate_limiting: bool = True,
222
+ enable_health: bool = True,
223
+ enable_stats: bool = True,
224
+ excluded_paths: list = None,
225
+ ):
226
+ self.app = app
227
+ self.api_key = api_key
228
+ self.aim_name = aim_name
229
+ self.server_url = server_url
230
+ self.enable_telemetry = enable_telemetry
231
+ self.enable_rate_limiting = enable_rate_limiting
232
+ self.excluded_paths = set(excluded_paths or [
233
+ "/health", "/qt/stats", "/qt/rate-limit", "/docs",
234
+ "/openapi.json", "/favicon.ico",
235
+ ])
236
+
237
+ self.stats = LiveStats()
238
+ self.rate_limiter = RateLimiter(rate_limit, rate_window) if enable_rate_limiting else None
239
+ self.telemetry = TelemetryBuffer(server_url, api_key, flush_interval) if enable_telemetry else None
240
+
241
+ # Add middleware
242
+ self._add_middleware()
243
+
244
+ # Add endpoints
245
+ if enable_health:
246
+ self._add_health_endpoint()
247
+ if enable_stats:
248
+ self._add_stats_endpoint()
249
+ if enable_rate_limiting:
250
+ self._add_rate_limit_endpoint()
251
+
252
+ # Start periodic flush
253
+ if self.telemetry:
254
+ @app.on_event("startup")
255
+ async def _start_telemetry():
256
+ asyncio.create_task(self.telemetry.start_periodic_flush())
257
+
258
+ @app.on_event("shutdown")
259
+ async def _stop_telemetry():
260
+ await self.telemetry.flush()
261
+ self.telemetry.stop()
262
+
263
+ def _caller_hash(self, request) -> str:
264
+ ip = request.client.host if request.client else "unknown"
265
+ return hashlib.md5(ip.encode()).hexdigest()[:12]
266
+
267
+ def _add_middleware(self):
268
+ sdk = self
269
+
270
+ @self.app.middleware("http")
271
+ async def qyratech_middleware(request, call_next):
272
+ path = request.url.path
273
+ caller = sdk._caller_hash(request)
274
+
275
+ # Skip excluded paths
276
+ if path in sdk.excluded_paths:
277
+ return await call_next(request)
278
+
279
+ # Rate limiting
280
+ if sdk.rate_limiter and not sdk.rate_limiter.is_allowed(caller):
281
+ from fastapi.responses import JSONResponse
282
+ return JSONResponse(
283
+ status_code=429,
284
+ content={
285
+ "error": "Rate limit exceeded",
286
+ "retry_after_seconds": sdk.rate_limiter.callers[caller][0] + sdk.rate_limiter.window - time.time()
287
+ if sdk.rate_limiter.callers.get(caller) else 60,
288
+ },
289
+ headers={"X-HyperSDK": __version__},
290
+ )
291
+
292
+ # Track request
293
+ request_id = str(uuid.uuid4())[:8]
294
+ start = time.time()
295
+
296
+ try:
297
+ response = await call_next(request)
298
+ latency_ms = round((time.time() - start) * 1000, 2)
299
+ status_code = response.status_code
300
+
301
+ # Record stats
302
+ sdk.stats.record(latency_ms, status_code, path, caller)
303
+
304
+ # Buffer telemetry event
305
+ if sdk.telemetry:
306
+ sdk.telemetry.add({
307
+ "timestamp": datetime.now(timezone.utc).isoformat(),
308
+ "endpoint": path,
309
+ "method": request.method,
310
+ "status_code": status_code,
311
+ "latency_ms": latency_ms,
312
+ "caller_hash": caller,
313
+ "error_type": None,
314
+ })
315
+
316
+ # Add tracking headers
317
+ response.headers["X-Request-ID"] = request_id
318
+ response.headers["X-HyperSDK"] = __version__
319
+ response.headers["X-Response-Time-Ms"] = str(latency_ms)
320
+
321
+ return response
322
+
323
+ except Exception as e:
324
+ latency_ms = round((time.time() - start) * 1000, 2)
325
+ sdk.stats.record(latency_ms, 500, path, caller)
326
+
327
+ if sdk.telemetry:
328
+ sdk.telemetry.add({
329
+ "timestamp": datetime.now(timezone.utc).isoformat(),
330
+ "endpoint": path,
331
+ "method": request.method,
332
+ "status_code": 500,
333
+ "latency_ms": latency_ms,
334
+ "caller_hash": caller,
335
+ "error_type": type(e).__name__,
336
+ })
337
+ raise
338
+
339
+ def _add_health_endpoint(self):
340
+ sdk = self
341
+
342
+ @self.app.get("/health")
343
+ async def qt_health():
344
+ stats = sdk.stats.get_stats()
345
+ return {
346
+ "status": "ok",
347
+ "aim": sdk.aim_name,
348
+ "sdk_version": __version__,
349
+ "uptime_seconds": stats["uptime_seconds"],
350
+ "total_requests": stats["total_requests"],
351
+ "error_rate_pct": stats["error_rate_pct"],
352
+ "avg_latency_ms": stats["latency"]["avg_ms"],
353
+ "unique_callers": stats["unique_callers"],
354
+ "intelligence_server": sdk.server_url,
355
+ "telemetry_enabled": sdk.enable_telemetry,
356
+ "rate_limiting_enabled": sdk.enable_rate_limiting,
357
+ }
358
+
359
+ def _add_stats_endpoint(self):
360
+ sdk = self
361
+
362
+ @self.app.get("/qt/stats")
363
+ async def qt_stats():
364
+ return {
365
+ "aim": sdk.aim_name,
366
+ "sdk_version": __version__,
367
+ "stats": sdk.stats.get_stats(),
368
+ "telemetry_buffer_size": len(sdk.telemetry.buffer) if sdk.telemetry else 0,
369
+ }
370
+
371
+ def _add_rate_limit_endpoint(self):
372
+ sdk = self
373
+ from fastapi import Request as FastAPIRequest
374
+
375
+ @self.app.get("/qt/rate-limit")
376
+ async def qt_rate_limit(request: FastAPIRequest):
377
+ caller = sdk._caller_hash(request)
378
+ if sdk.rate_limiter:
379
+ return sdk.rate_limiter.get_usage(caller)
380
+ return {"rate_limiting": "disabled"}