Mercury Genesys Token Calculator

This commit is contained in:
2026-08-07 14:49:39 -04:00
parent 22a5d907d6
commit 89b835d681
35 changed files with 14105 additions and 2912 deletions

View File

@@ -0,0 +1,263 @@
"""End-to-end pricing, hand-checked.
The reference scenario below is the one the notebook ships as its default.
Every figure was computed by hand from the published rates before it was
pinned here.
"""
from __future__ import annotations
import json
import pytest
from genesyscalc.appendix import result_json
from genesyscalc.meters import LicenceModel, TokenPrice
from genesyscalc.model import (
CalculatorInputs,
calculate,
compare,
cost_per_interaction,
metered_units,
)
from genesyscalc.ratecard import RATE_CARD_SOURCE_DATE
from genesyscalc.tts import TtsUsage
from genesyscalc.usage import DeflectionMix, VoiceBotUsage, Volumes
REFERENCE_ENABLED = frozenset(
{
"agent_copilot_named",
"speech_and_text_analytics_named",
"bots_voice",
"virtual_agent",
"agentic_virtual_agent",
"ai_summary_and_insights",
"ai_scoring",
"whatsapp_messaging",
"predictive_engagement",
}
)
@pytest.fixture
def volumes() -> Volumes:
return Volumes(
voice_inbound_monthly=100_000,
voice_outbound_monthly=20_000,
digital_sessions_monthly=8_000,
email_monthly=12_000,
messaging_monthly=6_000,
evaluations_monthly=2_000,
)
@pytest.fixture
def reference(volumes: Volumes) -> CalculatorInputs:
return CalculatorInputs(
volumes=volumes,
users=500,
licence=LicenceModel.NAMED,
enabled=REFERENCE_ENABLED,
mix=DeflectionMix(
bot_only_share=0.30, virtual_agent_share=0.15, agentic_va_share=0.05
),
price=TokenPrice(),
voice_bot=VoiceBotUsage(
calls_per_month=30_000, avg_bot_seconds_per_call=40
),
tts=TtsUsage(calls_monthly=100_000, chars_per_call=2_000),
)
# ── the hand-checked reference scenario ──────────────────────────────────
def test_subscription_lines(reference: CalculatorInputs) -> None:
"""500 users: Copilot 500×40 = 20,000; STA 500×30 = 15,000 tokens/mo."""
by_key = {line.key: line for line in calculate(reference).lines}
assert by_key["agent_copilot_named"].tokens_monthly == pytest.approx(20_000.0)
assert by_key["speech_and_text_analytics_named"].tokens_monthly == pytest.approx(
15_000.0
)
assert by_key["agent_copilot_named"].cost_annual == pytest.approx(240_000.0)
def test_voice_bot_line(reference: CalculatorInputs) -> None:
"""30,000 calls × ceil(40/15)×15s = 45s = 0.75 min → 22,500 min.
22,500 / 17 = 1,323.53 tokens/mo → $15,882.35/yr at $1.00."""
by_key = {line.key: line for line in calculate(reference).lines}
assert by_key["bots_voice"].units_monthly == pytest.approx(22_500.0)
assert by_key["bots_voice"].tokens_monthly == pytest.approx(1_323.529412, rel=1e-6)
assert by_key["bots_voice"].cost_annual == pytest.approx(15_882.35, abs=0.01)
def test_virtual_agent_lines_use_the_partition(reference: CalculatorInputs) -> None:
"""120,000 voice: VA 15% = 18,000 × 0.5 = 9,000 tokens;
AVA 5% = 6,000 × 1.2 = 7,200 tokens."""
by_key = {line.key: line for line in calculate(reference).lines}
assert by_key["virtual_agent"].units_monthly == pytest.approx(18_000.0)
assert by_key["virtual_agent"].tokens_monthly == pytest.approx(9_000.0)
assert by_key["agentic_virtual_agent"].units_monthly == pytest.approx(6_000.0)
assert by_key["agentic_virtual_agent"].tokens_monthly == pytest.approx(7_200.0)
def test_summary_is_zeroed_because_copilot_is_on(reference: CalculatorInputs) -> None:
result = calculate(reference)
by_key = {line.key: line for line in result.lines}
assert by_key["ai_summary_and_insights"].units_monthly == 0.0
assert by_key["ai_summary_and_insights"].cost_annual == 0.0
assert any("Agent Copilot is enabled" in w for w in result.warnings)
def test_zero_rated_line_is_shown_not_hidden(reference: CalculatorInputs) -> None:
"""A published $0 is a finding — it renders as a line, at zero."""
by_key = {line.key: line for line in calculate(reference).lines}
assert "predictive_engagement" in by_key
assert by_key["predictive_engagement"].units_monthly > 0
assert by_key["predictive_engagement"].cost_annual == 0.0
def test_reference_totals(reference: CalculatorInputs) -> None:
"""consumption 17,638.53 → ceil 17,639; + 35,000 subscription = 52,639;
250 allowance = 52,389 billable → $52,389/mo → $628,668/yr.
TTS 200M chars, 20% VA-free → 160M → $3,200/mo → $38,400/yr.
Grand total $667,068/yr."""
totals = calculate(reference).totals
assert totals.consumption_tokens_monthly == pytest.approx(17_638.529412, rel=1e-6)
assert totals.subscription_tokens_monthly == pytest.approx(35_000.0)
assert totals.gross_tokens_monthly == pytest.approx(52_639.0)
assert totals.allowance_tokens_monthly == 250
assert totals.billable_tokens_monthly == 52_389
assert totals.token_cost_annual == pytest.approx(628_668.0)
def test_reference_grand_total_splits_tokens_from_tts(
reference: CalculatorInputs,
) -> None:
result = calculate(reference)
assert result.tts_cost_annual == pytest.approx(38_400.0)
assert result.grand_total_annual == pytest.approx(667_068.0)
assert result.grand_total_annual == pytest.approx(
result.token_cost_annual + result.tts_cost_annual
)
def test_cost_per_interaction(reference: CalculatorInputs) -> None:
"""$667,068 / (146,000 × 12) = $0.3807 per interaction."""
result = calculate(reference)
assert cost_per_interaction(result, reference.volumes) == pytest.approx(
0.380747, rel=1e-5
)
def test_roundup_warning_is_reported(reference: CalculatorInputs) -> None:
assert any("15-second per-call round-up" in w for w in calculate(reference).warnings)
# ── structural ties that must hold at any setting ────────────────────────
def test_lines_sum_to_the_gross_token_count(reference: CalculatorInputs) -> None:
result = calculate(reference)
assert sum(line.tokens_monthly for line in result.lines) == pytest.approx(
result.totals.consumption_tokens_monthly
+ result.totals.subscription_tokens_monthly
)
def test_effective_cost_never_exceeds_list(reference: CalculatorInputs) -> None:
discounted = reference.with_(price=TokenPrice(concession_pct=0.4))
result = calculate(discounted)
assert result.totals.token_cost_annual <= result.totals.list_cost_annual
assert result.totals.concession_saving_annual >= 0
def test_allowance_only_ever_reduces_the_bill(reference: CalculatorInputs) -> None:
with_allowance = calculate(reference).totals.billable_tokens_monthly
without = calculate(
reference.with_(apply_allowance=False)
).totals.billable_tokens_monthly
assert with_allowance == without - 250
def test_allowance_absorbing_a_month_is_reported() -> None:
quiet = CalculatorInputs(
volumes=Volumes(voice_inbound_monthly=100),
users=0,
enabled=frozenset({"ai_scoring"}),
)
result = calculate(quiet)
assert result.totals.billable_tokens_monthly == 0
assert any("free monthly allowance" in w for w in result.warnings)
def test_unknown_feature_key_rejected(volumes: Volumes) -> None:
with pytest.raises(ValueError, match="not published meters"):
CalculatorInputs(volumes=volumes, users=1, enabled=frozenset({"telepathy"}))
def test_metered_units_covers_every_enabled_key(reference: CalculatorInputs) -> None:
assert set(metered_units(reference)) == set(reference.enabled)
def test_empty_scenario_costs_nothing() -> None:
result = calculate(CalculatorInputs(volumes=Volumes(), users=0))
assert result.grand_total_annual == 0.0
assert result.lines == ()
# ── licence model, scenarios ─────────────────────────────────────────────
def test_concurrent_licence_costs_more_per_user(reference: CalculatorInputs) -> None:
"""Copilot 40→60 and STA 30→45, so 35,000 → 52,500 subscription tokens."""
concurrent = reference.with_(
licence=LicenceModel.CONCURRENT,
enabled=frozenset(
{"agent_copilot_named", "speech_and_text_analytics_named"}
),
)
named = reference.with_(
enabled=frozenset({"agent_copilot_named", "speech_and_text_analytics_named"})
)
assert calculate(named).totals.subscription_tokens_monthly == pytest.approx(35_000.0)
assert calculate(concurrent).totals.subscription_tokens_monthly == pytest.approx(
52_500.0
)
def test_compare_is_monotone_in_deflection(reference: CalculatorInputs) -> None:
"""More virtual-agent deflection means more consumption tokens."""
rows = compare(
{
"Conservative": reference.with_(
mix=DeflectionMix(bot_only_share=0.20, virtual_agent_share=0.05)
),
"Base": reference,
"Aggressive": reference.with_(
mix=DeflectionMix(
bot_only_share=0.35,
virtual_agent_share=0.25,
agentic_va_share=0.10,
)
),
}
)
assert [r["Scenario"] for r in rows] == ["Conservative", "Base", "Aggressive"]
totals = [r["Token cost / yr"] for r in rows]
assert totals[0] < totals[1] < totals[2]
# ── the export payload ───────────────────────────────────────────────────
def test_result_json_round_trips_and_carries_provenance(
reference: CalculatorInputs,
) -> None:
payload = result_json(calculate(reference), reference, meta={"client": "Example"})
assert json.loads(json.dumps(payload)) == payload
assert payload["rate_card"]["source_date"] == RATE_CARD_SOURCE_DATE
assert payload["rate_card"]["voice_bot_roundup_seconds"] == 15
assert payload["tts_source"]["source_date"] == "2026-05-22"
assert payload["totals"]["grand_total_annual"] == pytest.approx(667_068.0)
assert payload["meta"]["client"] == "Example"
assert len(payload["lines"]) == len(REFERENCE_ENABLED)