import { EnvironmentId, ThreadId, type ScopedThreadRef } from "@t3tools/contracts";import * as Option from "effect/Option";import { AsyncResult, Atom, AtomRegistry } from "effect/unstable/reactivity";import { describe, expect, it } from "vite-plus/test"; import { v2Projection } from "./orchestrationV2TestFixtures.ts";import { EMPTY_THREAD_HISTORY_META } from "./threadHistoryMerge.ts";import { createEnvironmentThreadDetailAtoms } from "./threadDetail.ts";import type { EnvironmentThreadState } from "./threads.ts"; const ref: ScopedThreadRef = { environmentId: EnvironmentId.make("environment-detail"), threadId: ThreadId.make(v2Projection.thread.id),}; function threadState( partial: Pick<EnvironmentThreadState, "data" | "status" | "error"> & Partial<Pick<EnvironmentThreadState, "history">>,): EnvironmentThreadState { return { ...partial, history: partial.history ?? EMPTY_THREAD_HISTORY_META };} describe("createEnvironmentThreadDetailAtoms", () => { it("adds environment scope while preserving the pristine projection", () => { const initial: AsyncResult.AsyncResult<EnvironmentThreadState, never> = AsyncResult.success( threadState({ data: Option.some(v2Projection), status: "cached", error: Option.none(), }), ); const sourceAtom = Atom.make(initial); const details = createEnvironmentThreadDetailAtoms(() => sourceAtom); const registry = AtomRegistry.make(); const thread = registry.get(details.threadAtom(ref)); expect(thread).toEqual({ environmentId: ref.environmentId, projection: v2Projection }); expect(thread?.projection).toBe(v2Projection); expect(registry.get(details.visibleTurnItemsAtom(ref))).toBe(v2Projection.visibleTurnItems); expect(registry.get(details.statusAtom(ref))).toBe("cached"); expect(registry.get(details.historyAtom(ref))).toBe(EMPTY_THREAD_HISTORY_META); registry.set( sourceAtom, AsyncResult.success( threadState({ data: Option.some(v2Projection), status: "synchronizing", error: Option.none(), }), ), ); expect(registry.get(details.threadAtom(ref))).toBe(thread); expect(registry.get(details.statusAtom(ref))).toBe("synchronizing"); const progressiveHistory = { ...EMPTY_THREAD_HISTORY_META, historyCursor: "cursor-1", hasMoreHistory: true, }; registry.set( sourceAtom, AsyncResult.success( threadState({ data: Option.some(v2Projection), status: "live", error: Option.some("Stream interrupted."), history: progressiveHistory, }), ), ); expect(registry.get(details.threadAtom(ref))).toBe(thread); expect(registry.get(details.visibleTurnItemsAtom(ref))).toBe(v2Projection.visibleTurnItems); expect(registry.get(details.statusAtom(ref))).toBe("live"); expect(registry.get(details.errorAtom(ref))).toBe("Stream interrupted."); expect(registry.get(details.historyAtom(ref))).toBe(progressiveHistory); registry.set( sourceAtom, AsyncResult.success( threadState({ data: Option.none(), status: "deleted", error: Option.none(), }), ), ); expect(registry.get(details.threadAtom(ref))).toBeNull(); expect(registry.get(details.visibleTurnItemsAtom(ref))).toEqual([]); expect(registry.get(details.statusAtom(ref))).toBe("deleted"); expect(registry.get(details.errorAtom(ref))).toBeNull(); expect(registry.get(details.historyAtom(ref))).toBe(EMPTY_THREAD_HISTORY_META); registry.dispose(); });});
import { EnvironmentId, ThreadId, type ScopedThreadRef } from "@t3tools/contracts";
import * as Option from "effect/Option";
import { AsyncResult, Atom, AtomRegistry } from "effect/unstable/reactivity";
import { describe, expect, it } from "vite-plus/test";
import { v2Projection } from "./orchestrationV2TestFixtures.ts";
import { EMPTY_THREAD_HISTORY_META } from "./threadHistoryMerge.ts";
import { createEnvironmentThreadDetailAtoms } from "./threadDetail.ts";
import type { EnvironmentThreadState } from "./threads.ts";
const ref: ScopedThreadRef = {
environmentId: EnvironmentId.make("environment-detail"),
threadId: ThreadId.make(v2Projection.thread.id),
};
function threadState(
partial: Pick<EnvironmentThreadState, "data" | "status" | "error"> &
Partial<Pick<EnvironmentThreadState, "history">>,
): EnvironmentThreadState {
return { ...partial, history: partial.history ?? EMPTY_THREAD_HISTORY_META };
}
describe("createEnvironmentThreadDetailAtoms", () => {
it("adds environment scope while preserving the pristine projection", () => {
const initial: AsyncResult.AsyncResult<EnvironmentThreadState, never> = AsyncResult.success(
threadState({
data: Option.some(v2Projection),
status: "cached",
error: Option.none(),
}),
);
const sourceAtom = Atom.make(initial);
const details = createEnvironmentThreadDetailAtoms(() => sourceAtom);
const registry = AtomRegistry.make();
const thread = registry.get(details.threadAtom(ref));
expect(thread).toEqual({ environmentId: ref.environmentId, projection: v2Projection });
expect(thread?.projection).toBe(v2Projection);
expect(registry.get(details.visibleTurnItemsAtom(ref))).toBe(v2Projection.visibleTurnItems);
expect(registry.get(details.statusAtom(ref))).toBe("cached");
expect(registry.get(details.historyAtom(ref))).toBe(EMPTY_THREAD_HISTORY_META);
registry.set(
sourceAtom,
AsyncResult.success(
threadState({
data: Option.some(v2Projection),
status: "synchronizing",
error: Option.none(),
}),
),
);
expect(registry.get(details.threadAtom(ref))).toBe(thread);
expect(registry.get(details.statusAtom(ref))).toBe("synchronizing");
const progressiveHistory = {
...EMPTY_THREAD_HISTORY_META,
historyCursor: "cursor-1",
hasMoreHistory: true,
};
registry.set(
sourceAtom,
AsyncResult.success(
threadState({
data: Option.some(v2Projection),
status: "live",
error: Option.some("Stream interrupted."),
history: progressiveHistory,
}),
),
);
expect(registry.get(details.threadAtom(ref))).toBe(thread);
expect(registry.get(details.visibleTurnItemsAtom(ref))).toBe(v2Projection.visibleTurnItems);
expect(registry.get(details.statusAtom(ref))).toBe("live");
expect(registry.get(details.errorAtom(ref))).toBe("Stream interrupted.");
expect(registry.get(details.historyAtom(ref))).toBe(progressiveHistory);
registry.set(
sourceAtom,
AsyncResult.success(
threadState({
data: Option.none(),
status: "deleted",
error: Option.none(),
}),
),
);
expect(registry.get(details.threadAtom(ref))).toBeNull();
expect(registry.get(details.visibleTurnItemsAtom(ref))).toEqual([]);
expect(registry.get(details.statusAtom(ref))).toBe("deleted");
expect(registry.get(details.errorAtom(ref))).toBeNull();
expect(registry.get(details.historyAtom(ref))).toBe(EMPTY_THREAD_HISTORY_META);
registry.dispose();
});
});