| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- import assert from "node:assert/strict";
- import test from "node:test";
- import {
- normalizeInspection,
- normalizeStatus,
- parseStatusChangedNotification,
- type ReadMethod,
- type ThreadSummary,
- } from "../src/domain.js";
- const allowedMethod = "thread/read" satisfies ReadMethod;
- // @ts-expect-error Mutating methods must not satisfy the compile-time allowlist.
- const rejectedMethod: ReadMethod = "thread/archive";
- void allowedMethod;
- void rejectedMethod;
- const baseThread = {
- id: "thread-1",
- sessionId: "thread-1",
- parentThreadId: null,
- forkedFromId: null,
- preview: "Investigate",
- ephemeral: false,
- modelProvider: "openai",
- createdAt: 10,
- updatedAt: 20,
- recencyAt: 30,
- cwd: "/work/project",
- source: "cli",
- status: { type: "active", activeFlags: ["waitingOnApproval"] },
- name: "Investigation",
- agentNickname: null,
- agentRole: null,
- turns: [],
- };
- test("status normalization preserves all documented states and active flags", () => {
- assert.deepEqual(normalizeStatus({ type: "active", activeFlags: ["waitingOnApproval"] }), {
- type: "active",
- activeFlags: ["waitingOnApproval"],
- });
- for (const type of ["idle", "notLoaded", "systemError"] as const) {
- assert.deepEqual(normalizeStatus({ type }), { type, activeFlags: [] });
- }
- });
- test("status notifications preserve thread identity and semantics", () => {
- assert.deepEqual(
- parseStatusChangedNotification({
- method: "thread/status/changed",
- params: { threadId: "thread-1", status: { type: "idle" } },
- }),
- { threadId: "thread-1", status: { type: "idle", activeFlags: [] } },
- );
- assert.equal(parseStatusChangedNotification({ method: "turn/completed", params: {} }), null);
- });
- test("inspection returns bounded recent conversation context", () => {
- const result = normalizeInspection(
- {
- thread: {
- ...baseThread,
- turns: [
- {
- id: "turn-1",
- items: [
- { id: "user-1", type: "userMessage", content: [{ type: "text", text: "older" }] },
- { id: "agent-1", type: "agentMessage", text: "recent-answer" },
- ],
- },
- ],
- },
- },
- { maxItems: 1, maxCharacters: 6 },
- );
- assert.deepEqual(result.context.items.map((item) => item.text), ["answer"]);
- assert.equal(result.context.truncated, true);
- assert.equal(result.context.omittedItems, 1);
- });
- test("thread summary type contains no conversation body field", () => {
- const summary = normalizeInspection({ thread: baseThread }, { maxItems: 1, maxCharacters: 10 }).thread;
- assert.equal("turns" in (summary as ThreadSummary), false);
- });
- test("malformed thread response is rejected", () => {
- assert.throws(
- () => normalizeInspection({ thread: { ...baseThread, turns: "bad" } }, { maxItems: 1, maxCharacters: 10 }),
- /turns must be an array/,
- );
- });
|