Files
next-tjwater-drainage-frontend/features/agent/session-state.test.ts
T

123 lines
3.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
applyPermissionResponse,
applyQuestionResponse,
finalizeAssistantMessageAfterAbort,
toTodoUpdate,
upsertPermission,
upsertProgress,
upsertQuestion
} from "./session-state";
import type { AgentChatMessage } from "./types";
describe("agent session state", () => {
it("upserts progress events by id", () => {
const first = upsertProgress(undefined, {
id: "tool-1",
phase: "tool",
status: "running",
title: "调用工具",
elapsed_ms: 20
});
const next = upsertProgress(first, {
id: "tool-1",
phase: "tool",
status: "completed",
title: "工具完成",
duration_ms: 40
});
expect(next).toHaveLength(1);
expect(next[0]).toMatchObject({ id: "tool-1", status: "completed", title: "工具完成", durationMs: 40 });
});
it("normalizes todo updates", () => {
expect(
toTodoUpdate({
session_id: "session-1",
todos: [{ id: "todo-1", content: "分析压力", status: "in_progress", priority: "high" }],
created_at: 123
})
).toEqual({
sessionId: "session-1",
messageId: undefined,
todos: [{ id: "todo-1", content: "分析压力", status: "in_progress", priority: "high" }],
createdAt: 123
});
});
it("tracks permission request and response", () => {
const permissions = upsertPermission(undefined, {
session_id: "session-1",
request_id: "permission-1",
permission: "bash",
patterns: ["pnpm test"],
always: [],
created_at: 100
});
const next = applyPermissionResponse(permissions, {
request_id: "permission-1",
reply: "once"
});
expect(next?.[0]).toMatchObject({
requestId: "permission-1",
status: "approved_once"
});
});
it("dedupes question requests by tool call id", () => {
const questions = upsertQuestion(undefined, {
session_id: "session-1",
request_id: "call-1",
tool: { messageID: "message-1", callID: "call-1" },
questions: [{ header: "范围", question: "选择范围", options: [] }],
created_at: 100
});
const next = upsertQuestion(questions, {
session_id: "session-1",
request_id: "question-1",
tool: { messageID: "message-1", callID: "call-1" },
questions: [{ header: "范围", question: "选择范围", options: [] }],
created_at: 120
});
const answered = applyQuestionResponse(next, {
request_id: "question-1",
answers: [["东部"]]
});
expect(next).toHaveLength(1);
expect(answered?.[0]).toMatchObject({
requestId: "question-1",
status: "answered",
answers: [["东部"]]
});
});
it("finalizes open assistant state after abort", () => {
const message: AgentChatMessage = {
id: "assistant-1",
role: "assistant",
content: "",
progress: [{ id: "run", phase: "run", status: "running", title: "处理中", startedAt: Date.now() }],
permissions: [
{
requestId: "permission-1",
sessionId: "session-1",
permission: "bash",
patterns: [],
always: [],
createdAt: 100,
status: "pending"
}
]
};
const next = finalizeAssistantMessageAfterAbort(message);
expect(next.content).toBe("请求已中止。");
expect(next.progress?.[0].status).toBe("completed");
expect(next.permissions?.[0].status).toBe("aborted");
});
});