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
108 lines
3.0 KiB
Python
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
|