mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-04 22:02:16 +02:00
refactor: unify interrupt handling in Dropbox and Google Drive tools
Refactored the create and delete file functionalities in Dropbox and Google Drive tools to utilize a consistent InterruptResult interface with specific context types. This change enhances code clarity and maintains uniformity in handling user approvals by integrating the useHitlDecision hook for decision dispatching.
This commit is contained in:
parent
f844c3288c
commit
71cd04b05e
4 changed files with 50 additions and 145 deletions
|
|
@ -16,6 +16,8 @@ import {
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
||||||
|
import { isInterruptResult, useHitlDecision } from "@/lib/hitl";
|
||||||
|
import type { InterruptResult, HitlDecision } from "@/lib/hitl";
|
||||||
|
|
||||||
interface DropboxAccount {
|
interface DropboxAccount {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -29,21 +31,11 @@ interface SupportedType {
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InterruptResult {
|
interface DropboxCreateFileContext {
|
||||||
__interrupt__: true;
|
accounts?: DropboxAccount[];
|
||||||
__decided__?: "approve" | "reject" | "edit";
|
parent_folders?: Record<number, Array<{ folder_path: string; name: string }>>;
|
||||||
__completed__?: boolean;
|
supported_types?: SupportedType[];
|
||||||
action_requests: Array<{ name: string; args: Record<string, unknown> }>;
|
error?: string;
|
||||||
review_configs: Array<{
|
|
||||||
action_name: string;
|
|
||||||
allowed_decisions: Array<"approve" | "edit" | "reject">;
|
|
||||||
}>;
|
|
||||||
context?: {
|
|
||||||
accounts?: DropboxAccount[];
|
|
||||||
parent_folders?: Record<number, Array<{ folder_path: string; name: string }>>;
|
|
||||||
supported_types?: SupportedType[];
|
|
||||||
error?: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SuccessResult {
|
interface SuccessResult {
|
||||||
|
|
@ -65,16 +57,7 @@ interface AuthErrorResult {
|
||||||
connector_type?: string;
|
connector_type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateDropboxFileResult = InterruptResult | SuccessResult | ErrorResult | AuthErrorResult;
|
type CreateDropboxFileResult = InterruptResult<DropboxCreateFileContext> | SuccessResult | ErrorResult | AuthErrorResult;
|
||||||
|
|
||||||
function isInterruptResult(result: unknown): result is InterruptResult {
|
|
||||||
return (
|
|
||||||
typeof result === "object" &&
|
|
||||||
result !== null &&
|
|
||||||
"__interrupt__" in result &&
|
|
||||||
(result as InterruptResult).__interrupt__ === true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isErrorResult(result: unknown): result is ErrorResult {
|
function isErrorResult(result: unknown): result is ErrorResult {
|
||||||
return (
|
return (
|
||||||
|
|
@ -100,12 +83,8 @@ function ApprovalCard({
|
||||||
onDecision,
|
onDecision,
|
||||||
}: {
|
}: {
|
||||||
args: { name: string; file_type?: string; content?: string };
|
args: { name: string; file_type?: string; content?: string };
|
||||||
interruptData: InterruptResult;
|
interruptData: InterruptResult<DropboxCreateFileContext>;
|
||||||
onDecision: (decision: {
|
onDecision: (decision: HitlDecision) => void;
|
||||||
type: "approve" | "reject" | "edit";
|
|
||||||
message?: string;
|
|
||||||
edited_action?: { name: string; args: Record<string, unknown> };
|
|
||||||
}) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
||||||
const [isPanelOpen, setIsPanelOpen] = useState(false);
|
const [isPanelOpen, setIsPanelOpen] = useState(false);
|
||||||
|
|
@ -455,17 +434,14 @@ export const CreateDropboxFileToolUI = ({
|
||||||
{ name: string; file_type?: string; content?: string },
|
{ name: string; file_type?: string; content?: string },
|
||||||
CreateDropboxFileResult
|
CreateDropboxFileResult
|
||||||
>) => {
|
>) => {
|
||||||
|
const { dispatch } = useHitlDecision();
|
||||||
if (!result) return null;
|
if (!result) return null;
|
||||||
if (isInterruptResult(result)) {
|
if (isInterruptResult(result)) {
|
||||||
return (
|
return (
|
||||||
<ApprovalCard
|
<ApprovalCard
|
||||||
args={args}
|
args={args}
|
||||||
interruptData={result}
|
interruptData={result as InterruptResult<DropboxCreateFileContext>}
|
||||||
onDecision={(decision) => {
|
onDecision={(decision) => dispatch([decision])}
|
||||||
window.dispatchEvent(
|
|
||||||
new CustomEvent("hitl-decision", { detail: { decisions: [decision] } })
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import { TextShimmerLoader } from "@/components/prompt-kit/loader";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
||||||
|
import { isInterruptResult, useHitlDecision } from "@/lib/hitl";
|
||||||
|
import type { InterruptResult, HitlDecision } from "@/lib/hitl";
|
||||||
|
|
||||||
interface DropboxAccount {
|
interface DropboxAccount {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -22,13 +24,10 @@ interface DropboxFile {
|
||||||
document_id?: number;
|
document_id?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InterruptResult {
|
interface DropboxTrashFileContext {
|
||||||
__interrupt__: true;
|
account?: DropboxAccount;
|
||||||
__decided__?: "approve" | "reject";
|
file?: DropboxFile;
|
||||||
__completed__?: boolean;
|
error?: string;
|
||||||
action_requests: Array<{ name: string; args: Record<string, unknown> }>;
|
|
||||||
review_configs: Array<{ action_name: string; allowed_decisions: Array<"approve" | "reject"> }>;
|
|
||||||
context?: { account?: DropboxAccount; file?: DropboxFile; error?: string };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SuccessResult {
|
interface SuccessResult {
|
||||||
|
|
@ -52,20 +51,12 @@ interface AuthErrorResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteDropboxFileResult =
|
type DeleteDropboxFileResult =
|
||||||
| InterruptResult
|
| InterruptResult<DropboxTrashFileContext>
|
||||||
| SuccessResult
|
| SuccessResult
|
||||||
| ErrorResult
|
| ErrorResult
|
||||||
| NotFoundResult
|
| NotFoundResult
|
||||||
| AuthErrorResult;
|
| AuthErrorResult;
|
||||||
|
|
||||||
function isInterruptResult(result: unknown): result is InterruptResult {
|
|
||||||
return (
|
|
||||||
typeof result === "object" &&
|
|
||||||
result !== null &&
|
|
||||||
"__interrupt__" in result &&
|
|
||||||
(result as InterruptResult).__interrupt__ === true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function isErrorResult(result: unknown): result is ErrorResult {
|
function isErrorResult(result: unknown): result is ErrorResult {
|
||||||
return (
|
return (
|
||||||
typeof result === "object" &&
|
typeof result === "object" &&
|
||||||
|
|
@ -95,12 +86,8 @@ function ApprovalCard({
|
||||||
interruptData,
|
interruptData,
|
||||||
onDecision,
|
onDecision,
|
||||||
}: {
|
}: {
|
||||||
interruptData: InterruptResult;
|
interruptData: InterruptResult<DropboxTrashFileContext>;
|
||||||
onDecision: (decision: {
|
onDecision: (decision: HitlDecision) => void;
|
||||||
type: "approve" | "reject";
|
|
||||||
message?: string;
|
|
||||||
edited_action?: { name: string; args: Record<string, unknown> };
|
|
||||||
}) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
||||||
const [deleteFromKb, setDeleteFromKb] = useState(false);
|
const [deleteFromKb, setDeleteFromKb] = useState(false);
|
||||||
|
|
@ -308,16 +295,13 @@ export const DeleteDropboxFileToolUI = ({
|
||||||
{ file_name: string; delete_from_kb?: boolean },
|
{ file_name: string; delete_from_kb?: boolean },
|
||||||
DeleteDropboxFileResult
|
DeleteDropboxFileResult
|
||||||
>) => {
|
>) => {
|
||||||
|
const { dispatch } = useHitlDecision();
|
||||||
if (!result) return null;
|
if (!result) return null;
|
||||||
if (isInterruptResult(result)) {
|
if (isInterruptResult(result)) {
|
||||||
return (
|
return (
|
||||||
<ApprovalCard
|
<ApprovalCard
|
||||||
interruptData={result}
|
interruptData={result as InterruptResult<DropboxTrashFileContext>}
|
||||||
onDecision={(decision) => {
|
onDecision={(decision) => dispatch([decision])}
|
||||||
window.dispatchEvent(
|
|
||||||
new CustomEvent("hitl-decision", { detail: { decisions: [decision] } })
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import {
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
||||||
|
import { isInterruptResult, useHitlDecision } from "@/lib/hitl";
|
||||||
|
import type { InterruptResult, HitlDecision } from "@/lib/hitl";
|
||||||
|
|
||||||
interface GoogleDriveAccount {
|
interface GoogleDriveAccount {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -23,24 +25,11 @@ interface GoogleDriveAccount {
|
||||||
auth_expired?: boolean;
|
auth_expired?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InterruptResult {
|
interface DriveCreateFileContext {
|
||||||
__interrupt__: true;
|
accounts?: GoogleDriveAccount[];
|
||||||
__decided__?: "approve" | "reject" | "edit";
|
supported_types?: string[];
|
||||||
__completed__?: boolean;
|
parent_folders?: Record<number, Array<{ folder_id: string; name: string }>>;
|
||||||
action_requests: Array<{
|
error?: string;
|
||||||
name: string;
|
|
||||||
args: Record<string, unknown>;
|
|
||||||
}>;
|
|
||||||
review_configs: Array<{
|
|
||||||
action_name: string;
|
|
||||||
allowed_decisions: Array<"approve" | "edit" | "reject">;
|
|
||||||
}>;
|
|
||||||
context?: {
|
|
||||||
accounts?: GoogleDriveAccount[];
|
|
||||||
supported_types?: string[];
|
|
||||||
parent_folders?: Record<number, Array<{ folder_id: string; name: string }>>;
|
|
||||||
error?: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SuccessResult {
|
interface SuccessResult {
|
||||||
|
|
@ -69,21 +58,12 @@ interface AuthErrorResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateGoogleDriveFileResult =
|
type CreateGoogleDriveFileResult =
|
||||||
| InterruptResult
|
| InterruptResult<DriveCreateFileContext>
|
||||||
| SuccessResult
|
| SuccessResult
|
||||||
| ErrorResult
|
| ErrorResult
|
||||||
| InsufficientPermissionsResult
|
| InsufficientPermissionsResult
|
||||||
| AuthErrorResult;
|
| AuthErrorResult;
|
||||||
|
|
||||||
function isInterruptResult(result: unknown): result is InterruptResult {
|
|
||||||
return (
|
|
||||||
typeof result === "object" &&
|
|
||||||
result !== null &&
|
|
||||||
"__interrupt__" in result &&
|
|
||||||
(result as InterruptResult).__interrupt__ === true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isErrorResult(result: unknown): result is ErrorResult {
|
function isErrorResult(result: unknown): result is ErrorResult {
|
||||||
return (
|
return (
|
||||||
typeof result === "object" &&
|
typeof result === "object" &&
|
||||||
|
|
@ -122,12 +102,8 @@ function ApprovalCard({
|
||||||
onDecision,
|
onDecision,
|
||||||
}: {
|
}: {
|
||||||
args: { name: string; file_type: string; content?: string };
|
args: { name: string; file_type: string; content?: string };
|
||||||
interruptData: InterruptResult;
|
interruptData: InterruptResult<DriveCreateFileContext>;
|
||||||
onDecision: (decision: {
|
onDecision: (decision: HitlDecision) => void;
|
||||||
type: "approve" | "reject" | "edit";
|
|
||||||
message?: string;
|
|
||||||
edited_action?: { name: string; args: Record<string, unknown> };
|
|
||||||
}) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
||||||
const [isPanelOpen, setIsPanelOpen] = useState(false);
|
const [isPanelOpen, setIsPanelOpen] = useState(false);
|
||||||
|
|
@ -499,18 +475,15 @@ export const CreateGoogleDriveFileToolUI = ({
|
||||||
{ name: string; file_type: string; content?: string },
|
{ name: string; file_type: string; content?: string },
|
||||||
CreateGoogleDriveFileResult
|
CreateGoogleDriveFileResult
|
||||||
>) => {
|
>) => {
|
||||||
|
const { dispatch } = useHitlDecision();
|
||||||
if (!result) return null;
|
if (!result) return null;
|
||||||
|
|
||||||
if (isInterruptResult(result)) {
|
if (isInterruptResult(result)) {
|
||||||
return (
|
return (
|
||||||
<ApprovalCard
|
<ApprovalCard
|
||||||
args={args}
|
args={args}
|
||||||
interruptData={result}
|
interruptData={result as InterruptResult<DriveCreateFileContext>}
|
||||||
onDecision={(decision) => {
|
onDecision={(decision) => dispatch([decision])}
|
||||||
window.dispatchEvent(
|
|
||||||
new CustomEvent("hitl-decision", { detail: { decisions: [decision] } })
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import { TextShimmerLoader } from "@/components/prompt-kit/loader";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
import { useHitlPhase } from "@/hooks/use-hitl-phase";
|
||||||
|
import { isInterruptResult, useHitlDecision } from "@/lib/hitl";
|
||||||
|
import type { InterruptResult, HitlDecision } from "@/lib/hitl";
|
||||||
|
|
||||||
interface GoogleDriveAccount {
|
interface GoogleDriveAccount {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -21,23 +23,10 @@ interface GoogleDriveFile {
|
||||||
web_view_link: string;
|
web_view_link: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InterruptResult {
|
interface DriveTrashFileContext {
|
||||||
__interrupt__: true;
|
account?: GoogleDriveAccount;
|
||||||
__decided__?: "approve" | "reject";
|
file?: GoogleDriveFile;
|
||||||
__completed__?: boolean;
|
error?: string;
|
||||||
action_requests: Array<{
|
|
||||||
name: string;
|
|
||||||
args: Record<string, unknown>;
|
|
||||||
}>;
|
|
||||||
review_configs: Array<{
|
|
||||||
action_name: string;
|
|
||||||
allowed_decisions: Array<"approve" | "reject">;
|
|
||||||
}>;
|
|
||||||
context?: {
|
|
||||||
account?: GoogleDriveAccount;
|
|
||||||
file?: GoogleDriveFile;
|
|
||||||
error?: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SuccessResult {
|
interface SuccessResult {
|
||||||
|
|
@ -77,7 +66,7 @@ interface AuthErrorResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteGoogleDriveFileResult =
|
type DeleteGoogleDriveFileResult =
|
||||||
| InterruptResult
|
| InterruptResult<DriveTrashFileContext>
|
||||||
| SuccessResult
|
| SuccessResult
|
||||||
| WarningResult
|
| WarningResult
|
||||||
| ErrorResult
|
| ErrorResult
|
||||||
|
|
@ -85,15 +74,6 @@ type DeleteGoogleDriveFileResult =
|
||||||
| InsufficientPermissionsResult
|
| InsufficientPermissionsResult
|
||||||
| AuthErrorResult;
|
| AuthErrorResult;
|
||||||
|
|
||||||
function isInterruptResult(result: unknown): result is InterruptResult {
|
|
||||||
return (
|
|
||||||
typeof result === "object" &&
|
|
||||||
result !== null &&
|
|
||||||
"__interrupt__" in result &&
|
|
||||||
(result as InterruptResult).__interrupt__ === true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isErrorResult(result: unknown): result is ErrorResult {
|
function isErrorResult(result: unknown): result is ErrorResult {
|
||||||
return (
|
return (
|
||||||
typeof result === "object" &&
|
typeof result === "object" &&
|
||||||
|
|
@ -151,12 +131,8 @@ function ApprovalCard({
|
||||||
interruptData,
|
interruptData,
|
||||||
onDecision,
|
onDecision,
|
||||||
}: {
|
}: {
|
||||||
interruptData: InterruptResult;
|
interruptData: InterruptResult<DriveTrashFileContext>;
|
||||||
onDecision: (decision: {
|
onDecision: (decision: HitlDecision) => void;
|
||||||
type: "approve" | "reject";
|
|
||||||
message?: string;
|
|
||||||
edited_action?: { name: string; args: Record<string, unknown> };
|
|
||||||
}) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
|
||||||
const [deleteFromKb, setDeleteFromKb] = useState(false);
|
const [deleteFromKb, setDeleteFromKb] = useState(false);
|
||||||
|
|
@ -416,18 +392,14 @@ export const DeleteGoogleDriveFileToolUI = ({
|
||||||
{ file_name: string; delete_from_kb?: boolean },
|
{ file_name: string; delete_from_kb?: boolean },
|
||||||
DeleteGoogleDriveFileResult
|
DeleteGoogleDriveFileResult
|
||||||
>) => {
|
>) => {
|
||||||
|
const { dispatch } = useHitlDecision();
|
||||||
if (!result) return null;
|
if (!result) return null;
|
||||||
|
|
||||||
if (isInterruptResult(result)) {
|
if (isInterruptResult(result)) {
|
||||||
return (
|
return (
|
||||||
<ApprovalCard
|
<ApprovalCard
|
||||||
interruptData={result}
|
interruptData={result as InterruptResult<DriveTrashFileContext>}
|
||||||
onDecision={(decision) => {
|
onDecision={(decision) => dispatch([decision])}
|
||||||
const event = new CustomEvent("hitl-decision", {
|
|
||||||
detail: { decisions: [decision] },
|
|
||||||
});
|
|
||||||
window.dispatchEvent(event);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue