mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 17:30:31 +00:00
144 lines
5 KiB
TypeScript
144 lines
5 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import type { CodexInput } from "../../../../../src/domain/chat/input";
|
|
import type { Thread } from "../../../../../src/domain/threads/model";
|
|
import type { ComposerInputSnapshot } from "../../../../../src/features/chat/application/composer/input-snapshot";
|
|
import { createLocalIdSource } from "../../../../../src/features/chat/application/local-id-source";
|
|
import { createChatState } from "../../../../../src/features/chat/application/state/root-reducer";
|
|
import { createChatStateStore } from "../../../../../src/features/chat/application/state/store";
|
|
import { createTurnWorkflowActions } from "../../../../../src/features/chat/application/turns/composition";
|
|
import type { ThreadStreamItem } from "../../../../../src/features/chat/domain/thread-stream/items";
|
|
|
|
const IMPLEMENT_PLAN_PROMPT = "Please implement this plan.";
|
|
|
|
const planItem = (id: string): ThreadStreamItem => ({
|
|
id,
|
|
kind: "dialogue",
|
|
role: "assistant",
|
|
text: "Plan",
|
|
dialogueKind: "proposedPlan",
|
|
dialogueState: "completed",
|
|
});
|
|
|
|
function thread(id: string): Thread {
|
|
return {
|
|
id,
|
|
preview: "",
|
|
createdAt: 0,
|
|
updatedAt: 0,
|
|
name: null,
|
|
archived: false,
|
|
provenance: { kind: "interactive" },
|
|
};
|
|
}
|
|
|
|
function resumeThread(stateStore: ReturnType<typeof createChatStateStore>, items: readonly ThreadStreamItem[]): void {
|
|
stateStore.dispatch({
|
|
type: "active-thread/resumed",
|
|
approvalPolicyKnown: true,
|
|
sandboxPolicyKnown: true,
|
|
permissionProfileKnown: true,
|
|
approvalPolicy: null,
|
|
sandboxPolicy: null,
|
|
activePermissionProfile: null,
|
|
thread: thread("thread"),
|
|
cwd: "/vault",
|
|
model: null,
|
|
reasoningEffort: null,
|
|
serviceTier: null,
|
|
approvalsReviewer: null,
|
|
items,
|
|
});
|
|
stateStore.dispatch({ type: "runtime/requested-collaboration-mode-set", collaborationMode: "plan" });
|
|
}
|
|
|
|
describe("createTurnWorkflowActions", () => {
|
|
it("does not attach composer-only active file context when implementing a plan", async () => {
|
|
const stateStore = createChatStateStore(createChatState());
|
|
const plan = planItem("plan");
|
|
resumeThread(stateStore, [plan]);
|
|
const startTurn = vi.fn().mockResolvedValue({ kind: "completed-current" as const, value: { turnId: "turn" } });
|
|
const composerSnapshot: ComposerInputSnapshot = {
|
|
sourcePath: "notes/Alpha.md",
|
|
availableSkills: [],
|
|
referenceActiveNoteOnSend: true,
|
|
contextReferences: {
|
|
activeNote: { name: "Alpha", path: "notes/Alpha.md", linktext: "Alpha" },
|
|
selection: null,
|
|
},
|
|
activeNoteSnapshots: [],
|
|
selectionSnapshots: [],
|
|
attachments: [],
|
|
};
|
|
const prepareInput = vi.fn((text: string, _snapshot: ComposerInputSnapshot): { text: string; input: CodexInput } => ({
|
|
text,
|
|
input: [
|
|
{ type: "text", text },
|
|
{ type: "fileReference", name: "unexpected", path: "notes/Alpha.md" },
|
|
],
|
|
}));
|
|
const actions = createTurnWorkflowActions(
|
|
{
|
|
stateStore,
|
|
localItemIds: createLocalIdSource(),
|
|
connectionAvailable: () => true,
|
|
turnTransport: {
|
|
ensureConnected: vi.fn().mockResolvedValue(true),
|
|
startTurn,
|
|
steerTurn: vi.fn().mockResolvedValue({ kind: "completed-current" as const, value: undefined }),
|
|
interruptTurn: vi.fn().mockResolvedValue(true),
|
|
},
|
|
referThread: vi.fn(),
|
|
readWebUrl: vi.fn(),
|
|
status: {
|
|
set: vi.fn(),
|
|
addSystemMessage: vi.fn(),
|
|
addStructuredSystemMessage: vi.fn(),
|
|
},
|
|
runtime: {
|
|
connectionDiagnosticDetails: () => [],
|
|
permissionDetails: () => [],
|
|
modelStatusDetails: () => [],
|
|
effortStatusDetails: () => [],
|
|
statusDetails: () => [],
|
|
toolInventoryDetails: () => [],
|
|
},
|
|
thread: {
|
|
ensureRestoredThreadLoaded: vi.fn().mockResolvedValue(true),
|
|
startNewThread: vi.fn(),
|
|
selectThread: vi.fn(),
|
|
notifyIdentityChanged: vi.fn(),
|
|
resetTurnPresence: vi.fn(),
|
|
},
|
|
composer: {
|
|
prepareInput,
|
|
captureInputSnapshot: vi.fn(() => composerSnapshot),
|
|
draft: () => "",
|
|
trimmedDraft: () => "",
|
|
setDraft: vi.fn(),
|
|
},
|
|
scroll: { showLatest: vi.fn() },
|
|
},
|
|
{
|
|
threadStarter: { startThread: vi.fn() },
|
|
runtimeSettings: {
|
|
applyPendingThreadSettings: vi.fn().mockResolvedValue(true),
|
|
requestDefaultCollaborationModeForNextTurn: vi.fn(() => {
|
|
stateStore.dispatch({ type: "runtime/requested-collaboration-mode-set", collaborationMode: "default" });
|
|
}),
|
|
} as never,
|
|
threadActions: {} as never,
|
|
reconnectPanel: vi.fn(),
|
|
goals: {} as never,
|
|
},
|
|
);
|
|
await actions.planImplementation.implement(plan.id);
|
|
|
|
expect(prepareInput).not.toHaveBeenCalled();
|
|
expect(startTurn).toHaveBeenCalledWith({
|
|
threadId: "thread",
|
|
input: [{ type: "text", text: IMPLEMENT_PLAN_PROMPT }],
|
|
clientUserMessageId: expect.any(String),
|
|
});
|
|
});
|
|
});
|