vnai 2.0.1__py3-none-any.whl → 2.0.3__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.
vnai/flow/relay.py CHANGED
@@ -1,5 +1,7 @@
1
- # vnai/flow/relay.py
2
- # Data transmission system (formerly sync)
1
+ ##
2
+
3
+ ##
4
+
3
5
 
4
6
  import time
5
7
  import threading
@@ -11,7 +13,7 @@ from pathlib import Path
11
13
  from typing import Dict, List, Any, Optional
12
14
 
13
15
  class Conduit:
14
- """Handles system telemetry flow"""
16
+ #--
15
17
 
16
18
  _instance = None
17
19
  _lock = threading.Lock()
@@ -24,12 +26,13 @@ class Conduit:
24
26
  return cls._instance
25
27
 
26
28
  def _initialize(self, webhook_url, buffer_size, sync_interval):
27
- """Initialize conduit"""
29
+ #--
28
30
  self.webhook_url = webhook_url
29
31
  self.buffer_size = buffer_size
30
32
  self.sync_interval = sync_interval
31
33
 
32
- # Separate buffers for different data types
34
+ ##
35
+
33
36
  self.buffer = {
34
37
  "function_calls": [],
35
38
  "api_requests": [],
@@ -41,7 +44,8 @@ class Conduit:
41
44
  self.sync_count = 0
42
45
  self.failed_queue = []
43
46
 
44
- # Home directory setup
47
+ ##
48
+
45
49
  self.home_dir = Path.home()
46
50
  self.project_dir = self.home_dir / ".vnstock"
47
51
  self.project_dir.mkdir(exist_ok=True)
@@ -49,27 +53,31 @@ class Conduit:
49
53
  self.data_dir.mkdir(exist_ok=True)
50
54
  self.config_path = self.data_dir / "relay_config.json"
51
55
 
52
- # Get machine identifier from system profile
56
+ ##
57
+
53
58
  try:
54
59
  from vnai.scope.profile import inspector
55
60
  self.machine_id = inspector.fingerprint()
56
61
  except:
57
62
  self.machine_id = self._generate_fallback_id()
58
63
 
59
- # Load config if exists
64
+ ##
65
+
60
66
  self._load_config()
61
67
 
62
- # Start periodic sync
68
+ ##
69
+
63
70
  self._start_periodic_sync()
64
71
 
65
72
  def _generate_fallback_id(self) -> str:
66
- """Generate a fallback machine identifier if profile is unavailable"""
73
+ #--
67
74
  try:
68
75
  import platform
69
76
  import hashlib
70
77
  import uuid
71
78
 
72
- # Try to get machine-specific information
79
+ ##
80
+
73
81
  system_info = platform.node() + platform.platform() + platform.processor()
74
82
  return hashlib.md5(system_info.encode()).hexdigest()
75
83
  except:
@@ -77,7 +85,7 @@ class Conduit:
77
85
  return str(uuid.uuid4())
78
86
 
79
87
  def _load_config(self):
80
- """Load configuration from file"""
88
+ #--
81
89
  if self.config_path.exists():
82
90
  try:
83
91
  with open(self.config_path, 'r') as f:
@@ -97,7 +105,7 @@ class Conduit:
97
105
  pass
98
106
 
99
107
  def _save_config(self):
100
- """Save configuration to file"""
108
+ #--
101
109
  config = {
102
110
  'webhook_url': self.webhook_url,
103
111
  'buffer_size': self.buffer_size,
@@ -113,7 +121,7 @@ class Conduit:
113
121
  pass
114
122
 
115
123
  def _start_periodic_sync(self):
116
- """Start periodic sync thread"""
124
+ #--
117
125
  def periodic_sync():
118
126
  while True:
119
127
  time.sleep(self.sync_interval)
@@ -123,8 +131,9 @@ class Conduit:
123
131
  sync_thread.start()
124
132
 
125
133
  def add_function_call(self, record):
126
- """Add function call record"""
127
- # Ensure record is a dictionary
134
+ #--
135
+ ##
136
+
128
137
  if not isinstance(record, dict):
129
138
  record = {"value": str(record)}
130
139
 
@@ -133,8 +142,9 @@ class Conduit:
133
142
  self._check_triggers("function_calls")
134
143
 
135
144
  def add_api_request(self, record):
136
- """Add API request record"""
137
- # Ensure record is a dictionary
145
+ #--
146
+ ##
147
+
138
148
  if not isinstance(record, dict):
139
149
  record = {"value": str(record)}
140
150
 
@@ -143,8 +153,9 @@ class Conduit:
143
153
  self._check_triggers("api_requests")
144
154
 
145
155
  def add_rate_limit(self, record):
146
- """Add rate limit record"""
147
- # Ensure record is a dictionary
156
+ #--
157
+ ##
158
+
148
159
  if not isinstance(record, dict):
149
160
  record = {"value": str(record)}
150
161
 
@@ -153,33 +164,36 @@ class Conduit:
153
164
  self._check_triggers("rate_limits")
154
165
 
155
166
  def _check_triggers(self, record_type: str):
156
- """Check if any sync triggers are met"""
167
+ #--
157
168
  current_time = time.time()
158
169
  should_trigger = False
159
170
  trigger_reason = None
160
171
 
161
- # Get total buffer size
172
+ ##
173
+
162
174
  total_records = sum(len(buffer) for buffer in self.buffer.values())
163
175
 
164
- # SIZE TRIGGER: Buffer size threshold reached
176
+ ##
177
+
165
178
  if total_records >= self.buffer_size:
166
179
  should_trigger = True
167
180
  trigger_reason = "buffer_full"
168
181
 
169
- # EVENT TRIGGER: Critical events (errors, rate limit warnings)
170
- elif record_type == "rate_limits" and self.buffer["rate_limits"] and \
171
- any(item.get("is_exceeded") for item in self.buffer["rate_limits"] if isinstance(item, dict)):
182
+ ##
183
+
184
+ elif record_type == "rate_limits" and self.buffer["rate_limits"] and any(item.get("is_exceeded") for item in self.buffer["rate_limits"] if isinstance(item, dict)):
172
185
  should_trigger = True
173
186
  trigger_reason = "rate_limit_exceeded"
174
- elif record_type == "function_calls" and self.buffer["function_calls"] and \
175
- any(not item.get("success") for item in self.buffer["function_calls"] if isinstance(item, dict)):
187
+ elif record_type == "function_calls" and self.buffer["function_calls"] and any(not item.get("success") for item in self.buffer["function_calls"] if isinstance(item, dict)):
176
188
  should_trigger = True
177
189
  trigger_reason = "function_error"
178
190
 
179
- # TIME-WEIGHTED RANDOM TRIGGER: More likely as time since last sync increases
191
+ ##
192
+
180
193
  else:
181
194
  time_factor = min(1.0, (current_time - self.last_sync_time) / (self.sync_interval / 2))
182
- if random.random() < 0.05 * time_factor: # 0-5% chance based on time
195
+ if random.random() < 0.05 * time_factor: ##
196
+
183
197
  should_trigger = True
184
198
  trigger_reason = "random_time_weighted"
185
199
 
@@ -191,27 +205,32 @@ class Conduit:
191
205
  ).start()
192
206
 
193
207
  def queue(self, package, priority=None):
194
- """Queue data package"""
208
+ #--
195
209
  if not package:
196
210
  return False
197
211
 
198
- # Handle non-dictionary packages
212
+ ##
213
+
199
214
  if not isinstance(package, dict):
200
215
  self.add_function_call({"message": str(package)})
201
216
  return True
202
217
 
203
- # Add timestamp if not present
218
+ ##
219
+
204
220
  if "timestamp" not in package:
205
221
  package["timestamp"] = datetime.now().isoformat()
206
222
 
207
- # Route based on package type
223
+ ##
224
+
208
225
  if "type" in package:
209
226
  package_type = package["type"]
210
227
  data = package.get("data", {})
211
228
 
212
- # Remove system info if present to avoid duplication
229
+ ##
230
+
213
231
  if isinstance(data, dict) and "system" in data:
214
- # Get machine_id for reference but don't duplicate the whole system info
232
+ ##
233
+
215
234
  machine_id = data["system"].get("machine_id")
216
235
  data.pop("system")
217
236
  if machine_id:
@@ -224,8 +243,10 @@ class Conduit:
224
243
  elif package_type == "rate_limit":
225
244
  self.add_rate_limit(data)
226
245
  elif package_type == "system_info":
227
- # For system info, we'll add it as a special function call
228
- # but remove duplicated data
246
+ ##
247
+
248
+ ##
249
+
229
250
  self.add_function_call({
230
251
  "type": "system_info",
231
252
  "commercial": data.get("commercial"),
@@ -233,7 +254,8 @@ class Conduit:
233
254
  "timestamp": package.get("timestamp")
234
255
  })
235
256
  elif package_type == "metrics":
236
- # Handle metrics package with multiple categories
257
+ ##
258
+
237
259
  metrics_data = data
238
260
  for metric_type, metrics_list in metrics_data.items():
239
261
  if isinstance(metrics_list, list):
@@ -247,58 +269,68 @@ class Conduit:
247
269
  for item in metrics_list:
248
270
  self.add_api_request(item)
249
271
  else:
250
- # Default to function calls
272
+ ##
273
+
251
274
  self.add_function_call(data)
252
275
  else:
253
- # No type specified, default to function call
276
+ ##
277
+
254
278
  self.add_function_call(package)
255
279
 
256
- # Handle high priority items
280
+ ##
281
+
257
282
  if priority == "high":
258
283
  self.dispatch("high_priority")
259
284
 
260
285
  return True
261
286
 
262
287
  def dispatch(self, reason="manual"):
263
- """Send queued data"""
288
+ #--
264
289
  if not self.webhook_url:
265
290
  return False
266
291
 
267
292
  with self.lock:
268
- # Check if all buffers are empty
293
+ ##
294
+
269
295
  if all(len(records) == 0 for records in self.buffer.values()):
270
296
  return False
271
297
 
272
- # Create a copy of the buffer for sending
298
+ ##
299
+
273
300
  data_to_send = {
274
301
  "function_calls": self.buffer["function_calls"].copy(),
275
302
  "api_requests": self.buffer["api_requests"].copy(),
276
303
  "rate_limits": self.buffer["rate_limits"].copy()
277
304
  }
278
305
 
279
- # Clear buffer
306
+ ##
307
+
280
308
  self.buffer = {
281
309
  "function_calls": [],
282
310
  "api_requests": [],
283
311
  "rate_limits": []
284
312
  }
285
313
 
286
- # Update sync time and count
314
+ ##
315
+
287
316
  self.last_sync_time = time.time()
288
317
  self.sync_count += 1
289
318
  self._save_config()
290
319
 
291
- # Get environment information ONCE
320
+ ##
321
+
292
322
  try:
293
323
  from vnai.scope.profile import inspector
294
324
  environment_info = inspector.examine()
295
325
  machine_id = environment_info.get("machine_id", self.machine_id)
296
326
  except:
297
- # Fallback if environment info isn't available
327
+ ##
328
+
298
329
  environment_info = {"machine_id": self.machine_id}
299
330
  machine_id = self.machine_id
300
331
 
301
- # Create payload with environment info only in metadata
332
+ ##
333
+
302
334
  payload = {
303
335
  "analytics_data": data_to_send,
304
336
  "metadata": {
@@ -315,7 +347,8 @@ class Conduit:
315
347
  }
316
348
  }
317
349
 
318
- # Send data
350
+ ##
351
+
319
352
  success = self._send_data(payload)
320
353
 
321
354
  if not success:
@@ -327,7 +360,7 @@ class Conduit:
327
360
  return success
328
361
 
329
362
  def _send_data(self, payload):
330
- """Send data to webhook"""
363
+ #--
331
364
  if not self.webhook_url:
332
365
  return False
333
366
 
@@ -335,7 +368,8 @@ class Conduit:
335
368
  response = requests.post(
336
369
  self.webhook_url,
337
370
  json=payload,
338
- timeout=5 # 5 second timeout
371
+ timeout=5 ##
372
+
339
373
  )
340
374
 
341
375
  return response.status_code == 200
@@ -343,7 +377,7 @@ class Conduit:
343
377
  return False
344
378
 
345
379
  def retry_failed(self):
346
- """Retry sending failed data"""
380
+ #--
347
381
  if not self.failed_queue:
348
382
  return 0
349
383
 
@@ -362,18 +396,20 @@ class Conduit:
362
396
  return success_count
363
397
 
364
398
  def configure(self, webhook_url):
365
- """Configure webhook URL"""
399
+ #--
366
400
  with self.lock:
367
401
  self.webhook_url = webhook_url
368
402
  self._save_config()
369
403
  return True
370
404
 
371
- # Create singleton instance
405
+ ##
406
+
372
407
  conduit = Conduit()
373
408
 
374
- # Exposed functions that match sync.py naming pattern
409
+ ##
410
+
375
411
  def track_function_call(function_name, source, execution_time, success=True, error=None, args=None):
376
- """Track function call (bridge to add_function_call)"""
412
+ #--
377
413
  record = {
378
414
  "function": function_name,
379
415
  "source": source,
@@ -386,7 +422,8 @@ def track_function_call(function_name, source, execution_time, success=True, err
386
422
  record["error"] = error
387
423
 
388
424
  if args:
389
- # Sanitize arguments
425
+ ##
426
+
390
427
  sanitized_args = {}
391
428
  if isinstance(args, dict):
392
429
  for key, value in args.items():
@@ -401,7 +438,7 @@ def track_function_call(function_name, source, execution_time, success=True, err
401
438
  conduit.add_function_call(record)
402
439
 
403
440
  def track_rate_limit(source, limit_type, limit_value, current_usage, is_exceeded):
404
- """Track rate limit checks (bridge to add_rate_limit)"""
441
+ #--
405
442
  record = {
406
443
  "source": source,
407
444
  "limit_type": limit_type,
@@ -415,7 +452,7 @@ def track_rate_limit(source, limit_type, limit_value, current_usage, is_exceeded
415
452
  conduit.add_rate_limit(record)
416
453
 
417
454
  def track_api_request(endpoint, source, method, status_code, execution_time, request_size=0, response_size=0):
418
- """Track API requests (bridge to add_api_request)"""
455
+ #--
419
456
  record = {
420
457
  "endpoint": endpoint,
421
458
  "source": source,
@@ -430,13 +467,13 @@ def track_api_request(endpoint, source, method, status_code, execution_time, req
430
467
  conduit.add_api_request(record)
431
468
 
432
469
  def configure(webhook_url):
433
- """Configure webhook URL"""
470
+ #--
434
471
  return conduit.configure(webhook_url)
435
472
 
436
473
  def sync_now():
437
- """Manually trigger synchronization"""
474
+ #--
438
475
  return conduit.dispatch("manual")
439
476
 
440
477
  def retry_failed():
441
- """Retry failed synchronizations"""
478
+ #--
442
479
  return conduit.retry_failed()
vnai/scope/__init__.py CHANGED
@@ -1,5 +1,7 @@
1
- # vnai/scope/__init__.py
2
- # Environment detection and state tracking
1
+ ##
2
+
3
+ ##
4
+
3
5
 
4
6
  from vnai.scope.profile import inspector
5
7
  from vnai.scope.state import tracker, record