Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

108 lines
3.0 KiB
Python

"""Tests for perfxpert.conversation."""
import pytest
from perfxpert.conversation import Conversation
def test_add_user_and_assistant():
c = Conversation()
c.add_user("hi")
c.add_assistant("hello")
msgs = c.messages
assert len(msgs) == 2
assert msgs[0] == {"role": "user", "content": "hi"}
assert msgs[1] == {"role": "assistant", "content": "hello"}
def test_messages_returns_copy():
c = Conversation()
c.add_user("hi")
m = c.messages
m.append({"role": "user", "content": "mutate"})
assert len(c.messages) == 1 # unaffected
def test_turn_count():
c = Conversation()
assert c.turn_count == 0
c.add_user("a")
c.add_assistant("b")
assert c.turn_count == 1
c.add_user("c")
c.add_assistant("d")
assert c.turn_count == 2
def test_api_key_never_serialized():
c = Conversation(api_key="sk-secret")
c.add_user("hi")
c.add_assistant("ok")
payload = c.to_dict()
assert "api_key" not in payload
assert "sk-secret" not in repr(payload)
def test_round_trip_preserves_messages():
c = Conversation(api_key="sk-a")
c.add_user("ping")
c.add_assistant("pong")
payload = c.to_dict()
restored = Conversation.from_dict(payload, api_key="sk-b")
assert restored.messages == c.messages
assert restored.turn_count == c.turn_count
def test_compaction_triggers_at_threshold():
c = Conversation(compaction_every_n_turns=3, compaction_keep_recent_turns=1)
for i in range(5):
c.add_user(f"u{i}")
c.add_assistant(f"a{i}")
msgs = c.messages
# After compaction: summary message + 1 recent turn (2 messages) = 3 total
assert any(m.get("role") == "system" and "summary" in m.get("content", "").lower() for m in msgs)
assert len(msgs) < 10
def test_no_compaction_below_threshold():
c = Conversation(compaction_every_n_turns=100)
for i in range(3):
c.add_user(f"u{i}")
c.add_assistant(f"a{i}")
assert len(c.messages) == 6 # untouched
def test_dry_run_cost_estimate_zero_tokens():
c = Conversation()
est = c.dry_run_cost_estimate(
model="claude-3-5-sonnet-20241022",
input_price_per_mtok=3.0,
output_price_per_mtok=15.0,
avg_output_tokens=500,
)
assert est["estimated_input_tokens"] == 0
assert est["estimated_cost_usd"] >= 0.0
def test_dry_run_cost_with_messages():
c = Conversation()
c.add_user("x" * 400)
c.add_assistant("y" * 400)
est = c.dry_run_cost_estimate(
model="claude-3-5-sonnet-20241022",
input_price_per_mtok=3.0,
output_price_per_mtok=15.0,
avg_output_tokens=500,
)
# ~200 input tokens (800 chars / 4), 500 output tokens
assert est["estimated_input_tokens"] > 0
assert est["estimated_output_tokens"] == 500
assert est["estimated_cost_usd"] > 0
def test_empty_conversation_to_dict():
c = Conversation()
payload = c.to_dict()
assert payload["messages"] == []
assert payload["turn_count"] == 0