mirror of
https://github.com/ruvnet/RuView
synced 2026-07-28 18:21:42 +00:00
feat: vendor midstream and sublinear-time-solver libraries
Add ruvnet/midstream (AIMDS real-time inference) and ruvnet/sublinear-time-solver (sublinear optimization algorithms) as vendored dependencies under vendor/. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
+9
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Hyprstream Python client library for interacting with the Hyprstream metrics service.
|
||||
"""
|
||||
|
||||
from .client import MetricsClient
|
||||
from .types import MetricRecord
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__all__ = ["MetricsClient", "MetricRecord"]
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
"""Command line interface for the Hyprstream client."""
|
||||
|
||||
import time
|
||||
import click
|
||||
import pandas as pd
|
||||
from typing import List, Optional
|
||||
|
||||
from .client import MetricsClient, MetricRecord
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
"""Hyprstream metrics client CLI."""
|
||||
pass
|
||||
|
||||
@cli.command()
|
||||
@click.option('--metric-id', required=True, help='ID of the metric to set')
|
||||
@click.option('--value', required=True, type=float, help='Value to set')
|
||||
@click.option('--window-size', default=10, type=int, help='Size of the running window')
|
||||
@click.option('--host', default='localhost', help='Hyprstream server host')
|
||||
@click.option('--port', default=50051, type=int, help='Hyprstream server port')
|
||||
def set_metric(metric_id: str, value: float, window_size: int, host: str, port: int):
|
||||
"""Set a single metric value."""
|
||||
connection_string = f"grpc://{host}:{port}"
|
||||
with MetricsClient(connection_string) as client:
|
||||
metric = MetricRecord(
|
||||
metric_id=metric_id,
|
||||
timestamp=int(time.time() * 1e9),
|
||||
value_running_window_sum=value * window_size,
|
||||
value_running_window_avg=value,
|
||||
value_running_window_count=window_size
|
||||
)
|
||||
client.set_metric(metric)
|
||||
click.echo(f"Set metric {metric_id} to {value}")
|
||||
|
||||
@cli.command()
|
||||
@click.option('--metric-id', multiple=True, help='Filter by metric ID')
|
||||
@click.option('--window', default=60, type=int, help='Time window in seconds')
|
||||
@click.option('--host', default='localhost', help='Hyprstream server host')
|
||||
@click.option('--port', default=50051, type=int, help='Hyprstream server port')
|
||||
def query_metrics(metric_id: Optional[List[str]], window: int, host: str, port: int):
|
||||
"""Query metrics within a time window."""
|
||||
connection_string = f"grpc://{host}:{port}"
|
||||
with MetricsClient(connection_string) as client:
|
||||
if metric_id:
|
||||
df = client.query_metrics(
|
||||
metric_ids=list(metric_id),
|
||||
from_timestamp=int((time.time() - window) * 1e9)
|
||||
)
|
||||
else:
|
||||
df = client.get_metrics_window(window)
|
||||
|
||||
if df.empty:
|
||||
click.echo("No metrics found")
|
||||
else:
|
||||
# Format timestamp for better readability
|
||||
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ns')
|
||||
click.echo(df.to_string())
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
"""Client implementation for the Hyprstream metrics service."""
|
||||
|
||||
import time
|
||||
from typing import List, Optional, Dict, Any, Union
|
||||
|
||||
import pyarrow as pa
|
||||
import pyarrow.flight as flight
|
||||
import adbc_driver_flightsql
|
||||
import adbc_driver_flightsql.dbapi
|
||||
import pandas as pd
|
||||
|
||||
from .types import MetricRecord
|
||||
|
||||
class MetricsClient:
|
||||
"""Client for interacting with the Hyprstream metrics service."""
|
||||
|
||||
def __init__(self, connection_string: str = "grpc://localhost:50051"):
|
||||
"""Initialize the metrics client with a connection string."""
|
||||
self.connection_string = connection_string
|
||||
self.conn = None
|
||||
|
||||
def connect(self):
|
||||
"""Establish connection to the Flight SQL server."""
|
||||
print("Connecting to Flight SQL server")
|
||||
self.conn = adbc_driver_flightsql.dbapi.connect(self.connection_string)
|
||||
|
||||
def disconnect(self):
|
||||
"""Close the connection to the Flight SQL server."""
|
||||
if self.conn:
|
||||
self.conn.close()
|
||||
self.conn = None
|
||||
|
||||
def __enter__(self):
|
||||
"""Context manager entry."""
|
||||
self.connect()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""Context manager exit."""
|
||||
self.disconnect()
|
||||
|
||||
def set_metric(self, metric: Union[MetricRecord, Dict[str, Any]]) -> None:
|
||||
"""Insert or update a single metric."""
|
||||
if not self.conn:
|
||||
raise ConnectionError("Not connected to server")
|
||||
|
||||
if isinstance(metric, dict):
|
||||
metric = MetricRecord.from_dict(metric)
|
||||
|
||||
query = """
|
||||
INSERT INTO metrics (
|
||||
metric_id, timestamp, value_running_window_sum,
|
||||
value_running_window_avg, value_running_window_count
|
||||
) VALUES (?, ?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
cursor = self.conn.cursor()
|
||||
try:
|
||||
cursor.execute(query, [
|
||||
metric.metric_id,
|
||||
metric.timestamp,
|
||||
metric.value_running_window_sum,
|
||||
metric.value_running_window_avg,
|
||||
metric.value_running_window_count
|
||||
])
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def set_metrics_batch(self, metrics: List[Union[MetricRecord, Dict[str, Any]]]) -> None:
|
||||
"""Insert multiple metrics using Arrow's native batching."""
|
||||
if not self.conn:
|
||||
raise ConnectionError("Not connected to server")
|
||||
|
||||
# Convert all metrics to MetricRecord objects
|
||||
records = [
|
||||
m if isinstance(m, MetricRecord) else MetricRecord.from_dict(m)
|
||||
for m in metrics
|
||||
]
|
||||
|
||||
# Create Arrow arrays
|
||||
metric_ids = pa.array([r.metric_id for r in records], type=pa.string())
|
||||
timestamps = pa.array([r.timestamp for r in records], type=pa.int64())
|
||||
sums = pa.array([r.value_running_window_sum for r in records], type=pa.float64())
|
||||
avgs = pa.array([r.value_running_window_avg for r in records], type=pa.float64())
|
||||
counts = pa.array([r.value_running_window_count for r in records], type=pa.int64())
|
||||
|
||||
# Create Arrow table
|
||||
table = pa.Table.from_arrays(
|
||||
[metric_ids, timestamps, sums, avgs, counts],
|
||||
names=[
|
||||
'metric_id', 'timestamp', 'value_running_window_sum',
|
||||
'value_running_window_avg', 'value_running_window_count'
|
||||
]
|
||||
)
|
||||
|
||||
cursor = self.conn.cursor()
|
||||
try:
|
||||
cursor.adbc_statement.set_sql_query("""
|
||||
INSERT INTO metrics (
|
||||
metric_id, timestamp, value_running_window_sum,
|
||||
value_running_window_avg, value_running_window_count
|
||||
) VALUES (?, ?, ?, ?, ?)
|
||||
""")
|
||||
cursor.adbc_statement.bind(table)
|
||||
cursor.adbc_statement.execute_update()
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
print(f"Inserted {len(records)} metrics in batch")
|
||||
|
||||
def query_metrics(self,
|
||||
from_timestamp: Optional[int] = None,
|
||||
to_timestamp: Optional[int] = None,
|
||||
metric_ids: Optional[List[str]] = None) -> pd.DataFrame:
|
||||
"""Query metrics with flexible filtering."""
|
||||
if not self.conn:
|
||||
raise ConnectionError("Not connected to server")
|
||||
|
||||
conditions = []
|
||||
params = []
|
||||
|
||||
if from_timestamp is not None:
|
||||
conditions.append("timestamp >= ?")
|
||||
params.append(from_timestamp)
|
||||
|
||||
if to_timestamp is not None:
|
||||
conditions.append("timestamp <= ?")
|
||||
params.append(to_timestamp)
|
||||
|
||||
if metric_ids:
|
||||
placeholders = ','.join(['?' for _ in metric_ids])
|
||||
conditions.append(f"metric_id IN ({placeholders})")
|
||||
params.extend(metric_ids)
|
||||
|
||||
where_clause = " AND ".join(conditions) if conditions else "1=1"
|
||||
|
||||
query = f"""
|
||||
SELECT * FROM metrics
|
||||
WHERE {where_clause}
|
||||
ORDER BY timestamp ASC
|
||||
"""
|
||||
|
||||
cursor = self.conn.cursor()
|
||||
try:
|
||||
cursor.execute(query, params)
|
||||
results = cursor.fetch_arrow_table()
|
||||
|
||||
if results.num_rows > 0:
|
||||
return results.to_pandas()
|
||||
return pd.DataFrame()
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def get_metrics_window(self, window_seconds: int = 60) -> pd.DataFrame:
|
||||
"""Get metrics within a time window from now."""
|
||||
current_time = int(time.time() * 1e9)
|
||||
from_timestamp = current_time - (window_seconds * 1_000_000_000)
|
||||
return self.query_metrics(from_timestamp=from_timestamp)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
"""Type definitions for the Hyprstream client."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, Any
|
||||
import time
|
||||
|
||||
@dataclass
|
||||
class MetricRecord:
|
||||
"""Represents a metric record matching the server's schema."""
|
||||
metric_id: str
|
||||
timestamp: int
|
||||
value_running_window_sum: float
|
||||
value_running_window_avg: float
|
||||
value_running_window_count: int
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, Any]) -> 'MetricRecord':
|
||||
"""Create a MetricRecord from a dictionary, handling field name mappings."""
|
||||
return cls(
|
||||
metric_id=str(data.get('metric_id')), # Ensure string type
|
||||
timestamp=data.get('timestamp', int(time.time() * 1e9)),
|
||||
value_running_window_sum=float(data.get('value_running_window_sum', 0.0)),
|
||||
value_running_window_avg=float(data.get('value_running_window_avg', 0.0)),
|
||||
value_running_window_count=int(data.get('value_running_window_count', 0))
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Convert to dictionary for database operations."""
|
||||
return {
|
||||
'metric_id': self.metric_id,
|
||||
'timestamp': self.timestamp,
|
||||
'value_running_window_sum': self.value_running_window_sum,
|
||||
'value_running_window_avg': self.value_running_window_avg,
|
||||
'value_running_window_count': self.value_running_window_count
|
||||
}
|
||||
Reference in New Issue
Block a user