60 lines
2.9 KiB
TypeScript
60 lines
2.9 KiB
TypeScript
// The module's migrations are its own files, each exactly `schemaStatements()` over the entities it
|
|
// added (decision AT-D20: the entity definition is the one source of a column). Forward-only: the
|
|
// first file stays the run and step tables as first shipped; the second adds the step's recorded
|
|
// tool result and the run's conversation table (`agent_thread`, TanStack AI's message store); the
|
|
// third adds the run answer's provenance (EU AI Act Art. 50(2)).
|
|
|
|
import { readFileSync } from "node:fs"
|
|
import { AGENT_ENTITIES, agentRuns, agentSteps, agentThreads } from "@conusai-kit/agent"
|
|
import { schemaStatements } from "@conusai-kit/data-kysely"
|
|
import { describe, expect, it } from "vitest"
|
|
import { agentModule } from "../index.js"
|
|
|
|
function tablesOf(entities: Parameters<typeof schemaStatements>[0]): string {
|
|
const kernel = schemaStatements([]).length
|
|
return `${schemaStatements(entities)
|
|
.slice(kernel)
|
|
.map((statement) => `${statement};`)
|
|
.join("\n\n")}\n`
|
|
}
|
|
|
|
const migration = (name: string) => readFileSync(new URL(`../migrations/${name}`, import.meta.url), "utf8")
|
|
const HEADER = "-- SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0\n"
|
|
|
|
describe("the migrations of the agent module", () => {
|
|
it("are the run and step tables as first shipped, then the step's result column", () => {
|
|
const added = ',\n "result" jsonb\n'
|
|
const provenance = ',\n "answer_provenance" jsonb\n'
|
|
const generated = tablesOf([agentRuns, agentSteps])
|
|
expect(generated).toContain(added)
|
|
expect(generated).toContain(provenance)
|
|
expect(`${HEADER}${generated.replace(added, "\n").replace(provenance, "\n")}`).toBe(migration("0001_agent.sql"))
|
|
expect(migration("0002_agent_thread.sql")).toContain(
|
|
`${HEADER}alter table "agent_step" add column "result" jsonb;\n\n`,
|
|
)
|
|
})
|
|
|
|
it("add the run's conversation table in the second file, exactly its table", async () => {
|
|
await expect(
|
|
`${HEADER}alter table "agent_step" add column "result" jsonb;\n\n${tablesOf([agentThreads])}`,
|
|
).toMatchFileSnapshot("../migrations/0002_agent_thread.sql")
|
|
expect(AGENT_ENTITIES).toEqual([agentRuns, agentSteps, agentThreads])
|
|
})
|
|
|
|
it("add the run answer's provenance column in the third file, exactly that column", () => {
|
|
expect(tablesOf([agentRuns])).toContain(',\n "answer_provenance" jsonb\n')
|
|
expect(migration("0003_agent_answer_provenance.sql")).toBe(
|
|
`${HEADER}alter table "agent_run" add column "answer_provenance" jsonb;\n`,
|
|
)
|
|
})
|
|
|
|
it("are declared by the manifest, and every table is row-level secured", () => {
|
|
expect(agentModule.migrations).toEqual({ postgres: "migrations" })
|
|
const sql = migration("0001_agent.sql") + migration("0002_agent_thread.sql")
|
|
for (const table of ["agent_run", "agent_step", "agent_thread"]) {
|
|
expect(sql).toContain(`create table "${table}"`)
|
|
expect(sql).toContain(`alter table "${table}" force row level security`)
|
|
}
|
|
})
|
|
})
|