UNPKG

@assistant-ui/react

Version:

Open-source TypeScript/React library for building production-grade AI chat experiences

149 lines (148 loc) • 5 kB
"use client"; import { tool } from "@assistant-ui/core"; import { c } from "@assistant-ui/tap/react-shim/compiler-runtime"; import { createContext, forwardRef, useContext, useEffect, useId, useRef } from "@assistant-ui/tap/react-shim"; import { useAui } from "@assistant-ui/store"; import { jsx } from "react/jsx-runtime"; import { useComposedRefs } from "radix-ui/internal"; // src/model-context/makeAssistantVisible.tsx const DEFAULT_ACTION_SETTLE_DELAY_MS = 2e3; const MAX_ACTION_SETTLE_DELAY_MS = 2147483647; const waitForSettle = async (settleDelayMs) => { const delay = Number.isFinite(settleDelayMs) && settleDelayMs >= 0 && settleDelayMs <= MAX_ACTION_SETTLE_DELAY_MS ? settleDelayMs : DEFAULT_ACTION_SETTLE_DELAY_MS; if (delay === 0) return; await new Promise((resolve) => setTimeout(resolve, delay)); }; const readActionSettleDelay = (element) => { const value = element.dataset.actionSettleDelay; return value === void 0 || value.trim() === "" ? DEFAULT_ACTION_SETTLE_DELAY_MS : Number(value); }; const click = tool({ parameters: { type: "object", properties: { clickId: { type: "string" } }, required: ["clickId"] }, execute: async ({ clickId }) => { const escapedClickId = CSS.escape(clickId); const el = document.querySelector(`[data-click-id='${escapedClickId}']`); if (el instanceof HTMLElement) { el.click(); await waitForSettle(readActionSettleDelay(el)); return {}; } else return "Element not found"; } }); const setNativeValue = (element, value) => { const prototype = element instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype; const setter = Object.getOwnPropertyDescriptor(prototype, "value")?.set; if (setter) setter.call(element, value); else element.value = value; }; const edit = tool({ parameters: { type: "object", properties: { editId: { type: "string" }, value: { type: "string" } }, required: ["editId", "value"] }, execute: async ({ editId, value }) => { const escapedEditId = CSS.escape(editId); const el = document.querySelector(`[data-edit-id='${escapedEditId}']`); if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) { setNativeValue(el, value); el.dispatchEvent(new Event("input", { bubbles: true })); el.dispatchEvent(new Event("change", { bubbles: true })); await waitForSettle(readActionSettleDelay(el)); return {}; } else return "Element not found"; } }); const ReadableContext = createContext(false); const makeAssistantVisible = (Component, config) => { const settleDelayMs = config?.settleDelayMs ?? DEFAULT_ACTION_SETTLE_DELAY_MS; if (!Number.isFinite(settleDelayMs) || settleDelayMs < 0 || settleDelayMs > MAX_ACTION_SETTLE_DELAY_MS) throw new RangeError(`settleDelayMs must be between 0 and ${MAX_ACTION_SETTLE_DELAY_MS}`); const ReadableComponent = forwardRef((props, outerRef) => { const $ = c(16); const isNestedReadable = useContext(ReadableContext); const clickId = useId(); const componentRef = useRef(null); const aui = useAui(); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = config ?? {}; $[0] = t0; } else t0 = $[0]; const { clickable, editable } = t0; let t1; if ($[1] !== aui.modelContext || $[2] !== isNestedReadable) { t1 = () => aui.modelContext.register({ getModelContext: () => ({ tools: { ...clickable ? { click } : {}, ...editable ? { edit } : {} }, system: !isNestedReadable ? componentRef.current?.outerHTML : void 0 }) }); $[1] = aui.modelContext; $[2] = isNestedReadable; $[3] = t1; } else t1 = $[3]; let t2; if ($[4] !== aui || $[5] !== isNestedReadable) { t2 = [ isNestedReadable, aui, clickable, editable ]; $[4] = aui; $[5] = isNestedReadable; $[6] = t2; } else t2 = $[6]; useEffect(t1, t2); const ref = useComposedRefs(componentRef, outerRef); const t3 = props; let t4; let t5; if ($[7] !== clickId) { t4 = config?.clickable ? { "data-click-id": clickId } : {}; t5 = config?.editable ? { "data-edit-id": clickId } : {}; $[7] = clickId; $[8] = t4; $[9] = t5; } else { t4 = $[8]; t5 = $[9]; } let t6; if ($[10] === Symbol.for("react.memo_cache_sentinel")) { t6 = config?.settleDelayMs !== void 0 && (config.clickable || config.editable) ? { "data-action-settle-delay": settleDelayMs } : {}; $[10] = t6; } else t6 = $[10]; let t7; if ($[11] !== ref || $[12] !== t3 || $[13] !== t4 || $[14] !== t5) { t7 = /* @__PURE__ */ jsx(ReadableContext.Provider, { value: true, children: /* @__PURE__ */ jsx(Component, { ...t3, ...t4, ...t5, ...t6, ref }) }); $[11] = ref; $[12] = t3; $[13] = t4; $[14] = t5; $[15] = t7; } else t7 = $[15]; return t7; }); ReadableComponent.displayName = Component.displayName; return ReadableComponent; }; export { makeAssistantVisible as default, makeAssistantVisible }; //# sourceMappingURL=makeAssistantVisible.js.map