mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
Retire the request-time hint API. PR-B5 splits TOIN into two phases:
1. Observation: TOIN keeps recording compressions/retrievals at runtime,
but `get_recommendation()` is deprecated and now returns None.
2. Publish-then-load: the new `headroom.cli.toin_publish` CLI walks the
on-disk store and emits `recommendations.toml`. The Rust proxy reads
that file once at startup via `transforms::recommendations` and
exposes `get(auth_mode, model, structure_hash) -> Option<&Rec>`.
PR-F3 will wire the loader into the live-zone dispatcher.
Per-tenant aggregation: `_patterns` is now keyed by
`(auth_mode, model_family, sig_hash)` so PAYG/OAuth/subscription tenants
no longer share buckets. Callers that don't supply auth/model land in the
`("unknown", "unknown", sig_hash)` slot. Added `_make_pattern_key` helper
+ updated tests that previously indexed by raw `structure_hash`.
AuthMode is canonical in `transforms::live_zone`; `transforms::recommendations`
re-exports it (no duplicate enum). Live-zone enum gained `Unknown`,
`as_str()`, and `Hash` derive to serve recommendations callers without a
second source of truth.
Why: per-request hint calls coupled output to mutable TOIN state, breaking
prompt-cache stability across runs (P2-27, P5-56). Pulling advice into a
startup-published TOML keeps per-request output deterministic and lets the
deploy pipeline gate publication independently of proxy uptime.
Per-PR-B5 plan: REALIGNMENT/04-phase-B-live-zone.md.
710 lines
29 KiB
Python
710 lines
29 KiB
Python
"""Full integration tests for TOIN (Tool Output Intelligence Network).
|
|
|
|
These tests verify ACTUAL TOIN functionality with NO MOCKS.
|
|
Run with: pytest tests/test_toin_full_integration.py -v -s
|
|
|
|
The -s flag is important to see print() output showing TOIN in action.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from headroom.config import CCRConfig
|
|
from headroom.telemetry.models import ToolSignature
|
|
from headroom.telemetry.toin import (
|
|
TOIN_PATH_ENV_VAR,
|
|
TOINConfig,
|
|
ToolIntelligenceNetwork,
|
|
get_default_toin_storage_path,
|
|
get_toin,
|
|
reset_toin,
|
|
)
|
|
from headroom.transforms.smart_crusher import SmartCrusher, SmartCrusherConfig
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def reset_globals():
|
|
"""Reset global TOIN state before and after each test."""
|
|
reset_toin()
|
|
yield
|
|
reset_toin()
|
|
|
|
|
|
@pytest.fixture
|
|
def fresh_toin():
|
|
"""Create a fresh TOIN instance with temp storage."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
storage_path = str(Path(tmpdir) / "toin_test.json")
|
|
config = TOINConfig(storage_path=storage_path)
|
|
toin = ToolIntelligenceNetwork(config)
|
|
yield toin
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_tool_signature():
|
|
"""Create a sample tool signature from realistic data."""
|
|
items = [
|
|
{"id": i, "name": f"item_{i}", "status": "active", "score": 0.5 + i * 0.1}
|
|
for i in range(10)
|
|
]
|
|
return ToolSignature.from_items(items)
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_items():
|
|
"""Generate sample tool output items for testing."""
|
|
return [
|
|
{"id": i, "name": f"item_{i}", "status": "active", "score": 0.5 + i * 0.1}
|
|
for i in range(100)
|
|
]
|
|
|
|
|
|
class TestTOINDefaultStoragePath:
|
|
"""Test 1: Verify TOINConfig default storage path behavior."""
|
|
|
|
def test_toin_default_storage_path_exists(self):
|
|
"""Verify that TOINConfig now defaults to a storage path."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_toin_default_storage_path_exists")
|
|
print("=" * 60)
|
|
|
|
# Create config without specifying storage_path
|
|
config = TOINConfig()
|
|
|
|
print(f"\nDefault storage_path: {config.storage_path}")
|
|
print("Expected location: ~/.headroom/toin.json")
|
|
|
|
# Verify it's not None/empty
|
|
assert config.storage_path, "TOINConfig should have a default storage_path"
|
|
|
|
# Verify it points to expected location
|
|
expected_suffix = ".headroom/toin.json"
|
|
assert config.storage_path.endswith(expected_suffix), (
|
|
f"Default path should end with {expected_suffix}, got: {config.storage_path}"
|
|
)
|
|
|
|
# Verify the get_default_toin_storage_path function works
|
|
default_path = get_default_toin_storage_path()
|
|
print(f"get_default_toin_storage_path(): {default_path}")
|
|
assert default_path == config.storage_path
|
|
|
|
print("\n[PASS] Default storage path is correctly configured")
|
|
|
|
def test_headroom_toin_path_env_var(self):
|
|
"""Verify HEADROOM_TOIN_PATH env var overrides default."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_headroom_toin_path_env_var")
|
|
print("=" * 60)
|
|
|
|
# Save original env value
|
|
original_value = os.environ.get(TOIN_PATH_ENV_VAR)
|
|
|
|
try:
|
|
# Set custom path via env var
|
|
custom_path = "/tmp/custom_toin_test.json"
|
|
os.environ[TOIN_PATH_ENV_VAR] = custom_path
|
|
|
|
print(f"\nSet {TOIN_PATH_ENV_VAR}={custom_path}")
|
|
|
|
# Create config - should use env var
|
|
config = TOINConfig()
|
|
print(f"TOINConfig.storage_path: {config.storage_path}")
|
|
|
|
assert config.storage_path == custom_path, (
|
|
f"Expected {custom_path}, got {config.storage_path}"
|
|
)
|
|
|
|
# Also verify get_default_toin_storage_path respects env var
|
|
default_path = get_default_toin_storage_path()
|
|
print(f"get_default_toin_storage_path(): {default_path}")
|
|
assert default_path == custom_path
|
|
|
|
print("\n[PASS] HEADROOM_TOIN_PATH env var works correctly")
|
|
|
|
finally:
|
|
# Restore original env
|
|
if original_value is None:
|
|
os.environ.pop(TOIN_PATH_ENV_VAR, None)
|
|
else:
|
|
os.environ[TOIN_PATH_ENV_VAR] = original_value
|
|
|
|
def test_empty_env_var_uses_default(self):
|
|
"""Verify empty HEADROOM_TOIN_PATH falls back to default."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_empty_env_var_uses_default")
|
|
print("=" * 60)
|
|
|
|
original_value = os.environ.get(TOIN_PATH_ENV_VAR)
|
|
|
|
try:
|
|
# Set empty env var
|
|
os.environ[TOIN_PATH_ENV_VAR] = ""
|
|
print(f"\nSet {TOIN_PATH_ENV_VAR}='' (empty)")
|
|
|
|
default_path = get_default_toin_storage_path()
|
|
print(f"get_default_toin_storage_path(): {default_path}")
|
|
|
|
# Should fall back to default ~/.headroom/toin.json
|
|
assert ".headroom/toin.json" in default_path, (
|
|
f"Empty env var should use default, got: {default_path}"
|
|
)
|
|
|
|
print("\n[PASS] Empty env var correctly falls back to default")
|
|
|
|
finally:
|
|
if original_value is None:
|
|
os.environ.pop(TOIN_PATH_ENV_VAR, None)
|
|
else:
|
|
os.environ[TOIN_PATH_ENV_VAR] = original_value
|
|
|
|
|
|
class TestTOINPersistenceAcrossInstances:
|
|
"""Test 2: Verify TOIN persistence across instances."""
|
|
|
|
def test_toin_persistence_across_instances(self, sample_tool_signature):
|
|
"""Verify patterns persist when creating new TOIN instances."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_toin_persistence_across_instances")
|
|
print("=" * 60)
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
storage_path = str(Path(tmpdir) / "toin_persistence_test.json")
|
|
|
|
# Create first TOIN instance and record compressions
|
|
print("\n--- Phase 1: Create TOIN and record compressions ---")
|
|
config1 = TOINConfig(storage_path=storage_path)
|
|
toin1 = ToolIntelligenceNetwork(config1)
|
|
|
|
# Record several compressions
|
|
for i in range(5):
|
|
toin1.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100,
|
|
compressed_count=15,
|
|
original_tokens=5000,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample",
|
|
query_context=f"test query {i}",
|
|
)
|
|
|
|
# Record some retrievals
|
|
for i in range(2):
|
|
toin1.record_retrieval(
|
|
tool_signature_hash=sample_tool_signature.structure_hash,
|
|
retrieval_type="search",
|
|
query=f"field:value_{i}",
|
|
strategy="smart_sample",
|
|
)
|
|
|
|
stats_before = toin1.get_stats()
|
|
patterns_before = len(toin1._patterns)
|
|
print(f"Patterns tracked before save: {patterns_before}")
|
|
print(f"Total compressions before save: {stats_before['total_compressions']}")
|
|
print(f"Total retrievals before save: {stats_before['total_retrievals']}")
|
|
|
|
# Save to disk
|
|
toin1.save()
|
|
print(f"\nSaved to: {storage_path}")
|
|
|
|
# Verify file exists and show content
|
|
assert Path(storage_path).exists(), "TOIN file should exist after save"
|
|
with open(storage_path) as f:
|
|
saved_data = json.load(f)
|
|
print(f"Saved patterns count: {len(saved_data.get('patterns', {}))}")
|
|
|
|
# Create NEW TOIN instance with same path
|
|
print("\n--- Phase 2: Create new TOIN instance from same path ---")
|
|
config2 = TOINConfig(storage_path=storage_path)
|
|
toin2 = ToolIntelligenceNetwork(config2)
|
|
|
|
stats_after = toin2.get_stats()
|
|
patterns_after = len(toin2._patterns)
|
|
print(f"Patterns tracked after load: {patterns_after}")
|
|
print(f"Total compressions after load: {stats_after['total_compressions']}")
|
|
print(f"Total retrievals after load: {stats_after['total_retrievals']}")
|
|
|
|
# Verify patterns were loaded
|
|
assert patterns_after >= patterns_before, (
|
|
f"Should have at least {patterns_before} patterns after reload, got {patterns_after}"
|
|
)
|
|
assert stats_after["total_compressions"] >= stats_before["total_compressions"], (
|
|
"Compressions should persist"
|
|
)
|
|
|
|
# Verify specific pattern exists
|
|
pattern = toin2.get_pattern(sample_tool_signature.structure_hash)
|
|
assert pattern is not None, "Pattern for our tool signature should exist"
|
|
print("\nReloaded pattern details:")
|
|
print(f" - total_compressions: {pattern.total_compressions}")
|
|
print(f" - total_retrievals: {pattern.total_retrievals}")
|
|
print(f" - sample_size: {pattern.sample_size}")
|
|
print(f" - confidence: {pattern.confidence:.3f}")
|
|
|
|
print("\n[PASS] TOIN persistence works correctly")
|
|
|
|
|
|
@pytest.mark.skip(
|
|
reason="PR-B5: get_recommendation retired; feedback-loop covered by test_toin_observation_only.py"
|
|
)
|
|
class TestTOINFullFeedbackLoop:
|
|
"""Test 3: Verify TOIN feedback loop with recommendations."""
|
|
|
|
def test_toin_full_feedback_loop(self, sample_tool_signature):
|
|
"""Verify TOIN learns from high retrieval rate and recommends skip."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_toin_full_feedback_loop")
|
|
print("=" * 60)
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
storage_path = str(Path(tmpdir) / "toin_feedback_test.json")
|
|
config = TOINConfig(
|
|
storage_path=storage_path,
|
|
min_samples_for_recommendation=5, # Lower threshold for test
|
|
high_retrieval_threshold=0.5, # 50% retrieval = high
|
|
)
|
|
toin = ToolIntelligenceNetwork(config)
|
|
|
|
print("\n--- Phase 1: Record compressions ---")
|
|
# Record 5 compressions with same tool signature
|
|
for i in range(5):
|
|
toin.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100,
|
|
compressed_count=15,
|
|
original_tokens=5000,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample",
|
|
)
|
|
print(f" Recorded compression {i + 1}")
|
|
|
|
print("\n--- Phase 2: Record retrievals (simulating high retrieval rate) ---")
|
|
# Record 3 full retrievals (60% retrieval rate = high)
|
|
for i in range(3):
|
|
toin.record_retrieval(
|
|
tool_signature_hash=sample_tool_signature.structure_hash,
|
|
retrieval_type="full", # Full retrieval = compression too aggressive
|
|
strategy="smart_sample",
|
|
)
|
|
print(f" Recorded full retrieval {i + 1}")
|
|
|
|
# Get pattern stats
|
|
pattern = toin.get_pattern(sample_tool_signature.structure_hash)
|
|
print("\n--- Pattern Stats ---")
|
|
print(f" total_compressions: {pattern.total_compressions}")
|
|
print(f" total_retrievals: {pattern.total_retrievals}")
|
|
print(f" retrieval_rate: {pattern.retrieval_rate:.1%}")
|
|
print(f" full_retrieval_rate: {pattern.full_retrieval_rate:.1%}")
|
|
print(f" skip_compression_recommended: {pattern.skip_compression_recommended}")
|
|
|
|
# Get recommendation
|
|
print("\n--- Getting Recommendation ---")
|
|
hint = toin.get_recommendation(sample_tool_signature)
|
|
print(f" source: {hint.source}")
|
|
print(f" skip_compression: {hint.skip_compression}")
|
|
print(f" compression_level: {hint.compression_level}")
|
|
print(f" max_items: {hint.max_items}")
|
|
print(f" confidence: {hint.confidence:.3f}")
|
|
print(f" reason: {hint.reason}")
|
|
print(f" based_on_samples: {hint.based_on_samples}")
|
|
|
|
# Verify high retrieval rate triggers skip recommendation
|
|
# With 60% retrieval rate (3/5) and full_retrieval_rate of 100% (3/3),
|
|
# TOIN should recommend skipping compression
|
|
retrieval_rate = pattern.retrieval_rate
|
|
assert retrieval_rate >= 0.5, (
|
|
f"Expected retrieval rate >= 50%, got {retrieval_rate:.1%}"
|
|
)
|
|
|
|
# With high retrieval rate and high full retrieval rate, should skip
|
|
if pattern.full_retrieval_rate > 0.8:
|
|
assert hint.skip_compression or hint.compression_level in (
|
|
"none",
|
|
"conservative",
|
|
), (
|
|
f"High full retrieval rate should trigger skip or conservative, "
|
|
f"got compression_level={hint.compression_level}"
|
|
)
|
|
print("\n[PASS] High retrieval rate correctly influences recommendation")
|
|
else:
|
|
print("\n[INFO] Full retrieval rate not high enough for skip recommendation")
|
|
print(f" full_retrieval_rate: {pattern.full_retrieval_rate:.1%}")
|
|
|
|
print("\n[PASS] TOIN feedback loop works correctly")
|
|
|
|
|
|
@pytest.mark.skip(
|
|
reason="PR-B5: get_recommendation retired; confidence-progression validated via record + get_pattern instead"
|
|
)
|
|
class TestTOINProgressiveConfidence:
|
|
"""Test 4: Verify TOIN confidence increases with sample size."""
|
|
|
|
def test_toin_progressive_confidence(self, sample_tool_signature):
|
|
"""Verify confidence increases with more samples."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_toin_progressive_confidence")
|
|
print("=" * 60)
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
storage_path = str(Path(tmpdir) / "toin_confidence_test.json")
|
|
config = TOINConfig(
|
|
storage_path=storage_path,
|
|
min_samples_for_recommendation=3,
|
|
)
|
|
toin = ToolIntelligenceNetwork(config)
|
|
|
|
confidence_history = []
|
|
|
|
# Batch 1: Record 1 compression
|
|
print("\n--- Batch 1: 1 compression ---")
|
|
toin.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100,
|
|
compressed_count=15,
|
|
original_tokens=5000,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample",
|
|
)
|
|
pattern = toin.get_pattern(sample_tool_signature.structure_hash)
|
|
hint = toin.get_recommendation(sample_tool_signature)
|
|
confidence_history.append(pattern.confidence)
|
|
print(f" sample_size: {pattern.sample_size}")
|
|
print(f" confidence: {pattern.confidence:.3f}")
|
|
print(f" hint.source: {hint.source}")
|
|
|
|
# Batch 2: Record 2 more compressions
|
|
print("\n--- Batch 2: +2 compressions (total: 3) ---")
|
|
for _ in range(2):
|
|
toin.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100,
|
|
compressed_count=15,
|
|
original_tokens=5000,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample",
|
|
)
|
|
pattern = toin.get_pattern(sample_tool_signature.structure_hash)
|
|
hint = toin.get_recommendation(sample_tool_signature)
|
|
confidence_history.append(pattern.confidence)
|
|
print(f" sample_size: {pattern.sample_size}")
|
|
print(f" confidence: {pattern.confidence:.3f}")
|
|
print(f" hint.source: {hint.source}")
|
|
|
|
# Batch 3: Record 2 more compressions
|
|
print("\n--- Batch 3: +2 compressions (total: 5) ---")
|
|
for _ in range(2):
|
|
toin.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100,
|
|
compressed_count=15,
|
|
original_tokens=5000,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample",
|
|
)
|
|
pattern = toin.get_pattern(sample_tool_signature.structure_hash)
|
|
hint = toin.get_recommendation(sample_tool_signature)
|
|
confidence_history.append(pattern.confidence)
|
|
print(f" sample_size: {pattern.sample_size}")
|
|
print(f" confidence: {pattern.confidence:.3f}")
|
|
print(f" hint.source: {hint.source}")
|
|
|
|
# Batch 4: Add many more to boost confidence
|
|
print("\n--- Batch 4: +15 compressions (total: 20) ---")
|
|
for _ in range(15):
|
|
toin.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100,
|
|
compressed_count=15,
|
|
original_tokens=5000,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample",
|
|
)
|
|
pattern = toin.get_pattern(sample_tool_signature.structure_hash)
|
|
hint = toin.get_recommendation(sample_tool_signature)
|
|
confidence_history.append(pattern.confidence)
|
|
print(f" sample_size: {pattern.sample_size}")
|
|
print(f" confidence: {pattern.confidence:.3f}")
|
|
print(f" hint.source: {hint.source}")
|
|
|
|
# Print confidence progression
|
|
print("\n--- Confidence Progression ---")
|
|
for i, conf in enumerate(confidence_history):
|
|
print(f" Stage {i + 1}: confidence = {conf:.3f}")
|
|
|
|
# Verify confidence increases with sample size
|
|
# Confidence should generally increase (may plateau at high values)
|
|
assert confidence_history[-1] >= confidence_history[0], (
|
|
f"Confidence should increase: start={confidence_history[0]:.3f}, "
|
|
f"end={confidence_history[-1]:.3f}"
|
|
)
|
|
|
|
# With 20 samples, should have meaningful confidence
|
|
assert confidence_history[-1] >= 0.1, (
|
|
f"With 20 samples, confidence should be >= 0.1, got {confidence_history[-1]:.3f}"
|
|
)
|
|
|
|
print("\n[PASS] Confidence increases with sample size")
|
|
|
|
|
|
class TestTOINWithSmartCrusher:
|
|
"""Test 5: Verify TOIN integration with SmartCrusher."""
|
|
|
|
def test_toin_with_smartcrusher(self, sample_items):
|
|
"""Verify SmartCrusher records compressions to TOIN."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_toin_with_smartcrusher")
|
|
print("=" * 60)
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
storage_path = str(Path(tmpdir) / "toin_smartcrusher_test.json")
|
|
|
|
# Reset global TOIN and configure with our path
|
|
reset_toin()
|
|
config = TOINConfig(storage_path=storage_path)
|
|
toin = get_toin(config)
|
|
|
|
print(f"\nTOIN storage path: {storage_path}")
|
|
print(f"Initial patterns tracked: {toin.get_stats()['patterns_tracked']}")
|
|
|
|
# Create SmartCrusher with CCR enabled
|
|
ccr_config = CCRConfig(
|
|
enabled=True,
|
|
inject_retrieval_marker=False, # Don't add markers for this test
|
|
)
|
|
crusher_config = SmartCrusherConfig(
|
|
enabled=True,
|
|
max_items_after_crush=10,
|
|
use_feedback_hints=True,
|
|
)
|
|
crusher = SmartCrusher(
|
|
config=crusher_config,
|
|
ccr_config=ccr_config,
|
|
)
|
|
|
|
# Compress the sample items
|
|
print("\n--- Compressing 100 items ---")
|
|
json_content = json.dumps(sample_items)
|
|
result = crusher.crush(json_content, query="find items with high scores")
|
|
|
|
print(f"Original items: {len(sample_items)}")
|
|
compressed_items = json.loads(result.compressed)
|
|
print(f"Compressed items: {len(compressed_items)}")
|
|
print(f"Was modified: {result.was_modified}")
|
|
print(f"Strategy: {result.strategy}")
|
|
|
|
# Get TOIN stats after compression
|
|
stats_after = toin.get_stats()
|
|
print("\n--- TOIN Stats After Compression ---")
|
|
print(f" patterns_tracked: {stats_after['patterns_tracked']}")
|
|
print(f" total_compressions: {stats_after['total_compressions']}")
|
|
print(f" total_retrievals: {stats_after['total_retrievals']}")
|
|
|
|
# Verify TOIN recorded the compression
|
|
# Note: SmartCrusher uses internal telemetry which may or may not go through TOIN
|
|
# depending on the integration. Let's check if patterns were recorded.
|
|
if stats_after["patterns_tracked"] > 0:
|
|
print("\n[PASS] SmartCrusher integration with TOIN works")
|
|
else:
|
|
# If no patterns recorded via global TOIN, manually record to verify TOIN works
|
|
print(
|
|
"\n[INFO] SmartCrusher may use internal telemetry, testing manual recording..."
|
|
)
|
|
sig = ToolSignature.from_items(sample_items)
|
|
toin.record_compression(
|
|
tool_signature=sig,
|
|
original_count=len(sample_items),
|
|
compressed_count=len(compressed_items),
|
|
original_tokens=len(json_content),
|
|
compressed_tokens=len(result.compressed),
|
|
strategy="smart_sample",
|
|
)
|
|
stats_manual = toin.get_stats()
|
|
print(f" patterns_tracked after manual: {stats_manual['patterns_tracked']}")
|
|
assert stats_manual["patterns_tracked"] > 0, "Manual recording should work"
|
|
print("\n[PASS] TOIN recording works (manual verification)")
|
|
|
|
|
|
class TestTOINStatsOutput:
|
|
"""Test 6: Verify TOIN stats output format and content."""
|
|
|
|
def test_toin_stats_output(self, sample_tool_signature):
|
|
"""Exercise TOIN and verify stats output."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_toin_stats_output")
|
|
print("=" * 60)
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
storage_path = str(Path(tmpdir) / "toin_stats_test.json")
|
|
config = TOINConfig(storage_path=storage_path)
|
|
toin = ToolIntelligenceNetwork(config)
|
|
|
|
# Exercise TOIN with various operations
|
|
print("\n--- Exercising TOIN ---")
|
|
|
|
# Record compressions
|
|
for i in range(10):
|
|
toin.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100 + i * 10,
|
|
compressed_count=15,
|
|
original_tokens=5000 + i * 500,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample" if i % 2 == 0 else "top_n",
|
|
query_context=f"query with field:value_{i}",
|
|
)
|
|
print(" Recorded 10 compressions")
|
|
|
|
# Record retrievals
|
|
for i in range(3):
|
|
toin.record_retrieval(
|
|
tool_signature_hash=sample_tool_signature.structure_hash,
|
|
retrieval_type="full" if i == 0 else "search",
|
|
query=f"status:error_{i}",
|
|
query_fields=["status", "error"],
|
|
strategy="smart_sample",
|
|
)
|
|
print(" Recorded 3 retrievals")
|
|
|
|
# Get stats
|
|
stats = toin.get_stats()
|
|
|
|
# Print formatted stats
|
|
print("\n--- TOIN Stats ---")
|
|
print(json.dumps(stats, indent=2))
|
|
|
|
# Verify expected keys
|
|
expected_keys = [
|
|
"enabled",
|
|
"patterns_tracked",
|
|
"total_compressions",
|
|
"total_retrievals",
|
|
"global_retrieval_rate",
|
|
"patterns_with_recommendations",
|
|
]
|
|
|
|
print("\n--- Verifying Stats Keys ---")
|
|
for key in expected_keys:
|
|
assert key in stats, f"Stats should contain '{key}'"
|
|
print(f" {key}: {stats[key]}")
|
|
|
|
# Verify values make sense
|
|
assert stats["enabled"] is True
|
|
assert stats["patterns_tracked"] >= 1
|
|
assert stats["total_compressions"] == 10
|
|
assert stats["total_retrievals"] == 3
|
|
assert 0 <= stats["global_retrieval_rate"] <= 1
|
|
|
|
# Get pattern details
|
|
pattern = toin.get_pattern(sample_tool_signature.structure_hash)
|
|
print("\n--- Pattern Details ---")
|
|
print(f" tool_signature_hash: {pattern.tool_signature_hash}")
|
|
print(f" total_compressions: {pattern.total_compressions}")
|
|
print(f" total_items_seen: {pattern.total_items_seen}")
|
|
print(f" total_items_kept: {pattern.total_items_kept}")
|
|
print(f" avg_compression_ratio: {pattern.avg_compression_ratio:.3f}")
|
|
print(f" avg_token_reduction: {pattern.avg_token_reduction:.3f}")
|
|
print(f" total_retrievals: {pattern.total_retrievals}")
|
|
print(f" full_retrievals: {pattern.full_retrievals}")
|
|
print(f" search_retrievals: {pattern.search_retrievals}")
|
|
print(f" retrieval_rate: {pattern.retrieval_rate:.1%}")
|
|
print(f" sample_size: {pattern.sample_size}")
|
|
print(f" confidence: {pattern.confidence:.3f}")
|
|
print(f" optimal_strategy: {pattern.optimal_strategy}")
|
|
print(f" strategy_success_rates: {pattern.strategy_success_rates}")
|
|
|
|
# Export and print
|
|
print("\n--- Export Data (truncated) ---")
|
|
export = toin.export_patterns()
|
|
print(f" version: {export.get('version')}")
|
|
print(f" patterns count: {len(export.get('patterns', {}))}")
|
|
|
|
print("\n[PASS] TOIN stats output is complete and correct")
|
|
|
|
|
|
class TestTOINGlobalSingleton:
|
|
"""Test the global TOIN singleton behavior."""
|
|
|
|
def test_get_toin_singleton(self):
|
|
"""Verify get_toin returns the same instance."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_get_toin_singleton")
|
|
print("=" * 60)
|
|
|
|
# Get TOIN twice
|
|
toin1 = get_toin()
|
|
toin2 = get_toin()
|
|
|
|
print(f"toin1 id: {id(toin1)}")
|
|
print(f"toin2 id: {id(toin2)}")
|
|
|
|
assert toin1 is toin2, "get_toin should return the same instance"
|
|
print("\n[PASS] get_toin returns singleton")
|
|
|
|
def test_reset_toin_creates_new_instance(self):
|
|
"""Verify reset_toin creates a new instance."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_reset_toin_creates_new_instance")
|
|
print("=" * 60)
|
|
|
|
toin1 = get_toin()
|
|
print(f"Before reset - toin id: {id(toin1)}")
|
|
|
|
reset_toin()
|
|
toin2 = get_toin()
|
|
print(f"After reset - toin id: {id(toin2)}")
|
|
|
|
assert toin1 is not toin2, "reset_toin should create new instance"
|
|
print("\n[PASS] reset_toin creates new instance")
|
|
|
|
|
|
class TestTOINFieldLearning:
|
|
"""Test TOIN field-level semantic learning."""
|
|
|
|
def test_field_retrieval_tracking(self, fresh_toin, sample_tool_signature):
|
|
"""Verify TOIN tracks which fields are frequently retrieved."""
|
|
print("\n" + "=" * 60)
|
|
print("TEST: test_field_retrieval_tracking")
|
|
print("=" * 60)
|
|
|
|
# Record compressions first
|
|
for _i in range(5):
|
|
fresh_toin.record_compression(
|
|
tool_signature=sample_tool_signature,
|
|
original_count=100,
|
|
compressed_count=15,
|
|
original_tokens=5000,
|
|
compressed_tokens=750,
|
|
strategy="smart_sample",
|
|
)
|
|
|
|
# Record retrievals with specific field queries
|
|
print("\n--- Recording retrievals with field queries ---")
|
|
for i in range(5):
|
|
fresh_toin.record_retrieval(
|
|
tool_signature_hash=sample_tool_signature.structure_hash,
|
|
retrieval_type="search",
|
|
query=f"status:error_{i}",
|
|
query_fields=["status", "error_code"],
|
|
strategy="smart_sample",
|
|
)
|
|
print(f" Recorded retrieval {i + 1} querying 'status' and 'error_code'")
|
|
|
|
# Check pattern
|
|
pattern = fresh_toin.get_pattern(sample_tool_signature.structure_hash)
|
|
print("\n--- Field Retrieval Frequency ---")
|
|
for field_hash, count in pattern.field_retrieval_frequency.items():
|
|
print(f" {field_hash}: {count} retrievals")
|
|
|
|
print(f"\nCommonly retrieved fields: {pattern.commonly_retrieved_fields}")
|
|
|
|
# Verify field frequencies were recorded
|
|
assert len(pattern.field_retrieval_frequency) > 0, "Should track field retrieval frequency"
|
|
|
|
print("\n[PASS] Field retrieval tracking works")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v", "-s"])
|