refactor: unify interrupt handling in OneDrive tools

Refactored the create and delete file functionalities in OneDrive 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:
Anish Sarkar 2026-04-13 20:23:03 +05:30
parent 5169d3d56c
commit 041af34820
2 changed files with 24 additions and 65 deletions

View file

@ -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 OneDriveAccount { interface OneDriveAccount {
id: number; id: number;
@ -24,20 +26,10 @@ interface OneDriveAccount {
auth_expired?: boolean; auth_expired?: boolean;
} }
interface InterruptResult { interface OneDriveCreateFileContext {
__interrupt__: true; accounts?: OneDriveAccount[];
__decided__?: "approve" | "reject" | "edit"; parent_folders?: Record<number, Array<{ folder_id: string; name: string }>>;
__completed__?: boolean; error?: string;
action_requests: Array<{ name: string; args: Record<string, unknown> }>;
review_configs: Array<{
action_name: string;
allowed_decisions: Array<"approve" | "edit" | "reject">;
}>;
context?: {
accounts?: OneDriveAccount[];
parent_folders?: Record<number, Array<{ folder_id: string; name: string }>>;
error?: string;
};
} }
interface SuccessResult { interface SuccessResult {
@ -59,16 +51,7 @@ interface AuthErrorResult {
connector_type?: string; connector_type?: string;
} }
type CreateOneDriveFileResult = InterruptResult | SuccessResult | ErrorResult | AuthErrorResult; type CreateOneDriveFileResult = InterruptResult<OneDriveCreateFileContext> | 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 (
@ -94,12 +77,8 @@ function ApprovalCard({
onDecision, onDecision,
}: { }: {
args: { name: string; content?: string }; args: { name: string; content?: string };
interruptData: InterruptResult; interruptData: InterruptResult<OneDriveCreateFileContext>;
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);
@ -434,17 +413,14 @@ export const CreateOneDriveFileToolUI = ({
args, args,
result, result,
}: ToolCallMessagePartProps<{ name: string; content?: string }, CreateOneDriveFileResult>) => { }: ToolCallMessagePartProps<{ name: string; content?: string }, CreateOneDriveFileResult>) => {
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<OneDriveCreateFileContext>}
onDecision={(decision) => { onDecision={(decision) => dispatch([decision])}
window.dispatchEvent(
new CustomEvent("hitl-decision", { detail: { decisions: [decision] } })
);
}}
/> />
); );
} }

View file

@ -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 OneDriveAccount { interface OneDriveAccount {
id: number; id: number;
@ -22,13 +24,10 @@ interface OneDriveFile {
web_url?: string; web_url?: string;
} }
interface InterruptResult { interface OneDriveTrashFileContext {
__interrupt__: true; account?: OneDriveAccount;
__decided__?: "approve" | "reject"; file?: OneDriveFile;
__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?: OneDriveAccount; file?: OneDriveFile; error?: string };
} }
interface SuccessResult { interface SuccessResult {
@ -52,20 +51,11 @@ interface AuthErrorResult {
} }
type DeleteOneDriveFileResult = type DeleteOneDriveFileResult =
| InterruptResult | InterruptResult<OneDriveTrashFileContext>
| 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 +85,8 @@ function ApprovalCard({
interruptData, interruptData,
onDecision, onDecision,
}: { }: {
interruptData: InterruptResult; interruptData: InterruptResult<OneDriveTrashFileContext>;
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);
@ -311,16 +297,13 @@ export const DeleteOneDriveFileToolUI = ({
{ file_name: string; delete_from_kb?: boolean }, { file_name: string; delete_from_kb?: boolean },
DeleteOneDriveFileResult DeleteOneDriveFileResult
>) => { >) => {
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<OneDriveTrashFileContext>}
onDecision={(decision) => { onDecision={(decision) => dispatch([decision])}
window.dispatchEvent(
new CustomEvent("hitl-decision", { detail: { decisions: [decision] } })
);
}}
/> />
); );
} }