AkurAI Build
Menu

popagent

public

Latest change 6edc7e928c57dab23c0973ed3f7ee70b3ebb72d5 - Initial popagent baseline by AkurAI Build

import { beforeAll, describe, expect, test } from "bun:test";
import { storage } from "./storage";

type SettingsMigration = {
  file: string;
  table: string;
  valueColumns: string[];
};

const migrations: SettingsMigration[] = [
  {
    file: "channel-settings.sql",
    table: "popagent_channel_settings",
    valueColumns: ["enabled", "dispatch_mode", "context_messages", "streaming", "tool_display"],
  },
  {
    file: "browser-settings.sql",
    table: "popagent_browser_settings",
    valueColumns: [
      "enabled", "scope", "viewport_width", "viewport_height", "timeout_ms",
      "max_sessions", "idle_timeout_ms", "screencast_enabled", "screenshots_enabled",
      "multi_tab_enabled", "forms_enabled", "dialogs_enabled", "drag_enabled",
      "evaluate_enabled", "recording_enabled", "recording_retention_days",
      "recording_max_files", "allow_hosts", "deny_hosts",
    ],
  },
  {
    file: "memory-settings.sql",
    table: "popagent_memory_settings",
    valueColumns: [
      "auto_compact",
      "observation_tokens",
      "reflection_tokens",
      "recent_message_percent",
      "buffer_on_idle",
    ],
  },
  {
    file: "agent-runtime-settings.sql",
    table: "popagent_agent_runtime_settings",
    valueColumns: [
      "default_model",
      "supervisor_max_steps",
      "specialist_max_steps",
      "tool_concurrency",
      "delegation_context_messages",
      "delegation_result_characters",
      "max_processor_retries",
      "final_response_feedback",
      "delegation_failure_feedback",
      "delegation_result_truncation_marker",
      "task_concurrency",
      "task_poll_interval_ms",
      "task_timeout_ms",
      "task_stale_after_ms",
    ],
  },
];

beforeAll(() => storage.init());

describe("settings migrations", () => {
  for (const migration of migrations) {
    test(`${migration.file} seeds configuration only once`, async () => {
      const schemaName = `settings_migration_${crypto.randomUUID().replaceAll("-", "")}`;
      const quotedSchema = `"${schemaName}"`;
      const sql = await Bun.file(new URL(`./${migration.file}`, import.meta.url)).text();

      await storage.db.tx(async (transaction) => {
        await transaction.none(`CREATE SCHEMA ${quotedSchema}`);
        try {
          await transaction.none(`SET LOCAL search_path TO ${quotedSchema}`);
          await transaction.none(sql);
          expect(await transaction.one<{ count: number }>(
            `SELECT COUNT(*)::int AS count FROM ${migration.table}`,
          )).toEqual({ count: 1 });

          const columns = await transaction.any<{ columnName: string; defaultValue: string | null }>(`
            SELECT column_name AS "columnName", column_default AS "defaultValue"
            FROM information_schema.columns
            WHERE table_schema = $1 AND table_name = $2
          `, [schemaName, migration.table]);
          expect(columns.filter((column) => migration.valueColumns.includes(column.columnName)))
            .toEqual(migration.valueColumns.map((columnName) => ({ columnName, defaultValue: null })));

          await transaction.none(`DELETE FROM ${migration.table}`);
          await transaction.none(sql);
          expect(await transaction.one<{ count: number }>(
            `SELECT COUNT(*)::int AS count FROM ${migration.table}`,
          )).toEqual({ count: 0 });
        } finally {
          await transaction.none(`DROP SCHEMA ${quotedSchema} CASCADE`);
        }
      });
    });
  }
});