mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-12 17:22:38 +02:00
Render HITL approval cards inline in the thinking-steps timeline.
This commit is contained in:
parent
4b2c9f07cd
commit
a8417e3c45
4 changed files with 158 additions and 14 deletions
|
|
@ -6,6 +6,12 @@ export {
|
|||
useHitlBundle,
|
||||
useToolCallIdContext,
|
||||
} from "./bundle-context";
|
||||
export {
|
||||
type HitlRenderTarget,
|
||||
HitlRenderTargetProvider,
|
||||
useHitlRenderTarget,
|
||||
withHitlInTimeline,
|
||||
} from "./render-target";
|
||||
export type {
|
||||
HitlDecision,
|
||||
InterruptActionRequest,
|
||||
|
|
|
|||
48
surfsense_web/lib/hitl/render-target.tsx
Normal file
48
surfsense_web/lib/hitl/render-target.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
"use client";
|
||||
|
||||
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
||||
import { createContext, useContext } from "react";
|
||||
import { isInterruptResult } from "./types";
|
||||
|
||||
/**
|
||||
* Where this tool-call card is currently rendering.
|
||||
*
|
||||
* - ``"body"`` (default) — assistant-ui's ``MessagePrimitive.Parts`` renders
|
||||
* the card inside the message bubble.
|
||||
* - ``"timeline"`` — ``ThinkingStepsDisplay`` renders the SAME component
|
||||
* inline under the matching step row so the HITL approval lives in the
|
||||
* chain-of-thought instead of as a standalone card in the message body.
|
||||
*
|
||||
* The two render targets share one component implementation; the context
|
||||
* lets the body render skip itself when the timeline copy will show the
|
||||
* card, avoiding a double-render.
|
||||
*/
|
||||
export type HitlRenderTarget = "body" | "timeline";
|
||||
|
||||
const HitlRenderTargetContext = createContext<HitlRenderTarget>("body");
|
||||
|
||||
export const HitlRenderTargetProvider = HitlRenderTargetContext.Provider;
|
||||
|
||||
export function useHitlRenderTarget(): HitlRenderTarget {
|
||||
return useContext(HitlRenderTargetContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the body render of a tool-call whose result is a HITL interrupt.
|
||||
* The same component is mounted again inside ``ThinkingStepsDisplay``
|
||||
* with ``HitlRenderTargetProvider value="timeline"`` — that copy renders
|
||||
* normally, so the card "moves" from the message body to the timeline.
|
||||
*
|
||||
* Pure pass-through for non-HITL results AND for the timeline render.
|
||||
*/
|
||||
export function withHitlInTimeline(
|
||||
Component: ToolCallMessagePartComponent
|
||||
): ToolCallMessagePartComponent {
|
||||
const Wrapped: ToolCallMessagePartComponent = (props) => {
|
||||
const target = useHitlRenderTarget();
|
||||
if (target === "body" && isInterruptResult(props.result)) return null;
|
||||
return <Component {...props} />;
|
||||
};
|
||||
Wrapped.displayName = `withHitlInTimeline(${Component.displayName ?? Component.name ?? "ToolUI"})`;
|
||||
return Wrapped;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue