refactor: unify interrupt handling in Confluence and Jira tools

Refactored the create, delete, and update functions in Confluence and Jira tools to utilize a consistent InterruptResult interface with specific context types. This change enhances code clarity and maintains uniformity in handling user approvals across different tools by integrating the useHitlDecision hook for decision dispatching.
This commit is contained in:
Anish Sarkar 2026-04-13 20:20:38 +05:30
parent ea7bcebcd0
commit f844c3288c
6 changed files with 102 additions and 266 deletions

View file

@ -6,38 +6,26 @@ import { useCallback, useEffect, useState } from "react";
import { TextShimmerLoader } from "@/components/prompt-kit/loader";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { isInterruptResult, useHitlDecision } from "@/lib/hitl";
import type { InterruptResult, HitlDecision } from "@/lib/hitl";
import { useHitlPhase } from "@/hooks/use-hitl-phase";
interface InterruptResult {
__interrupt__: true;
__decided__?: "approve" | "reject";
__completed__?: boolean;
action_requests: Array<{
interface DeleteConfluencePageInterruptContext {
account?: {
id: number;
name: string;
args: Record<string, unknown>;
}>;
review_configs: Array<{
action_name: string;
allowed_decisions: Array<"approve" | "reject">;
}>;
interrupt_type?: string;
context?: {
account?: {
id: number;
name: string;
base_url: string;
auth_expired?: boolean;
};
page?: {
page_id: string;
page_title: string;
space_id: string;
connector_id?: number;
document_id?: number;
indexed_at?: string;
};
error?: string;
base_url: string;
auth_expired?: boolean;
};
page?: {
page_id: string;
page_title: string;
space_id: string;
connector_id?: number;
document_id?: number;
indexed_at?: string;
};
error?: string;
}
interface SuccessResult {
@ -77,7 +65,7 @@ interface InsufficientPermissionsResult {
}
type DeleteConfluencePageResult =
| InterruptResult
| InterruptResult<DeleteConfluencePageInterruptContext>
| SuccessResult
| ErrorResult
| NotFoundResult
@ -85,15 +73,6 @@ type DeleteConfluencePageResult =
| AuthErrorResult
| InsufficientPermissionsResult;
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" &&
@ -145,12 +124,8 @@ function ApprovalCard({
interruptData,
onDecision,
}: {
interruptData: InterruptResult;
onDecision: (decision: {
type: "approve" | "reject";
message?: string;
edited_action?: { name: string; args: Record<string, unknown> };
}) => void;
interruptData: InterruptResult<DeleteConfluencePageInterruptContext>;
onDecision: (decision: HitlDecision) => void;
}) {
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
const [deleteFromKb, setDeleteFromKb] = useState(false);
@ -402,18 +377,15 @@ export const DeleteConfluencePageToolUI = ({
{ page_title_or_id: string; delete_from_kb?: boolean },
DeleteConfluencePageResult
>) => {
const { dispatch } = useHitlDecision();
if (!result) return null;
if (isInterruptResult(result)) {
return (
<ApprovalCard
interruptData={result}
onDecision={(decision) => {
const event = new CustomEvent("hitl-decision", {
detail: { decisions: [decision] },
});
window.dispatchEvent(event);
}}
interruptData={result as InterruptResult<DeleteConfluencePageInterruptContext>}
onDecision={(decision) => dispatch([decision])}
/>
);
}