816a823b75
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
90 lines
3.9 KiB
TypeScript
90 lines
3.9 KiB
TypeScript
/**
|
|
* POST /api/projects/:projectId/agents/:agentId/config/reset — overwrites
|
|
* system_config.yaml with the current code defaults, keeping only the identity fields
|
|
* (name / description / version); the config-side analogue of a skill update. Same
|
|
* member-level authorization as PUT config; a non-member gets 404 without a write.
|
|
*/
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
import { defaultSystemConfig } from "@prismshadow/penguin-core";
|
|
import type { AgentConfigResponse, ProjectCreateResponse } from "../src/api/types.js";
|
|
import { apiClient, createTestApp, provisionUser } from "./helpers.js";
|
|
import type { TestApp } from "./helpers.js";
|
|
|
|
describe("POST agent config reset", () => {
|
|
let t: TestApp;
|
|
let alice: ReturnType<typeof apiClient>;
|
|
let projectId: string;
|
|
const configUrl = () => `/api/projects/${projectId}/agents/default_agent/config`;
|
|
|
|
beforeEach(async () => {
|
|
t = await createTestApp();
|
|
const a = await provisionUser(t.app, "alice");
|
|
alice = apiClient(t.app, a.cookie);
|
|
// Project ids are username-prefixed (`alice-…`), same as the other route tests.
|
|
const created = (await (
|
|
await alice.post("/api/projects", { projectId: "alice-reset", name: "Reset project" })
|
|
).json()) as ProjectCreateResponse;
|
|
projectId = created.project.projectId;
|
|
});
|
|
afterEach(async () => {
|
|
await t.cleanup();
|
|
});
|
|
|
|
it("restores the defaults while preserving name / description / version", async () => {
|
|
// Customize everything the reset is supposed to overwrite, plus the kept fields.
|
|
const put = await alice.put(configUrl(), {
|
|
config: {
|
|
name: "Custom Name",
|
|
description: "Custom description",
|
|
systemPrompt: "CUSTOM PROMPT",
|
|
maxTurns: 3,
|
|
model: { maxTokens: 1234 },
|
|
compaction: { mode: "discard" },
|
|
toolsBuiltin: [],
|
|
mcpServers: [{ name: "custom-mcp", config: {} }],
|
|
},
|
|
});
|
|
expect(put.status).toBe(200);
|
|
|
|
const res = await alice.post(`${configUrl()}/reset`);
|
|
expect(res.status).toBe(200);
|
|
const body = (await res.json()) as AgentConfigResponse;
|
|
const defaults = defaultSystemConfig();
|
|
|
|
// Identity fields survive.
|
|
expect(body.config.name).toBe("Custom Name");
|
|
expect(body.config.description).toBe("Custom description");
|
|
expect(body.config.version).toBe(1);
|
|
// Everything else is back to the current defaults.
|
|
expect(body.config.systemPrompt).toBe(defaults.system_prompt);
|
|
expect(body.config.systemPrompt).toContain("App Data Dir: {{PROJECT_DIR}}");
|
|
expect(body.config.maxTurns).toBe(defaults.max_turns);
|
|
expect(body.config.model?.maxTokens).toBe(defaults.model?.max_tokens);
|
|
expect(body.config.compaction?.mode).toBe("summarize");
|
|
expect(body.config.toolsBuiltin.map((tool) => tool.name)).toEqual(
|
|
(defaults.tools?.builtin ?? []).map((tool) => tool.name),
|
|
);
|
|
expect(body.config.mcpServers).toEqual([]);
|
|
|
|
// A later GET sees the same reset state (it was persisted, not just echoed).
|
|
const got = (await (await alice.get(configUrl())).json()) as AgentConfigResponse;
|
|
expect(got.config.systemPrompt).toBe(defaults.system_prompt);
|
|
expect(got.config.name).toBe("Custom Name");
|
|
});
|
|
|
|
it("404 for a nonexistent agent (no initialization side effect)", async () => {
|
|
const res = await alice.post(`/api/projects/${projectId}/agents/ghost/config/reset`);
|
|
expect(res.status).toBe(404);
|
|
});
|
|
|
|
it("404 for a non-member; the config is not modified", async () => {
|
|
const before = (await (await alice.get(configUrl())).json()) as AgentConfigResponse;
|
|
const m = await provisionUser(t.app, "mallory");
|
|
const mallory = apiClient(t.app, m.cookie);
|
|
const res = await mallory.post(`${configUrl()}/reset`);
|
|
expect(res.status).toBe(404);
|
|
const after = (await (await alice.get(configUrl())).json()) as AgentConfigResponse;
|
|
expect(after.systemConfigYaml).toBe(before.systemConfigYaml);
|
|
});
|
|
});
|