@app-vitals/agent-admin 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@app-vitals/agent-admin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/app-vitals/agent.git",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@anthropic-ai/sdk": "0.135.0",
|
|
46
|
-
"@app-vitals/agent-lib": "0.
|
|
46
|
+
"@app-vitals/agent-lib": "0.13.0",
|
|
47
47
|
"@hono/zod-openapi": "^1.0.0",
|
|
48
48
|
"@prisma/adapter-pg": "^7.10.0",
|
|
49
49
|
"@prisma/client": "^7.10.0",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent/src/agent-specialty-backfill.integration.test.ts
|
|
3
|
+
* Migration test for the AGR-6.1 Agent.specialty backfill
|
|
4
|
+
* (20261029000000_add_agent_specialty: UPDATE "Agent" SET specialty = typeName).
|
|
5
|
+
*
|
|
6
|
+
* Seeded from the live distinct typeName values (admin API, 2026-10-27):
|
|
7
|
+
* coding (11 agents) and specialist (1 agent). Must stay green until AGR-6.3
|
|
8
|
+
* removes typeName.
|
|
9
|
+
*
|
|
10
|
+
* Requires DATABASE_URL_ADMIN_TEST; skips otherwise.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
14
|
+
import { readFileSync } from "node:fs";
|
|
15
|
+
import type { PrismaClient } from "../prisma/client/client.ts";
|
|
16
|
+
import { createAdminPrismaClient } from "./prisma-client.ts";
|
|
17
|
+
|
|
18
|
+
const TEST_DB = process.env.DATABASE_URL_ADMIN_TEST;
|
|
19
|
+
const describeOrSkip = TEST_DB ? describe : describe.skip;
|
|
20
|
+
|
|
21
|
+
const LIVE_TYPE_NAMES = ["coding", "specialist"] as const;
|
|
22
|
+
|
|
23
|
+
const BACKFILL_SQL = readFileSync(
|
|
24
|
+
new URL(
|
|
25
|
+
"../prisma/migrations/20261029000000_add_agent_specialty/migration.sql",
|
|
26
|
+
import.meta.url,
|
|
27
|
+
),
|
|
28
|
+
"utf8",
|
|
29
|
+
)
|
|
30
|
+
.split("\n")
|
|
31
|
+
.filter((l) => !l.trimStart().startsWith("--"))
|
|
32
|
+
.join("\n")
|
|
33
|
+
.split(";")
|
|
34
|
+
.map((s) => s.trim())
|
|
35
|
+
.find((s) => s.startsWith("UPDATE")) as string;
|
|
36
|
+
|
|
37
|
+
describeOrSkip("Agent.specialty backfill (AGR-6.1 migration)", () => {
|
|
38
|
+
let prisma: PrismaClient;
|
|
39
|
+
|
|
40
|
+
beforeEach(async () => {
|
|
41
|
+
prisma = createAdminPrismaClient(TEST_DB as string);
|
|
42
|
+
await prisma.agent.deleteMany({
|
|
43
|
+
where: { name: { startsWith: "agr62a-" } },
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
afterEach(async () => {
|
|
48
|
+
await prisma.agent.deleteMany({
|
|
49
|
+
where: { name: { startsWith: "agr62a-" } },
|
|
50
|
+
});
|
|
51
|
+
await prisma.$disconnect();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("extracts the UPDATE statement from the migration", () => {
|
|
55
|
+
expect(BACKFILL_SQL).toContain('SET "specialty" = "typeName"');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("sets specialty == typeName for every live typeName, leaving no NULLs", async () => {
|
|
59
|
+
// Pre-migration state: rows exist with typeName only (specialty NULL).
|
|
60
|
+
for (const [i, typeName] of LIVE_TYPE_NAMES.entries()) {
|
|
61
|
+
await prisma.agent.create({
|
|
62
|
+
data: { name: `agr62a-${i}-${typeName}`, typeName, specialty: null },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Scope the migration's UPDATE to the seeded rows so unrelated rows in a
|
|
67
|
+
// shared test DB are untouched.
|
|
68
|
+
await prisma.$executeRawUnsafe(
|
|
69
|
+
`${BACKFILL_SQL} WHERE "name" LIKE 'agr62a-%'`,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const rows = await prisma.agent.findMany({
|
|
73
|
+
where: { name: { startsWith: "agr62a-" } },
|
|
74
|
+
});
|
|
75
|
+
expect(rows.map((r) => r.typeName).sort()).toEqual([...LIVE_TYPE_NAMES]);
|
|
76
|
+
for (const row of rows) {
|
|
77
|
+
expect(row.specialty).not.toBeNull();
|
|
78
|
+
expect(row.specialty).toBe(row.typeName);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|