111 lines
3.9 KiB
TypeScript
111 lines
3.9 KiB
TypeScript
import { createNotesApiClient } from "@/lib/api-helpers";
|
|
import { RETRY_WHEN_ONLINE_MESSAGE, withMutationRetry } from "@/lib/mutation-retry";
|
|
import type { AgentTimelineItem, ApprovalQueueItem, NoteAgentActionDoc, NoteAgentActionListResponse } from "@/lib/types";
|
|
|
|
|
|
function toSeverity(actionType: NoteAgentActionDoc["actionType"]): ApprovalQueueItem["severity"] {
|
|
if (actionType === "update" || actionType === "extract_tasks") {
|
|
return "medium";
|
|
}
|
|
|
|
if (actionType === "attach_citation") {
|
|
return "low";
|
|
}
|
|
|
|
return "high";
|
|
}
|
|
|
|
function toTimelineItem(action: NoteAgentActionDoc): AgentTimelineItem {
|
|
return {
|
|
id: action.id,
|
|
actor: action.actorId,
|
|
action: `${action.actorType} ${action.actionType.replaceAll("_", " ")}`,
|
|
timestamp: action.updatedAt,
|
|
status: action.state,
|
|
summary: action.afterSummary ?? action.reason ?? action.toolName ?? action.actionType,
|
|
};
|
|
}
|
|
|
|
function toApprovalQueueItem(action: NoteAgentActionDoc): ApprovalQueueItem {
|
|
return {
|
|
id: action.id,
|
|
title: action.afterSummary ?? action.reason ?? `${action.actionType} proposal`,
|
|
owner: action.actorId,
|
|
severity: toSeverity(action.actionType),
|
|
status: action.state,
|
|
noteId: action.noteId,
|
|
workspaceId: action.workspaceId,
|
|
before: action.beforeSummary,
|
|
after: action.afterSummary,
|
|
};
|
|
}
|
|
|
|
async function updateAgentActionState(
|
|
id: string,
|
|
workspaceId: string,
|
|
state: "approved" | "rejected",
|
|
reviewNote?: string,
|
|
): Promise<NoteAgentActionDoc> {
|
|
const api = createNotesApiClient();
|
|
const path = `/note-agent-actions/${encodeURIComponent(id)}?workspaceId=${encodeURIComponent(workspaceId)}`;
|
|
|
|
return withMutationRetry({
|
|
run: () => api.fetch<NoteAgentActionDoc>(path, {
|
|
method: "PATCH",
|
|
body: JSON.stringify({
|
|
state,
|
|
reviewedAt: new Date().toISOString(),
|
|
...(reviewNote ? { reviewNote } : {}),
|
|
}),
|
|
}),
|
|
offlineMessage: RETRY_WHEN_ONLINE_MESSAGE,
|
|
});
|
|
}
|
|
|
|
export async function listApprovalQueue(): Promise<ApprovalQueueItem[]> {
|
|
const api = createNotesApiClient();
|
|
const response = await api.fetch<NoteAgentActionListResponse>("/note-agent-actions/pending");
|
|
return response.items
|
|
.sort((a: NoteAgentActionDoc, b: NoteAgentActionDoc) => b.updatedAt.localeCompare(a.updatedAt))
|
|
.map(toApprovalQueueItem);
|
|
}
|
|
|
|
export async function listAgentTimeline(noteId?: string): Promise<AgentTimelineItem[]> {
|
|
const api = createNotesApiClient();
|
|
const response = await api.fetch<NoteAgentActionListResponse>("/note-agent-actions/pending");
|
|
return response.items
|
|
.filter((action: NoteAgentActionDoc) => (noteId ? action.noteId === noteId : true))
|
|
.sort((a: NoteAgentActionDoc, b: NoteAgentActionDoc) => b.updatedAt.localeCompare(a.updatedAt))
|
|
.map(toTimelineItem);
|
|
}
|
|
|
|
export async function approveReviewItem(item: ApprovalQueueItem, reviewNote?: string): Promise<ApprovalQueueItem> {
|
|
const updated = await updateAgentActionState(item.id, item.workspaceId, "approved", reviewNote);
|
|
return toApprovalQueueItem(updated);
|
|
}
|
|
|
|
export async function rejectReviewItem(item: ApprovalQueueItem, reviewNote?: string): Promise<ApprovalQueueItem> {
|
|
const updated = await updateAgentActionState(item.id, item.workspaceId, "rejected", reviewNote);
|
|
return toApprovalQueueItem(updated);
|
|
}
|
|
|
|
export async function batchReviewItems(
|
|
items: ApprovalQueueItem[],
|
|
state: "approved" | "rejected",
|
|
reviewNote?: string,
|
|
): Promise<{ updated: number; total: number }> {
|
|
const api = createNotesApiClient();
|
|
const result = await withMutationRetry({
|
|
run: () => api.fetch<{ updated: number; total: number }>("/note-agent-actions/batch-review", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
ids: items.map((item) => ({ id: item.id, workspaceId: item.workspaceId })),
|
|
state,
|
|
...(reviewNote ? { reviewNote } : {}),
|
|
}),
|
|
}),
|
|
offlineMessage: RETRY_WHEN_ONLINE_MESSAGE,
|
|
});
|
|
return result;
|
|
}
|