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

@ -15,6 +15,8 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { isInterruptResult, useHitlDecision } from "@/lib/hitl";
import type { InterruptResult, HitlDecision } from "@/lib/hitl";
import { useHitlPhase } from "@/hooks/use-hitl-phase";
interface ConfluenceAccount {
@ -30,24 +32,10 @@ interface ConfluenceSpace {
name: string;
}
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">;
}>;
interrupt_type?: string;
context?: {
accounts?: ConfluenceAccount[];
spaces?: ConfluenceSpace[];
error?: string;
};
interface CreateConfluencePageInterruptContext {
accounts?: ConfluenceAccount[];
spaces?: ConfluenceSpace[];
error?: string;
}
interface SuccessResult {
@ -76,21 +64,12 @@ interface InsufficientPermissionsResult {
}
type CreateConfluencePageResult =
| InterruptResult
| InterruptResult<CreateConfluencePageInterruptContext>
| SuccessResult
| ErrorResult
| 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" &&
@ -124,12 +103,8 @@ function ApprovalCard({
onDecision,
}: {
args: { title: string; content?: string; space_id?: string };
interruptData: InterruptResult;
onDecision: (decision: {
type: "approve" | "reject" | "edit";
message?: string;
edited_action?: { name: string; args: Record<string, unknown> };
}) => void;
interruptData: InterruptResult<CreateConfluencePageInterruptContext>;
onDecision: (decision: HitlDecision) => void;
}) {
const { phase, setProcessing, setRejected } = useHitlPhase(interruptData);
const [isPanelOpen, setIsPanelOpen] = useState(false);
@ -464,18 +439,16 @@ export const CreateConfluencePageToolUI = ({
{ title: string; content?: string; space_id?: string },
CreateConfluencePageResult
>) => {
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<CreateConfluencePageInterruptContext>}
onDecision={(decision) => dispatch([decision])}
/>
);
}