fix(FN-2149): harden agent reflection error handling
- Update reflection trigger API typing to allow null responses from manual generation - Handle null results in AgentReflectionsTab with a clear insufficient-history toast - Normalize reflection trigger errors to show specific UX for deleted agents and insufficient history - Return a clear 500 error when manual reflection generation yields no reflection payload - Expand dashboard reflection route/UI tests to lock in null and not-found regression behavior
This commit is contained in:
@@ -206,6 +206,62 @@ describe("AgentReflectionsTab", () => {
|
||||
expect(mockedFetchAgentPerformance).toHaveBeenCalledTimes(2); // Initial + refresh
|
||||
});
|
||||
|
||||
it("shows not-enough-history toast when Reflect Now returns null", async () => {
|
||||
mockedTriggerAgentReflection.mockResolvedValue(null);
|
||||
|
||||
render(
|
||||
<AgentReflectionsTab agentId="agent-001" projectId="test-project" addToast={addToast} />
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Reflect Now")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText("Reflect Now"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(addToast).toHaveBeenCalledWith("Not enough history to generate a reflection yet", "error");
|
||||
});
|
||||
});
|
||||
|
||||
it("shows agent-deleted toast when Reflect Now returns agent-not-found", async () => {
|
||||
mockedTriggerAgentReflection.mockRejectedValue(new Error("Agent not found"));
|
||||
|
||||
render(
|
||||
<AgentReflectionsTab agentId="agent-001" projectId="test-project" addToast={addToast} />
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Reflect Now")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText("Reflect Now"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(addToast).toHaveBeenCalledWith("This agent is no longer available. It may have been deleted.", "error");
|
||||
});
|
||||
});
|
||||
|
||||
it("shows not-enough-history toast when Reflect Now fails with insufficient-history error", async () => {
|
||||
mockedTriggerAgentReflection.mockRejectedValue(
|
||||
new Error("Unable to generate reflection — insufficient history or AI unavailable")
|
||||
);
|
||||
|
||||
render(
|
||||
<AgentReflectionsTab agentId="agent-001" projectId="test-project" addToast={addToast} />
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Reflect Now")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText("Reflect Now"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(addToast).toHaveBeenCalledWith("Not enough history to generate a reflection yet", "error");
|
||||
});
|
||||
});
|
||||
|
||||
it("shows error toast when Reflect Now fails", async () => {
|
||||
mockedTriggerAgentReflection.mockRejectedValue(new Error("Service unavailable"));
|
||||
|
||||
|
||||
@@ -72,6 +72,13 @@ function getTriggerLabel(trigger: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function getErrorMessage(err: unknown): string {
|
||||
if (err instanceof Error && err.message) {
|
||||
return err.message;
|
||||
}
|
||||
return String(err);
|
||||
}
|
||||
|
||||
export function AgentReflectionsTab({ agentId, projectId, addToast }: AgentReflectionsTabProps) {
|
||||
const [reflections, setReflections] = useState<AgentReflection[]>([]);
|
||||
const [performance, setPerformance] = useState<AgentPerformanceSummary | null>(null);
|
||||
@@ -103,12 +110,26 @@ export function AgentReflectionsTab({ agentId, projectId, addToast }: AgentRefle
|
||||
const handleReflectNow = async () => {
|
||||
setIsReflecting(true);
|
||||
try {
|
||||
await triggerAgentReflection(agentId, projectId);
|
||||
const reflection = await triggerAgentReflection(agentId, projectId);
|
||||
if (!reflection) {
|
||||
addToast("Not enough history to generate a reflection yet", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
addToast("Reflection generated successfully", "success");
|
||||
setIsLoading(true);
|
||||
await loadData();
|
||||
} catch (err: any) {
|
||||
addToast(`Failed to generate reflection: ${err.message}`, "error");
|
||||
} catch (err: unknown) {
|
||||
const message = getErrorMessage(err);
|
||||
const normalizedMessage = message.toLowerCase();
|
||||
|
||||
if (normalizedMessage.includes("agent not found") || normalizedMessage.includes("not found")) {
|
||||
addToast("This agent is no longer available. It may have been deleted.", "error");
|
||||
} else if (normalizedMessage.includes("insufficient history")) {
|
||||
addToast("Not enough history to generate a reflection yet", "error");
|
||||
} else {
|
||||
addToast(`Failed to generate reflection: ${message}`, "error");
|
||||
}
|
||||
} finally {
|
||||
setIsReflecting(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user