refactor: unify interrupt handling in Gmail and Google Calendar tools

Refactored the create, send, update, and delete functionalities in Gmail and Google Calendar 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:22:26 +05:30
parent 1c9c496e01
commit e6065b6793
7 changed files with 92 additions and 278 deletions

View file

@ -9,6 +9,8 @@ import { openHitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";
import { PlateEditor } from "@/components/editor/plate-editor";
import { TextShimmerLoader } from "@/components/prompt-kit/loader";
import { Button } from "@/components/ui/button";
import { isInterruptResult, useHitlDecision } from "@/lib/hitl";
import type { HitlDecision, InterruptResult } from "@/lib/hitl";
import { useHitlPhase } from "@/hooks/use-hitl-phase";
interface GmailAccount {
@ -28,25 +30,12 @@ interface GmailMessage {
document_id: number;
}
interface InterruptResult {
__interrupt__: true;
__decided__?: "approve" | "reject" | "edit";
__completed__?: boolean;
action_requests: Array<{
name: string;
args: Record<string, unknown>;
}>;
review_configs: Array<{
action_name: string;
allowed_decisions: Array<"approve" | "edit" | "reject">;
}>;
context?: {
account?: GmailAccount;
email?: GmailMessage;
draft_id?: string;
existing_body?: string;
error?: string;
};
interface GmailUpdateDraftContext {
account?: GmailAccount;
email?: GmailMessage;
draft_id?: string;
existing_body?: string;
error?: string;
}
interface SuccessResult {
@ -78,22 +67,13 @@ interface InsufficientPermissionsResult {
}
type UpdateGmailDraftResult =
| InterruptResult
| InterruptResult<GmailUpdateDraftContext>
| SuccessResult
| ErrorResult
| NotFoundResult
| InsufficientPermissionsResult
| 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 {
return (
typeof result === "object" &&
@ -143,12 +123,8 @@ function ApprovalCard({
cc?: string;
bcc?: string;
};
interruptData: InterruptResult;
onDecision: (decision: {
type: "approve" | "reject" | "edit";
message?: string;
edited_action?: { name: string; args: Record<string, unknown> };
}) => void;
interruptData: InterruptResult<GmailUpdateDraftContext>;
onDecision: (decision: HitlDecision) => void;
}) {
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
const [isPanelOpen, setIsPanelOpen] = useState(false);
@ -522,20 +498,16 @@ export const UpdateGmailDraftToolUI = ({
},
UpdateGmailDraftResult
>) => {
const { dispatch } = useHitlDecision();
if (!result) return null;
if (isInterruptResult(result)) {
return (
<ApprovalCard
args={args}
interruptData={result}
onDecision={(decision) => {
window.dispatchEvent(
new CustomEvent("hitl-decision", {
detail: { decisions: [decision] },
})
);
}}
interruptData={result as InterruptResult<GmailUpdateDraftContext>}
onDecision={(decision) => dispatch([decision])}
/>
);
}