refactor(ai_client,gui_2): merge vendor_state split: VendorMetric -> ai_client, get_vendor_state (renamed _get_vendor_state_metrics) -> gui_2; git rm src/vendor_state.py
Per spec FR2 + Phase 2.2 + architecture feedback (data != view):
- VendorMetric (data) -> src/ai_client.py (alongside VendorCapabilities; all vendor data)
- get_vendor_state -> renamed to _get_vendor_state_metrics in src/gui_2.py
(it's a view-helper that builds the metrics for render_vendor_state's table)
- render_vendor_state in gui_2.py now calls _get_vendor_state_metrics directly
Tests:
- tests/test_vendor_state.py: imports get_vendor_state from src.gui_2, VendorMetric from src.ai_client
This commit is contained in:
@@ -3537,3 +3537,13 @@ register(VendorCapabilities(vendor='deepseek', model='deepseek-v3', conte
|
||||
register(VendorCapabilities(vendor='deepseek', model='deepseek-reasoner', context_window=32768, cost_input_per_mtok=0.55, cost_output_per_mtok=2.19, reasoning=True, structured_output=True))
|
||||
register(VendorCapabilities(vendor='deepseek', model='deepseek-r1', context_window=32768, cost_input_per_mtok=0.55, cost_output_per_mtok=2.19, reasoning=True, structured_output=True))
|
||||
#endregion: Vendor Capabilities
|
||||
|
||||
#region: Vendor State (moved from src/vendor_state.py)
|
||||
@dataclass(frozen=True)
|
||||
class VendorMetric:
|
||||
key: str
|
||||
label: str
|
||||
value: str
|
||||
state: str
|
||||
tooltip: str
|
||||
#endregion: Vendor State
|
||||
|
||||
+69
-2
@@ -97,6 +97,7 @@ filedialog = _LazyModule("tkinter", "filedialog") # was: from tkinter import fi
|
||||
Tk = _LazyModule("tkinter", "Tk") # was: from tkinter import Tk
|
||||
|
||||
from src import ai_client
|
||||
from src.ai_client import VendorMetric
|
||||
from src import aggregate
|
||||
from src import api_hooks
|
||||
from src import app_controller
|
||||
@@ -5628,8 +5629,7 @@ def render_vendor_state(app: App) -> None:
|
||||
| Last Error | (none) | info |
|
||||
+---------------------------------------------------------+
|
||||
"""
|
||||
from src.vendor_state import get_vendor_state
|
||||
metrics = get_vendor_state(app)
|
||||
metrics = _get_vendor_state_metrics(app)
|
||||
if imgui.begin_table("vendor_state", 3, imgui.TableFlags_.row_bg | imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Metric", imgui.TableColumnFlags_.width_fixed, 180)
|
||||
imgui.table_setup_column("Value", imgui.TableColumnFlags_.width_stretch)
|
||||
@@ -8704,3 +8704,70 @@ def render_palette_modal(app: Any, commands: List[Any]) -> None:
|
||||
imgui.end_child()
|
||||
imgui.end()
|
||||
#endregion: Command Palette Modal
|
||||
|
||||
#region: Vendor State Metrics (moved from src/vendor_state.py; VendorMetric dataclass lives in src/ai_client.py)
|
||||
def _get_vendor_state_metrics(app: Any) -> list[Any]:
|
||||
out: list[Any] = []
|
||||
out.append(VendorMetric(
|
||||
key = "provider_model",
|
||||
label = "Provider / Model",
|
||||
value = f"{app.current_provider} / {app.current_model}",
|
||||
state = "info",
|
||||
tooltip = "The vendor and model that will handle the next request."
|
||||
))
|
||||
ctrl = getattr(app, "controller", None)
|
||||
tt = getattr(ctrl, "token_tracker", None) if ctrl else None
|
||||
if tt and getattr(tt, "limit", 0):
|
||||
pct = 100.0 * getattr(tt, "used", 0) / tt.limit
|
||||
state = "warn" if pct > 75 else "ok"
|
||||
out.append(VendorMetric(
|
||||
key = "context_window",
|
||||
label = "Context Window",
|
||||
value = f"{tt.used:,} / {tt.limit:,} ({pct:.0f}%)",
|
||||
state = state,
|
||||
tooltip = "Used vs total context window for the current session."
|
||||
))
|
||||
else:
|
||||
out.append(VendorMetric(
|
||||
key = "context_window", label="Context Window", value="—", state="info",
|
||||
tooltip = "No token tracker attached for the current provider."
|
||||
))
|
||||
if tt is not None:
|
||||
hits = getattr(tt, "cache_hits", 0)
|
||||
miss = getattr(tt, "cache_misses", 0)
|
||||
total = hits + miss
|
||||
rate = (100.0 * hits / total) if total else 0.0
|
||||
out.append(VendorMetric(
|
||||
key = "cache", label="Cache Hit Rate",
|
||||
value = f"{rate:.0f}% ({hits:,}/{total:,})",
|
||||
state = "ok" if rate > 50 else "info",
|
||||
tooltip = "Server-side prompt cache hit rate for the current session."
|
||||
))
|
||||
else:
|
||||
out.append(VendorMetric(
|
||||
key = "cache", label="Cache Hit Rate", value="—", state="info",
|
||||
tooltip = "No token tracker attached for the current provider."
|
||||
))
|
||||
quota = (getattr(ctrl, "vendor_quota", {}) or {}) if ctrl else {}
|
||||
pct_left = quota.get("remaining_pct")
|
||||
if pct_left is None:
|
||||
out.append(VendorMetric(
|
||||
key = "quota", label="Vendor Quota", value="—", state="info",
|
||||
tooltip = "Vendor did not report quota for the current billing period."
|
||||
))
|
||||
else:
|
||||
out.append(VendorMetric(
|
||||
key = "quota", label="Vendor Quota",
|
||||
value = f"{pct_left}% remaining",
|
||||
state = "ok" if pct_left > 25 else "warn",
|
||||
tooltip = "Approximate quota remaining for the current billing period."
|
||||
))
|
||||
err = getattr(ctrl, "last_error", None) if ctrl else None
|
||||
out.append(VendorMetric(
|
||||
key = "last_error", label="Last Error",
|
||||
value = err.get("class", "none") if err else "none",
|
||||
state = "error" if err else "ok",
|
||||
tooltip = err.get("message", "No error since session start.") if err else "No error since session start."
|
||||
))
|
||||
return out
|
||||
#endregion: Vendor State Metrics
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class VendorMetric:
|
||||
"""Atomic vendor-state metric.
|
||||
[C: src/gui_2.py:render_vendor_state]
|
||||
"""
|
||||
key: str
|
||||
label: str
|
||||
value: str
|
||||
state: str
|
||||
tooltip: str
|
||||
|
||||
def get_vendor_state(app) -> list[VendorMetric]:
|
||||
"""Aggregate per-vendor session state for the Operations Hub Vendor State tab.
|
||||
[C: src/gui_2.py:render_vendor_state]
|
||||
"""
|
||||
out: list[VendorMetric] = []
|
||||
out.append(VendorMetric(
|
||||
key = "provider_model",
|
||||
label = "Provider / Model",
|
||||
value = f"{app.current_provider} / {app.current_model}",
|
||||
state = "info",
|
||||
tooltip = "The vendor and model that will handle the next request."
|
||||
))
|
||||
ctrl = getattr(app, "controller", None)
|
||||
tt = getattr(ctrl, "token_tracker", None) if ctrl else None
|
||||
if tt and getattr(tt, "limit", 0):
|
||||
pct = 100.0 * getattr(tt, "used", 0) / tt.limit
|
||||
state = "warn" if pct > 75 else "ok"
|
||||
out.append(VendorMetric(
|
||||
key = "context_window",
|
||||
label = "Context Window",
|
||||
value = f"{tt.used:,} / {tt.limit:,} ({pct:.0f}%)",
|
||||
state = state,
|
||||
tooltip = "Used vs total context window for the current session."
|
||||
))
|
||||
else:
|
||||
out.append(VendorMetric(
|
||||
key = "context_window", label="Context Window", value="—", state="info",
|
||||
tooltip = "No token tracker attached for the current provider."
|
||||
))
|
||||
if tt is not None:
|
||||
hits = getattr(tt, "cache_hits", 0)
|
||||
miss = getattr(tt, "cache_misses", 0)
|
||||
total = hits + miss
|
||||
rate = (100.0 * hits / total) if total else 0.0
|
||||
out.append(VendorMetric(
|
||||
key = "cache", label="Cache Hit Rate",
|
||||
value = f"{rate:.0f}% ({hits:,}/{total:,})",
|
||||
state = "ok" if rate > 50 else "info",
|
||||
tooltip = "Server-side prompt cache hit rate for the current session."
|
||||
))
|
||||
else:
|
||||
out.append(VendorMetric(
|
||||
key = "cache", label="Cache Hit Rate", value="—", state="info",
|
||||
tooltip = "No token tracker attached for the current provider."
|
||||
))
|
||||
quota = (getattr(ctrl, "vendor_quota", {}) or {}) if ctrl else {}
|
||||
pct_left = quota.get("remaining_pct")
|
||||
if pct_left is None:
|
||||
out.append(VendorMetric(
|
||||
key = "quota", label="Vendor Quota", value="—", state="info",
|
||||
tooltip = "Vendor did not report quota for the current billing period."
|
||||
))
|
||||
else:
|
||||
out.append(VendorMetric(
|
||||
key = "quota", label="Vendor Quota",
|
||||
value = f"{pct_left}% remaining",
|
||||
state = "ok" if pct_left > 25 else "warn",
|
||||
tooltip = "Approximate quota remaining for the current billing period."
|
||||
))
|
||||
err = getattr(ctrl, "last_error", None) if ctrl else None
|
||||
out.append(VendorMetric(
|
||||
key = "last_error", label="Last Error",
|
||||
value = err.get("class", "none") if err else "none",
|
||||
state = "error" if err else "ok",
|
||||
tooltip = err.get("message", "No error since session start.") if err else "No error since session start."
|
||||
))
|
||||
return out
|
||||
@@ -1,4 +1,5 @@
|
||||
from src.vendor_state import get_vendor_state, VendorMetric
|
||||
from src.gui_2 import _get_vendor_state_metrics as get_vendor_state
|
||||
from src.ai_client import VendorMetric
|
||||
|
||||
class _StubTT:
|
||||
def __init__(self, used=0, limit=0, cache_hits=0, cache_misses=0):
|
||||
|
||||
Reference in New Issue
Block a user