@app-vitals/agent-admin 0.13.0 → 0.13.2

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.
Files changed (41) hide show
  1. package/e2e/test-server.ts +5 -5
  2. package/openapi.json +12 -19
  3. package/openapi.platform.json +11 -18
  4. package/package.json +2 -2
  5. package/prisma/client/internal/class.ts +4 -4
  6. package/prisma/client/internal/prismaNamespace.ts +0 -1
  7. package/prisma/client/internal/prismaNamespaceBrowser.ts +0 -1
  8. package/prisma/client/models/Agent.ts +62 -137
  9. package/prisma/migrations/20261030000000_drop_agent_type_name/migration.sql +8 -0
  10. package/prisma/schema/schema.prisma +3 -4
  11. package/src/account-lifecycle.integration.test.ts +1 -1
  12. package/src/account-trial-warning-sweeper.integration.test.ts +1 -1
  13. package/src/admin-local-agent.smoke.test.ts +12 -12
  14. package/src/admin-ui-pages.ts +2 -2
  15. package/src/admin-ui-pages.unit.test.ts +2 -2
  16. package/src/admin-ui.fixtures.ts +6 -6
  17. package/src/admin-ui.smoke.test.ts +39 -39
  18. package/src/admin-ui.ts +8 -8
  19. package/src/agent-cron-jobs.integration.test.ts +8 -7
  20. package/src/agent-cron-jobs.ts +4 -5
  21. package/src/agent-cron-jobs.unit.test.ts +23 -23
  22. package/src/agent-patch-author-allowlist.integration.test.ts +4 -4
  23. package/src/agent-specialty-backfill.integration.test.ts +98 -53
  24. package/src/agents-api.integration.test.ts +20 -20
  25. package/src/agents-api.smoke.test.ts +76 -77
  26. package/src/agents-api.ts +9 -14
  27. package/src/agents.integration.test.ts +40 -53
  28. package/src/agents.ts +33 -46
  29. package/src/agents.unit.test.ts +28 -35
  30. package/src/api.smoke.test.ts +24 -2
  31. package/src/api.ts +15 -16
  32. package/src/openapi-schemas.ts +14 -7
  33. package/src/slack-provisioning-service.integration.test.ts +2 -2
  34. package/src/slack-provisioning.integration.test.ts +2 -2
  35. package/src/specialty-manifest-loader.ts +32 -32
  36. package/src/specialty-manifest-loader.unit.test.ts +8 -8
  37. package/src/startup-policy-reconcile.unit.test.ts +1 -1
  38. package/src/trial-expiry-sweeper.integration.test.ts +1 -1
  39. package/src/trial-expiry-warning-sweeper.integration.test.ts +1 -1
  40. package/src/agent-specialty.ts +0 -22
  41. package/src/agent-specialty.unit.test.ts +0 -43
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * admin/src/specialty-manifest-loader.unit.test.ts
3
3
  * Unit tests for SpecialtyRegistry — the disk-backed resolver from an agent's
4
- * typeName to its parsed manifest, with the unknown-type "coding" fallback.
4
+ * specialty to its parsed manifest, with the unknown-type "coding" fallback.
5
5
  *
6
6
  * Pure logic against an injected reader/warner — no filesystem, no DB. See
7
7
  * docs/testing.md for the unit-layer contract.
@@ -44,7 +44,7 @@ voice: true
44
44
  }
45
45
 
