feat: integrate HITL phase management across tool components

- Refactored ApprovalCard in various tools (Gmail, Google Calendar, Google Drive) to utilize the new useHitlPhase hook for improved state management.
- Updated logic to handle tool action phases (pending, processing, complete, rejected) consistently across components, enhancing user feedback during interactions.
- Simplified decision handling by removing direct state management for approval decisions, streamlining the approval process.
- Enhanced UI feedback to reflect the current phase of tool actions, improving user experience during tool interactions.
This commit is contained in:
Anish Sarkar 2026-03-21 11:18:35 +05:30
parent ff6514a99f
commit 9cd2c1f712
19 changed files with 706 additions and 590 deletions

View file

@ -107,6 +107,25 @@ import {
trackChatResponseReceived,
} from "@/lib/posthog/events";
/**
* After a tool produces output, mark any previously-decided interrupt tool
* calls as completed so the ApprovalCard can transition from shimmer to done.
*/
function markInterruptsCompleted(contentParts: Array<{ type: string; result?: unknown }>): void {
for (const part of contentParts) {
if (
part.type === "tool-call" &&
typeof part.result === "object" &&
part.result !== null &&
(part.result as Record<string, unknown>).__interrupt__ === true &&
(part.result as Record<string, unknown>).__decided__ &&
!(part.result as Record<string, unknown>).__completed__
) {
part.result = { ...(part.result as Record<string, unknown>), __completed__: true };
}
}
}
/**
* Extract thinking steps from message content
*/
@ -729,6 +748,7 @@ export default function NewChatPage() {
case "tool-output-available": {
// Update the tool call with its result
updateToolCall(contentPartsState, parsed.toolCallId, { result: parsed.output });
markInterruptsCompleted(contentParts);
// Handle podcast-specific logic
if (parsed.output?.status === "pending" && parsed.output?.podcast_id) {
// Check if this is a podcast tool by looking at the content part
@ -1107,6 +1127,7 @@ export default function NewChatPage() {
updateToolCall(contentPartsState, parsed.toolCallId, {
result: parsed.output,
});
markInterruptsCompleted(contentParts);
setMessages((prev) =>
prev.map((m) =>
m.id === assistantMsgId
@ -1458,6 +1479,7 @@ export default function NewChatPage() {
case "tool-output-available":
updateToolCall(contentPartsState, parsed.toolCallId, { result: parsed.output });
markInterruptsCompleted(contentParts);
if (parsed.output?.status === "pending" && parsed.output?.podcast_id) {
const idx = toolCallIndices.get(parsed.toolCallId);
if (idx !== undefined) {