Changeset 0.17.1 (#76)

This commit is contained in:
2026-02-28 01:40:31 +00:00
parent c9141a6896
commit 856dc9b0ac
64 changed files with 8037 additions and 1657 deletions

View File

@@ -11,38 +11,48 @@ import (
"git.gobha.me/xcaliber/chat-switchboard/database"
"git.gobha.me/xcaliber/chat-switchboard/models"
"git.gobha.me/xcaliber/chat-switchboard/roles"
"git.gobha.me/xcaliber/chat-switchboard/store"
postgres "git.gobha.me/xcaliber/chat-switchboard/store/postgres"
sqlite "git.gobha.me/xcaliber/chat-switchboard/store/sqlite"
"git.gobha.me/xcaliber/chat-switchboard/treepath"
)
// ═══════════════════════════════════════════
// Live Compaction Tests
// ═══════════════════════════════════════════
// Requires: TEST_DATABASE_URL + VENICE_API_KEY
// Requires: TEST_DATABASE_URL + PROVIDER_KEY (or VENICE_API_KEY)
//
// Tests the full Compact() pipeline end-to-end:
// seed messages → call utility model → verify summary tree node
// ═══════════════════════════════════════════
// dialectStores returns the correct store bundle for the active dialect.
func dialectStores() store.Stores {
if database.IsSQLite() {
return sqlite.NewStores(database.TestDB)
}
return postgres.NewStores(database.TestDB)
}
func TestLive_CompactionFullPipeline(t *testing.T) {
h := setupHarness(t)
veniceKey := requireVeniceKey(t)
pc := requireLiveProvider(t)
userID, adminToken := h.createAdminUser("compactadmin", "compact@test.com")
// Set up Venice provider + enable qwen3-4b
configID, _ := setupVeniceWithModel(t, h, adminToken, veniceKey, veniceTestModel)
// Set up provider + enable first model
configID, modelID := setupProviderWithModel(t, h, adminToken, pc)
// Configure utility role → qwen3-4b
// Configure utility role
w := h.request("PUT", "/api/v1/admin/roles/utility", adminToken, map[string]interface{}{
"primary": map[string]interface{}{
"provider_config_id": configID,
"model_id": veniceTestModel,
"model_id": modelID,
},
})
if w.Code != http.StatusOK {
t.Fatalf("configure utility role: %d: %s", w.Code, w.Body.String())
}
t.Log(" ✓ Utility role configured with", veniceTestModel)
t.Log(" ✓ Utility role configured with", modelID)
// Create a channel with enough messages to summarize
w = h.request("POST", "/api/v1/channels", adminToken, map[string]interface{}{
@@ -69,33 +79,30 @@ func TestLive_CompactionFullPipeline(t *testing.T) {
{"assistant", "Early morning is best for temples. Fushimi Inari at sunrise (5-6am) is magical and nearly empty. Kinkaku-ji opens at 9am — arrive right at opening. Arashiyama bamboo grove is best before 8am. For Senso-ji in Tokyo, go at dawn for beautiful photos. Weekdays are always less crowded than weekends."},
}
ph := database.PH
var lastMsgID string
for _, m := range msgs {
var parentPtr *string
if lastMsgID != "" {
parentPtr = &lastMsgID
}
err := database.TestDB.QueryRow(`
INSERT INTO messages (channel_id, parent_id, role, content, sibling_index)
VALUES ($1, $2, $3, $4, 0)
RETURNING id
`, channelID, parentPtr, m.role, m.content).Scan(&lastMsgID)
err := database.TestDB.QueryRow(
"INSERT INTO messages (channel_id, parent_id, role, content, sibling_index) VALUES ("+ph(1)+", "+ph(2)+", "+ph(3)+", "+ph(4)+", 0) RETURNING id",
channelID, parentPtr, m.role, m.content).Scan(&lastMsgID)
if err != nil {
t.Fatalf("seed message: %v", err)
}
}
// Set cursor to last message
database.TestDB.Exec(`
INSERT INTO channel_cursors (channel_id, user_id, active_leaf_id)
VALUES ($1, $2, $3)
ON CONFLICT (channel_id, user_id) DO UPDATE SET active_leaf_id = $3
`, channelID, userID, lastMsgID)
database.TestDB.Exec(
"INSERT INTO channel_cursors (channel_id, user_id, active_leaf_id) VALUES ("+ph(1)+", "+ph(2)+", "+ph(3)+") ON CONFLICT (channel_id, user_id) DO UPDATE SET active_leaf_id = excluded.active_leaf_id",
channelID, userID, lastMsgID)
t.Logf(" ✓ Seeded %d messages in channel %s", len(msgs), channelID)
// ── Run compaction ──
stores := postgres.NewStores(database.TestDB)
stores := dialectStores()
resolver := roles.NewResolver(stores, nil)
svc := compaction.NewService(stores, resolver)
@@ -119,16 +126,16 @@ func TestLive_CompactionFullPipeline(t *testing.T) {
if result.Content == "" {
t.Fatal("summary content should not be empty")
}
if result.Model != veniceTestModel {
t.Errorf("model = %q, want %q", result.Model, veniceTestModel)
if result.Model != modelID {
t.Errorf("model = %q, want %q", result.Model, modelID)
}
// Verify summary message exists in the tree
var summaryContent, summaryRole string
var metadataRaw []byte
err = database.TestDB.QueryRow(`
SELECT role, content, metadata FROM messages WHERE id = $1
`, result.SummaryID).Scan(&summaryRole, &summaryContent, &metadataRaw)
err = database.TestDB.QueryRow(
"SELECT role, content, metadata FROM messages WHERE id = "+ph(1),
result.SummaryID).Scan(&summaryRole, &summaryContent, &metadataRaw)
if err != nil {
t.Fatalf("query summary message: %v", err)
}
@@ -152,7 +159,6 @@ func TestLive_CompactionFullPipeline(t *testing.T) {
t.Fatalf("GetActivePath after compaction: %v", err)
}
// The last message in the path should be the summary
if len(path) == 0 {
t.Fatal("path should not be empty after compaction")
}
@@ -164,9 +170,9 @@ func TestLive_CompactionFullPipeline(t *testing.T) {
// Verify usage was logged
var usageCount int
database.TestDB.QueryRow(`
SELECT COUNT(*) FROM usage_log WHERE channel_id = $1 AND role = 'utility'
`, channelID).Scan(&usageCount)
database.TestDB.QueryRow(
"SELECT COUNT(*) FROM usage_log WHERE channel_id = "+ph(1)+" AND role = 'utility'",
channelID).Scan(&usageCount)
if usageCount == 0 {
t.Error("expected usage_log entry for utility role")
}
@@ -177,24 +183,31 @@ func TestLive_CompactionFullPipeline(t *testing.T) {
// rejects input that exceeds the utility model's context window.
func TestLive_CompactionContextBudgetGuardRail(t *testing.T) {
h := setupHarness(t)
veniceKey := requireVeniceKey(t)
pc := requireLiveProvider(t)
_, adminToken := h.createAdminUser("guardrail_admin", "guardrail@test.com")
userID := database.SeedTestUser(t, "guardrail_user", "gruser@test.com")
// Set up Venice + qwen3-4b (32K context)
configID, catalogEntryID := setupVeniceWithModel(t, h, adminToken, veniceKey, veniceTestModel)
// Set up provider + enable first model
configID, modelID := setupProviderWithModel(t, h, adminToken, pc)
ph := database.PH
// Set max_context to 32000 in catalog (in case sync didn't populate it)
database.TestDB.Exec(`
UPDATE model_catalog SET capabilities = capabilities || '{"max_context": 32000}'::jsonb
WHERE id = $1
`, catalogEntryID)
if database.IsSQLite() {
database.TestDB.Exec(
"UPDATE model_catalog SET capabilities = json_set(COALESCE(capabilities,'{}'), '$.max_context', 32000) WHERE provider_config_id = "+ph(1)+" AND model_id = "+ph(2),
configID, modelID)
} else {
database.TestDB.Exec(
"UPDATE model_catalog SET capabilities = capabilities || '{\"max_context\": 32000}'::jsonb WHERE provider_config_id = "+ph(1)+" AND model_id = "+ph(2),
configID, modelID)
}
// Configure utility role
h.request("PUT", "/api/v1/admin/roles/utility", adminToken, map[string]interface{}{
"primary": map[string]interface{}{
"provider_config_id": configID,
"model_id": veniceTestModel,
"model_id": modelID,
},
})
@@ -207,7 +220,6 @@ func TestLive_CompactionContextBudgetGuardRail(t *testing.T) {
channelID := ch["id"].(string)
// Seed 20 messages × 8000 chars each = 160K chars ≈ 40K tokens
// This exceeds 32K × 0.80 = 25.6K token ceiling
bigContent := make([]byte, 8000)
for i := range bigContent {
bigContent[i] = 'a'
@@ -222,19 +234,16 @@ func TestLive_CompactionContextBudgetGuardRail(t *testing.T) {
if i%2 == 1 {
role = "assistant"
}
database.TestDB.QueryRow(`
INSERT INTO messages (channel_id, parent_id, role, content, sibling_index)
VALUES ($1, $2, $3, $4, 0) RETURNING id
`, channelID, parentPtr, role, string(bigContent)).Scan(&lastMsgID)
database.TestDB.QueryRow(
"INSERT INTO messages (channel_id, parent_id, role, content, sibling_index) VALUES ("+ph(1)+", "+ph(2)+", "+ph(3)+", "+ph(4)+", 0) RETURNING id",
channelID, parentPtr, role, string(bigContent)).Scan(&lastMsgID)
}
database.TestDB.Exec(`
INSERT INTO channel_cursors (channel_id, user_id, active_leaf_id)
VALUES ($1, $2, $3)
ON CONFLICT (channel_id, user_id) DO UPDATE SET active_leaf_id = $3
`, channelID, userID, lastMsgID)
database.TestDB.Exec(
"INSERT INTO channel_cursors (channel_id, user_id, active_leaf_id) VALUES ("+ph(1)+", "+ph(2)+", "+ph(3)+") ON CONFLICT (channel_id, user_id) DO UPDATE SET active_leaf_id = excluded.active_leaf_id",
channelID, userID, lastMsgID)
// Run compaction — should fail with context budget error
stores := postgres.NewStores(database.TestDB)
stores := dialectStores()
resolver := roles.NewResolver(stores, nil)
svc := compaction.NewService(stores, resolver)
@@ -250,7 +259,6 @@ func TestLive_CompactionContextBudgetGuardRail(t *testing.T) {
t.Logf(" ✓ Guard rail triggered: %v", err)
// Verify it's specifically a context budget error
if !strings.Contains(err.Error(), "context window") {
t.Errorf("expected context window error, got: %v", err)
}