refactor: unify tool reason requirements
This commit is contained in:
@@ -32,10 +32,10 @@ describe("learning tools across process boundaries", () => {
|
||||
'import memory from "./.opencode/tools/memory_manager.ts";',
|
||||
'import skill from "./.opencode/tools/skill_manager.ts";',
|
||||
'const ctx = { sessionID: "learning-bridge-session" };',
|
||||
'const call = (action, content) => memory.execute({ action, scope: "user", reason: "test", content }, ctx).then(JSON.parse);',
|
||||
'const call = (action, content) => memory.execute({ action, scope: "user", ...(action === "list" ? {} : { reason: "test" }), content }, ctx).then(JSON.parse);',
|
||||
'const before = await call("add", "用户偏好简洁答复");',
|
||||
'await call("list"); const added = await call("add", "用户偏好简洁答复");',
|
||||
'const skills = JSON.parse(await skill.execute({ action: "list", skill_path: "__root__", reason: "test" }, ctx));',
|
||||
'const skills = JSON.parse(await skill.execute({ action: "list", skill_path: "__root__" }, ctx));',
|
||||
'process.stdout.write(JSON.stringify({ before, added, skills }));',
|
||||
].join("\n")], { cwd: process.cwd(), env: { ...process.env, AGENT_INTERNAL_TOKEN: "TEST_ONLY", TJWATER_AGENT_INTERNAL_BASE_URL: baseUrl }, stdout: "pipe", stderr: "pipe" });
|
||||
const [exitCode, stdout, stderr] = await Promise.all([child.exited, new Response(child.stdout).text(), new Response(child.stderr).text()]);
|
||||
@@ -48,6 +48,21 @@ describe("learning tools across process boundaries", () => {
|
||||
expect(await memoryStore.list("user", "owner")).toHaveLength(1);
|
||||
expect(await memoryStore.list("user", "other-owner")).toHaveLength(0);
|
||||
const post = (sessionId: string, input: unknown, token = "TEST_ONLY") => fetch(`${baseUrl}/internal/tools/memory-manager`, { method: "POST", headers: { "Content-Type": "application/json", "x-agent-internal-token": token }, body: JSON.stringify({ session_id: sessionId, input }) });
|
||||
// Invalid mutation reasons must fail before either store is changed.
|
||||
for (const reason of [undefined, "", " ", "x".repeat(2001)]) {
|
||||
expect((await post("learning-bridge-session", {
|
||||
action: "remove", scope: "user", target_id: "anything", reason,
|
||||
})).status).toBe(400);
|
||||
const skillResponse = await fetch(`${baseUrl}/internal/tools/skill-manager`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", "x-agent-internal-token": "TEST_ONLY" },
|
||||
body: JSON.stringify({ session_id: "learning-bridge-session", input: {
|
||||
action: "write_skill", skill_path: "test", content: "must not be written", reason,
|
||||
} }),
|
||||
});
|
||||
expect(skillResponse.status).toBe(400);
|
||||
}
|
||||
expect(await memoryStore.list("user", "owner")).toHaveLength(1);
|
||||
expect((await post("missing", { action: "list", scope: "user" })).status).toBe(404);
|
||||
expect((await post("learning-bridge-session", { action: "list", scope: "user", actorKey: "other-owner" })).status).toBe(400);
|
||||
expect((await post("learning-bridge-session", { action: "list", scope: "user" }, "wrong")).status).toBe(403);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { optionalToolReason, toolReason } from "../../.opencode/tool-reason.js";
|
||||
|
||||
describe("tool reason contract", () => {
|
||||
it("allows omitted purpose but requires a nonblank business reason", () => {
|
||||
expect(optionalToolReason.parse(undefined)).toBeUndefined();
|
||||
expect(toolReason.safeParse(undefined).success).toBeFalse();
|
||||
for (const schema of [optionalToolReason, toolReason]) {
|
||||
expect(schema.parse(" 核验压力异常 ")).toBe("核验压力异常");
|
||||
expect(schema.safeParse(" ").success).toBeFalse();
|
||||
expect(schema.safeParse("x".repeat(2001)).success).toBeFalse();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user