46
46
  describe("SpecialtyRegistry", () => {
47
- it("resolves a known typeName to its parsed manifest", () => {
47
+ it("resolves a known specialty to its parsed manifest", () => {
48
48
  const registry = new SpecialtyRegistry({
49
49
  defaultTypeName: DEFAULT_SPECIALTY_NAME,
50
50
  read: (t) => manifestYaml(t),
@@ -54,7 +54,7 @@ describe("SpecialtyRegistry", () => {
54
54
  expect(manifest.crons[0]?.name).toBe("coding-cron");
55
55
  });
56
56
 
57
- it("falls back to the coding manifest with a warning for an unknown typeName", () => {
57
+ it("falls back to the coding manifest with a warning for an unknown specialty", () => {
58
58
  const warnings: string[] = [];
59
59
  const registry = new SpecialtyRegistry({
60
60
  defaultTypeName: DEFAULT_SPECIALTY_NAME,
@@ -97,10 +97,10 @@ describe("SpecialtyRegistry", () => {
97
97
  defaultTypeName: "absent",
98
98
  });
99
99
 
100
- for (const typeName of ["absent", "some-other-type"]) {
100
+ for (const specialty of ["absent", "some-other-type"]) {
101
101
  let message = "";
102
102
  try {
103
- registry.getManifest(typeName);
103
+ registry.getManifest(specialty);
104
104
  } catch (err) {
105
105
  message = (err as Error).message;
106
106
  }
@@ -131,12 +131,12 @@ describe("SpecialtyRegistry", () => {
131
131
  // ─── tryGetManifest — non-fallback lookup ────────────────────────────────
132
132
  //
133
133
  // Unlike getManifest(), tryGetManifest() must NOT fall back to "coding" for
134
- // an unknown typeName — it returns undefined instead. This is what lets
134
+ // an unknown specialty — it returns undefined instead. This is what lets
135
135
  // POST /agents distinguish "resolved to the exact requested type" from
136
136
  // "silently degraded", which the cron-reconcile boot path (getManifest())
137
137
  // deliberately does not need to distinguish.
138
138
 
139
- it("tryGetManifest resolves a known typeName to its parsed manifest", () => {
139
+ it("tryGetManifest resolves a known specialty to its parsed manifest", () => {
140
140
  const registry = new SpecialtyRegistry({
141
141
  defaultTypeName: DEFAULT_SPECIALTY_NAME,
142
142
  read: (t) => manifestYaml(t),
@@ -145,7 +145,7 @@ describe("SpecialtyRegistry", () => {
145
145
  expect(manifest?.metadata.name).toBe("coding");
146
146
  });
147
147
 
148
- it("tryGetManifest returns undefined for an unknown typeName — no fallback, no warning", () => {
148
+ it("tryGetManifest returns undefined for an unknown specialty — no fallback, no warning", () => {
149
149
  const warnings: string[] = [];
150
150
  const registry = new SpecialtyRegistry({
151
151
  defaultTypeName: DEFAULT_SPECIALTY_NAME,
@@ -80,7 +80,7 @@ function agent(overrides: Partial<AgentSummary> & { id: string }) {
80
80
  return {
81
81
  name: `${overrides.id}-slug`,
82
82
  selfHosted: false,
83
- typeName: "dev",
83
+ specialty: "dev",
84
84
  accountId: null,
85
85
  ...overrides,
86
86
  } satisfies AgentSummary;
@@ -35,7 +35,7 @@ async function createAgent(
35
35
  const agent = await prisma.agent.create({
36
36
  data: {
37
37
  name: opts.name ?? "Test Agent",
38
- typeName: "coding",
38
+ specialty: "coding",
39
39
  trialExpiresAt: opts.trialExpiresAt ?? null,
40
40
  },
41
41
  });
@@ -88,7 +88,7 @@ function buildDeps(
88
88
  name: agent.name,
89
89
  slackId: null,
90
90
  selfHosted: false,
91
- typeName: "coding",
91
+ specialty: "coding",
92
92
  createdAt: NOW,
93
93
  updatedAt: NOW,
94
94
  missingRequiredEnv: [],
@@ -1,22 +0,0 @@
1
- /**
2
- * AGR-6.1: typeName -> specialty rename, ADD step. `Agent.specialty` is a
3
- * nullable column written alongside `typeName`; reads prefer it and fall back
4
- * to `typeName` for rows that predate the column. Nothing is retired yet.
5
- */
6
-
7
- export interface SpecialtyBearingRow {
8
- typeName: string;
9
- specialty?: string | null;
10
- }
11
-
12
- /** The agent's specialty: the new column when set, else the legacy `typeName`. */
13
- export function resolveSpecialty(row: SpecialtyBearingRow): string {
14
- return row.specialty ?? row.typeName;
15
- }
16
-
17
- /** Returns the row with `specialty` resolved to a non-null string. */
18
- export function withResolvedSpecialty<T extends SpecialtyBearingRow>(
19
- row: T,
20
- ): Omit<T, "specialty"> & { specialty: string } {
21
- return { ...row, specialty: resolveSpecialty(row) };
22
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * Unit tests for the AGR-6.1 specialty mapper (typeName -> specialty ADD step).
3
- */
4
-
5
- import { describe, expect, it } from "bun:test";
6
- import { resolveSpecialty, withResolvedSpecialty } from "./agent-specialty.ts";
7
-
8
- describe("resolveSpecialty", () => {
9
- it("prefers specialty when set", () => {
10
- expect(
11
- resolveSpecialty({ typeName: "coding", specialty: "research" }),
12
- ).toBe("research");
13
- });
14
-
15
- it("falls back to typeName when specialty is null", () => {
16
- expect(resolveSpecialty({ typeName: "coding", specialty: null })).toBe(
17
- "coding",
18
- );
19
- });
20
-
21
- it("falls back to typeName when specialty is absent", () => {
22
- expect(resolveSpecialty({ typeName: "coding" })).toBe("coding");
23
- });
24
-
25
- it("does not treat an empty-string specialty as unset", () => {
26
- expect(resolveSpecialty({ typeName: "coding", specialty: "" })).toBe("");
27
- });
28
- });
29
-
30
- describe("withResolvedSpecialty", () => {
31
- it("returns a copy with specialty resolved and typeName preserved", () => {
32
- const row = { id: "a1", typeName: "coding", specialty: null };
33
- const out = withResolvedSpecialty(row);
34
- expect(out).toEqual({ id: "a1", typeName: "coding", specialty: "coding" });
35
- expect(row.specialty).toBeNull();
36
- });
37
-
38
- it("keeps an explicit specialty", () => {
39
- expect(
40
- withResolvedSpecialty({ typeName: "coding", specialty: "research" }),
41
- ).toEqual({ typeName: "coding", specialty: "research" });
42
- });
43
- });