FN-6750: harden task chat steering coverage
Verify task chat timestamps and immediate steering delivery across UI, route, and executor surfaces. - Assert inline and expanded TaskChatTab timestamp parity for agent output and user steering comments. - Cover steering route wake payloads so assigned agents receive the newest steering comment id immediately. - Harden executor real-time steering tests for seen-before-inject ordering, queued prompt delivery, duplicate suppression, and empty-comment no-ops. Files changed: .../app/components/__tests__/TaskChatTab.test.tsx | 79 +++++++++++- .../src/__tests__/routes-tasks-ops.test.ts | 136 +++++++++++++++++++++ .../src/__tests__/executor-step-session.test.ts | 116 ++++++++++++++++-- 3 files changed, 316 insertions(+), 15 deletions(-) Fusion-Task-Id: FN-6750 Fusion-Task-Lineage: 48e1d57d-fd37-4d45-9b98-766c4a2f704d
This commit is contained in:
@@ -332,9 +332,14 @@ describe("TaskChatTab", () => {
|
||||
expect(mockedUseAgentLogs).toHaveBeenCalledWith("FN-001", false, "project-1");
|
||||
});
|
||||
|
||||
it("renders empty state when no agent output exists", () => {
|
||||
it("renders empty state without timestamp shells when no transcript messages exist", () => {
|
||||
render(<TaskChatTab task={makeTask()} active addToast={vi.fn()} />);
|
||||
expect(screen.getByText(/No agent output yet/)).toBeTruthy();
|
||||
|
||||
const transcript = screen.getByTestId("task-chat-transcript");
|
||||
expect(within(transcript).getByText(/No agent output yet/)).toBeTruthy();
|
||||
expect(within(transcript).queryByTestId("task-chat-group-time")).not.toBeInTheDocument();
|
||||
expect(within(transcript).queryByTestId("task-chat-user-time")).not.toBeInTheDocument();
|
||||
expect(transcript).not.toHaveTextContent(/NaN|Invalid Date/);
|
||||
});
|
||||
|
||||
it("renders the collapsed icon-only expand toggle inside the chat view and calls the toggle handler", () => {
|
||||
@@ -461,6 +466,65 @@ describe("TaskChatTab", () => {
|
||||
expect(within(groupMeta as HTMLElement).getByTestId("task-chat-group-time")).toHaveTextContent("2m ago");
|
||||
});
|
||||
|
||||
it("keeps agent and user timestamp parity in the inline chat surface", () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2026-06-17T15:00:00.000Z"));
|
||||
mockLogs([
|
||||
makeEntry({ agent: "executor", text: "inline agent response", timestamp: "2026-06-17T14:58:30.000Z" }),
|
||||
]);
|
||||
|
||||
render(
|
||||
<TaskChatTab
|
||||
task={makeTask({
|
||||
steeringComments: [makeSteeringComment({ id: "inline-user", text: "inline user guidance", createdAt: "2026-06-17T14:57:00.000Z" })],
|
||||
})}
|
||||
active
|
||||
expanded={false}
|
||||
addToast={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
const transcript = screen.getByTestId("task-chat-transcript");
|
||||
expect(within(transcript).getByText("inline agent response")).toBeVisible();
|
||||
expect(within(transcript).getByText("inline user guidance")).toBeVisible();
|
||||
expect(within(transcript).getByTestId("task-chat-group-time")).toHaveTextContent("1m ago");
|
||||
expect(within(transcript).getByTestId("task-chat-user-time")).toHaveTextContent("3m ago");
|
||||
});
|
||||
|
||||
it("keeps agent and user timestamp parity in the expanded chat surface", () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2026-06-17T15:00:00.000Z"));
|
||||
mockLogs([
|
||||
makeEntry({ agent: "executor", text: "expanded single entry", timestamp: "2026-06-17T14:59:30.000Z" }),
|
||||
makeEntry({ agent: "reviewer", text: "expanded older reviewer entry", timestamp: "2026-06-17T14:53:00.000Z" }),
|
||||
makeEntry({ agent: "reviewer", text: "expanded latest reviewer entry", timestamp: "2026-06-17T14:55:00.000Z" }),
|
||||
]);
|
||||
|
||||
render(
|
||||
<TaskChatTab
|
||||
task={makeTask({
|
||||
steeringComments: [makeSteeringComment({ id: "expanded-user", text: "expanded user guidance", createdAt: "2026-06-17T14:57:00.000Z" })],
|
||||
})}
|
||||
active
|
||||
expanded
|
||||
onToggleExpanded={vi.fn()}
|
||||
addToast={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
const executorMeta = screen.getByLabelText("Executor messages").querySelector(".task-chat-group-meta");
|
||||
const reviewerMeta = screen.getByLabelText("Reviewer messages").querySelector(".task-chat-group-meta");
|
||||
const userHeader = screen.getByText("You").closest(".task-chat-user-header");
|
||||
expect(executorMeta).not.toBeNull();
|
||||
expect(reviewerMeta).not.toBeNull();
|
||||
expect(userHeader).not.toBeNull();
|
||||
expect(within(executorMeta as HTMLElement).getByText("1 entry")).toBeVisible();
|
||||
expect(within(executorMeta as HTMLElement).getByTestId("task-chat-group-time")).toHaveTextContent("just now");
|
||||
expect(within(reviewerMeta as HTMLElement).getByText("2 entries")).toBeVisible();
|
||||
expect(within(reviewerMeta as HTMLElement).getByTestId("task-chat-group-time")).toHaveTextContent("5m ago");
|
||||
expect(within(userHeader as HTMLElement).getByTestId("task-chat-user-time")).toHaveTextContent("3m ago");
|
||||
});
|
||||
|
||||
it("renders a single text entry as one text bubble", () => {
|
||||
mockLogs([
|
||||
makeEntry({ agent: "executor", text: "single response" }),
|
||||
@@ -2100,6 +2164,17 @@ describe("TaskChatTab", () => {
|
||||
expect(mobileInputRule).toContain("min-height: calc(var(--space-2xl) + var(--space-lg))");
|
||||
});
|
||||
|
||||
it("keeps TaskDetailModal inline and expanded chat on the canonical TaskChatTab renderer", () => {
|
||||
const source = readFileSync(resolve(__dirname, "../TaskDetailModal.tsx"), "utf8");
|
||||
const taskChatMounts = source.match(/<TaskChatTab\b/g) ?? [];
|
||||
|
||||
expect(source).toContain('import { TaskChatTab } from "./TaskChatTab"');
|
||||
expect(taskChatMounts).toHaveLength(1);
|
||||
expect(source).toContain("const isChatExpanded = chatExpanded && activeTab === \"chat\" && !isEditing");
|
||||
expect(source).toContain("task-detail-content--chat-expanded");
|
||||
expect(source).toContain("expanded={chatExpanded}");
|
||||
});
|
||||
|
||||
it("keeps task chat timestamp styling tokenized and mobile-safe", () => {
|
||||
const css = readFileSync(resolve(__dirname, "../TaskChatTab.css"), "utf8");
|
||||
const groupMetaRule = getCssRuleBlock(css, ".task-chat-group-meta");
|
||||
|
||||
@@ -10,6 +10,7 @@ import { join } from "node:path";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { createHmac } from "node:crypto";
|
||||
import { createApiRoutes } from "../routes.js";
|
||||
import { registerTaskWorkflowRoutes } from "../routes/register-task-workflow-routes.js";
|
||||
import {
|
||||
getProjectIdFromRequest as getProjectIdFromRouteRequest,
|
||||
getProjectContext as resolveRouteProjectContext,
|
||||
@@ -328,6 +329,141 @@ describe("POST /tasks/:id/steer", () => {
|
||||
return app;
|
||||
}
|
||||
|
||||
it("passes the new steering comment id to the task-workflow wake dependency", async () => {
|
||||
const scopedStore = createMockStore();
|
||||
const updatedTask = {
|
||||
...FAKE_TASK_DETAIL,
|
||||
id: "FN-001",
|
||||
column: "in-progress" as const,
|
||||
assignedAgentId: "agent-1",
|
||||
steeringComments: [{ id: "steer-route-1", text: "Please continue", author: "user" as const, createdAt: "2026-06-12T00:00:00.000Z" }],
|
||||
};
|
||||
const triggerCommentWakeForAssignedAgent = vi.fn().mockResolvedValue(undefined);
|
||||
(scopedStore.addSteeringComment as ReturnType<typeof vi.fn>).mockResolvedValue(updatedTask);
|
||||
const router = express.Router();
|
||||
registerTaskWorkflowRoutes({
|
||||
router,
|
||||
store: scopedStore,
|
||||
runtimeLogger: { error: vi.fn(), warn: vi.fn() },
|
||||
planningLogger: { error: vi.fn(), warn: vi.fn(), log: vi.fn() } as any,
|
||||
chatLogger: { error: vi.fn(), warn: vi.fn(), log: vi.fn() } as any,
|
||||
getProjectIdFromRequest: () => undefined,
|
||||
getScopedStore: async () => scopedStore,
|
||||
getProjectContext: async () => ({ store: scopedStore, projectId: undefined }),
|
||||
prioritizeProjectsForCurrentDirectory: (projects) => projects,
|
||||
emitRemoteRouteDiagnostic: vi.fn(),
|
||||
emitAuthSyncAuditLog: vi.fn(),
|
||||
parseScopeParam: () => undefined,
|
||||
resolveAutomationStore: vi.fn() as any,
|
||||
resolveRoutineStore: vi.fn() as any,
|
||||
resolveRoutineRunner: vi.fn() as any,
|
||||
registerDispose: vi.fn(),
|
||||
dispose: vi.fn(),
|
||||
rethrowAsApiError: (error) => { throw error; },
|
||||
}, {
|
||||
runtimeLogger: { error: vi.fn(), warn: vi.fn() },
|
||||
upload: { single: vi.fn(() => (_req: unknown, _res: unknown, next: () => void) => next()) },
|
||||
taskDetailActivityLogLimit: 100,
|
||||
validateOptionalModelField: () => undefined,
|
||||
normalizeModelSelectionPair: (provider, modelId) => ({ provider, modelId }),
|
||||
runGitCommand: vi.fn(),
|
||||
isGitRepo: vi.fn(),
|
||||
resolveIntegrationBranch: vi.fn(),
|
||||
trimTaskDetailActivityLog: (task) => task,
|
||||
triggerCommentWakeForAssignedAgent,
|
||||
resolveSelfHealingManager: () => undefined,
|
||||
});
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use("/api", router);
|
||||
|
||||
const res = await REQUEST(app, "POST", "/api/tasks/FN-001/steer", JSON.stringify({ text: "Please continue" }), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(scopedStore.addSteeringComment).toHaveBeenCalledWith("FN-001", "Please continue", "user");
|
||||
expect(triggerCommentWakeForAssignedAgent).toHaveBeenCalledOnce();
|
||||
expect(triggerCommentWakeForAssignedAgent).toHaveBeenCalledWith(scopedStore, updatedTask, {
|
||||
triggeringCommentType: "steering",
|
||||
triggeringCommentIds: ["steer-route-1"],
|
||||
triggerDetail: "steering-comment",
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the newest steering comment id when waking assigned agents", async () => {
|
||||
const scopedStore = createMockStore();
|
||||
const updatedTask = {
|
||||
...FAKE_TASK_DETAIL,
|
||||
id: "FN-001",
|
||||
column: "in-progress" as const,
|
||||
assignedAgentId: "agent-1",
|
||||
steeringComments: [
|
||||
{
|
||||
id: "older-steer",
|
||||
text: "Earlier guidance",
|
||||
author: "user" as const,
|
||||
createdAt: "2026-06-12T00:00:00.000Z",
|
||||
},
|
||||
{
|
||||
id: "newest-steer",
|
||||
text: "Newest guidance",
|
||||
author: "user" as const,
|
||||
createdAt: "2026-06-12T00:01:00.000Z",
|
||||
},
|
||||
],
|
||||
};
|
||||
const triggerCommentWakeForAssignedAgent = vi.fn().mockResolvedValue(undefined);
|
||||
(scopedStore.addSteeringComment as ReturnType<typeof vi.fn>).mockResolvedValue(updatedTask);
|
||||
const router = express.Router();
|
||||
registerTaskWorkflowRoutes({
|
||||
router,
|
||||
store: scopedStore,
|
||||
runtimeLogger: { error: vi.fn(), warn: vi.fn() },
|
||||
planningLogger: { error: vi.fn(), warn: vi.fn(), log: vi.fn() } as any,
|
||||
chatLogger: { error: vi.fn(), warn: vi.fn(), log: vi.fn() } as any,
|
||||
getProjectIdFromRequest: () => undefined,
|
||||
getScopedStore: async () => scopedStore,
|
||||
getProjectContext: async () => ({ store: scopedStore, projectId: undefined }),
|
||||
prioritizeProjectsForCurrentDirectory: (projects) => projects,
|
||||
emitRemoteRouteDiagnostic: vi.fn(),
|
||||
emitAuthSyncAuditLog: vi.fn(),
|
||||
parseScopeParam: () => undefined,
|
||||
resolveAutomationStore: vi.fn() as any,
|
||||
resolveRoutineStore: vi.fn() as any,
|
||||
resolveRoutineRunner: vi.fn() as any,
|
||||
registerDispose: vi.fn(),
|
||||
dispose: vi.fn(),
|
||||
rethrowAsApiError: (error) => { throw error; },
|
||||
}, {
|
||||
runtimeLogger: { error: vi.fn(), warn: vi.fn() },
|
||||
upload: { single: vi.fn(() => (_req: unknown, _res: unknown, next: () => void) => next()) },
|
||||
taskDetailActivityLogLimit: 100,
|
||||
validateOptionalModelField: () => undefined,
|
||||
normalizeModelSelectionPair: (provider, modelId) => ({ provider, modelId }),
|
||||
runGitCommand: vi.fn(),
|
||||
isGitRepo: vi.fn(),
|
||||
resolveIntegrationBranch: vi.fn(),
|
||||
trimTaskDetailActivityLog: (task) => task,
|
||||
triggerCommentWakeForAssignedAgent,
|
||||
resolveSelfHealingManager: () => undefined,
|
||||
});
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use("/api", router);
|
||||
|
||||
const res = await REQUEST(app, "POST", "/api/tasks/FN-001/steer", JSON.stringify({ text: "Newest guidance" }), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(triggerCommentWakeForAssignedAgent).toHaveBeenCalledWith(scopedStore, updatedTask, {
|
||||
triggeringCommentType: "steering",
|
||||
triggeringCommentIds: ["newest-steer"],
|
||||
triggerDetail: "steering-comment",
|
||||
});
|
||||
});
|
||||
|
||||
it("records user steering comments and wakes the assigned immediate-response agent", async () => {
|
||||
const updatedTask = {
|
||||
...FAKE_TASK_DETAIL,
|
||||
|
||||
@@ -3090,7 +3090,13 @@ describe("Real-time steering injection", () => {
|
||||
it("injects new steering comments via active StepSessionExecutor on task:updated", async () => {
|
||||
const store = createMockStore();
|
||||
const executor = new TaskExecutor(store, "/tmp/test");
|
||||
const steerActiveSessions = vi.fn().mockResolvedValue(1);
|
||||
const seenIds = new Set<string>();
|
||||
const updateSteeringComments = vi.fn();
|
||||
const steerActiveSessions = vi.fn().mockImplementation(async () => {
|
||||
expect(updateSteeringComments).toHaveBeenCalledWith([newComment]);
|
||||
expect(seenIds.has(newComment.id)).toBe(true);
|
||||
return 1;
|
||||
});
|
||||
const markSteeringCommentsDelivered = vi.fn();
|
||||
const newComment = {
|
||||
id: "step-session-comment",
|
||||
@@ -3099,8 +3105,12 @@ describe("Real-time steering injection", () => {
|
||||
author: "user" as const,
|
||||
};
|
||||
|
||||
(executor as any).activeStepExecutors.set("FN-001", { steerActiveSessions, markSteeringCommentsDelivered });
|
||||
(executor as any).activeStepExecutorSeenSteeringIds.set("FN-001", new Set());
|
||||
(executor as any).activeStepExecutors.set("FN-001", {
|
||||
steerActiveSessions,
|
||||
markSteeringCommentsDelivered,
|
||||
updateSteeringComments,
|
||||
});
|
||||
(executor as any).activeStepExecutorSeenSteeringIds.set("FN-001", seenIds);
|
||||
|
||||
await (store as any)._triggerAsync("task:updated", {
|
||||
id: "FN-001",
|
||||
@@ -3116,6 +3126,7 @@ describe("Real-time steering injection", () => {
|
||||
updatedAt: new Date().toISOString(),
|
||||
});
|
||||
|
||||
expect(updateSteeringComments).toHaveBeenCalledOnce();
|
||||
expect(steerActiveSessions).toHaveBeenCalledOnce();
|
||||
expect(steerActiveSessions.mock.calls[0][0]).toContain("📣 **New feedback**");
|
||||
expect(steerActiveSessions.mock.calls[0][0]).toContain("Please adjust the active step");
|
||||
@@ -3130,33 +3141,37 @@ describe("Real-time steering injection", () => {
|
||||
it("queues step-session steering comments for the next prompt when no step session is active", async () => {
|
||||
const store = createMockStore();
|
||||
const executor = new TaskExecutor(store, "/tmp/test");
|
||||
const steerActiveSessions = vi.fn().mockResolvedValue(0);
|
||||
const updateSteeringComments = vi.fn();
|
||||
const markSteeringCommentsDelivered = vi.fn();
|
||||
const newComment = {
|
||||
id: "step-session-queued-comment",
|
||||
text: "Please apply this in the next step prompt",
|
||||
createdAt: new Date().toISOString(),
|
||||
author: "user" as const,
|
||||
};
|
||||
|
||||
(executor as any).activeStepExecutors.set("FN-001", {
|
||||
steerActiveSessions,
|
||||
updateSteeringComments,
|
||||
markSteeringCommentsDelivered,
|
||||
const { StepSessionExecutor: ActualStepSessionExecutor } = await vi.importActual<typeof import("../step-session-executor.js")>("../step-session-executor.js");
|
||||
const stepExecutor = new ActualStepSessionExecutor({
|
||||
taskDetail: makeSteeringTask() as any,
|
||||
worktreePath: "/tmp/test",
|
||||
rootDir: "/tmp",
|
||||
settings: {} as any,
|
||||
});
|
||||
const markSteeringCommentsDelivered = vi.spyOn(stepExecutor, "markSteeringCommentsDelivered");
|
||||
|
||||
(executor as any).activeStepExecutors.set("FN-001", stepExecutor);
|
||||
(executor as any).activeStepExecutorSeenSteeringIds.set("FN-001", new Set());
|
||||
|
||||
await (store as any)._triggerAsync("task:updated", makeSteeringTask([newComment]));
|
||||
|
||||
expect(steerActiveSessions).toHaveBeenCalledOnce();
|
||||
expect(updateSteeringComments).toHaveBeenCalledWith([newComment]);
|
||||
expect(markSteeringCommentsDelivered).not.toHaveBeenCalled();
|
||||
expect(store.logEntry).toHaveBeenCalledWith(
|
||||
"FN-001",
|
||||
expect.stringContaining("Comment received mid-execution"),
|
||||
"by user",
|
||||
);
|
||||
|
||||
const nextPromptTask = (stepExecutor as any).consumeTaskDetailForStepPrompt();
|
||||
expect(nextPromptTask.steeringComments).toEqual([newComment]);
|
||||
const laterPromptTask = (stepExecutor as any).consumeTaskDetailForStepPrompt();
|
||||
expect(laterPromptTask.steeringComments).toBeUndefined();
|
||||
});
|
||||
|
||||
it("injects new steering comments via active workflow step session on task:updated", async () => {
|
||||
@@ -3197,6 +3212,52 @@ describe("Real-time steering injection", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("marks new comments seen before injecting and logs once across simultaneous surfaces", async () => {
|
||||
const store = createMockStore();
|
||||
const executor = new TaskExecutor(store, "/tmp/test");
|
||||
const newComment = {
|
||||
id: "shared-surface-comment",
|
||||
text: "Please reach every live surface once",
|
||||
createdAt: new Date().toISOString(),
|
||||
author: "user" as const,
|
||||
};
|
||||
const legacySeen = new Set<string>();
|
||||
const stepSeen = new Set<string>();
|
||||
const workflowSeen = new Set<string>();
|
||||
const legacySteer = vi.fn().mockImplementation(async () => {
|
||||
expect(legacySeen.has(newComment.id)).toBe(true);
|
||||
});
|
||||
const stepSteerActiveSessions = vi.fn().mockImplementation(async () => {
|
||||
expect(stepSeen.has(newComment.id)).toBe(true);
|
||||
return 1;
|
||||
});
|
||||
const workflowSteer = vi.fn().mockImplementation(async () => {
|
||||
expect(workflowSeen.has(newComment.id)).toBe(true);
|
||||
});
|
||||
const markSteeringCommentsDelivered = vi.fn();
|
||||
|
||||
setLegacyActiveSession(executor, legacySteer, legacySeen);
|
||||
(executor as any).activeStepExecutors.set("FN-001", { steerActiveSessions: stepSteerActiveSessions, markSteeringCommentsDelivered });
|
||||
(executor as any).activeStepExecutorSeenSteeringIds.set("FN-001", stepSeen);
|
||||
(executor as any).activeWorkflowStepSessions.set("FN-001", { steer: workflowSteer });
|
||||
(executor as any).activeWorkflowStepSessionSeenSteeringIds.set("FN-001", workflowSeen);
|
||||
|
||||
await (store as any)._triggerAsync("task:updated", makeSteeringTask([newComment]));
|
||||
await (store as any)._triggerAsync("task:updated", makeSteeringTask([newComment]));
|
||||
|
||||
expect(legacySteer).toHaveBeenCalledOnce();
|
||||
expect(stepSteerActiveSessions).toHaveBeenCalledOnce();
|
||||
expect(workflowSteer).toHaveBeenCalledOnce();
|
||||
expect(markSteeringCommentsDelivered).toHaveBeenCalledOnce();
|
||||
expect(markSteeringCommentsDelivered).toHaveBeenCalledWith([newComment.id]);
|
||||
expect(store.logEntry).toHaveBeenCalledTimes(1);
|
||||
expect(store.logEntry).toHaveBeenCalledWith(
|
||||
"FN-001",
|
||||
expect.stringContaining("Comment received mid-execution"),
|
||||
"by user",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not re-inject an already seen active StepSessionExecutor steering comment", async () => {
|
||||
const store = createMockStore();
|
||||
const executor = new TaskExecutor(store, "/tmp/test");
|
||||
@@ -3263,6 +3324,35 @@ describe("Real-time steering injection", () => {
|
||||
expect(steerFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not inject or log when active surfaces receive empty or undefined steering comments", async () => {
|
||||
const store = createMockStore();
|
||||
const executor = new TaskExecutor(store, "/tmp/test");
|
||||
const legacySteer = vi.fn().mockResolvedValue(undefined);
|
||||
const stepSteerActiveSessions = vi.fn().mockResolvedValue(1);
|
||||
const workflowSteer = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
setLegacyActiveSession(executor, legacySteer);
|
||||
(executor as any).activeStepExecutors.set("FN-001", {
|
||||
steerActiveSessions: stepSteerActiveSessions,
|
||||
updateSteeringComments: vi.fn(),
|
||||
});
|
||||
(executor as any).activeStepExecutorSeenSteeringIds.set("FN-001", new Set());
|
||||
(executor as any).activeWorkflowStepSessions.set("FN-001", { steer: workflowSteer });
|
||||
(executor as any).activeWorkflowStepSessionSeenSteeringIds.set("FN-001", new Set());
|
||||
|
||||
await (store as any)._triggerAsync("task:updated", { ...makeSteeringTask(), steeringComments: undefined });
|
||||
await (store as any)._triggerAsync("task:updated", makeSteeringTask([]));
|
||||
|
||||
expect(legacySteer).not.toHaveBeenCalled();
|
||||
expect(stepSteerActiveSessions).not.toHaveBeenCalled();
|
||||
expect(workflowSteer).not.toHaveBeenCalled();
|
||||
expect(store.logEntry).not.toHaveBeenCalledWith(
|
||||
"FN-001",
|
||||
expect.stringContaining("Comment received mid-execution"),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not inject steering comments for tasks without an active injection target", async () => {
|
||||
const store = createMockStore();
|
||||
new TaskExecutor(store, "/tmp/test");
|
||||
|
||||
Reference in New Issue
Block a user