@super_studio/ecforce-ai-agent-react 1.4.0-canary.0 → 1.4.0-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ai-icon.mjs +2 -3
- package/dist/components/ai-icon.mjs.map +1 -1
- package/dist/components/chatbot-sheet.mjs +2 -2
- package/dist/components/chatbot-sheet.mjs.map +1 -1
- package/dist/components/provider/use-chatbot-frame-handler.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/ai-icon.tsx +7 -7
- package/src/components/chatbot-sheet.tsx +2 -2
- package/src/components/provider/use-chatbot-frame-handler.tsx +1 -1
|
@@ -2,10 +2,9 @@ import { PROD_CHATBOT_URL } from "../lib/constants.mjs";
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/ai-icon.tsx
|
|
5
|
-
|
|
6
|
-
function AiIcon({ width = 24, height = 24 }) {
|
|
5
|
+
function AiIcon({ width = 24, height = 24, baseUrl = PROD_CHATBOT_URL }) {
|
|
7
6
|
return /* @__PURE__ */ jsx("img", {
|
|
8
|
-
src:
|
|
7
|
+
src: new URL("/images/ai-icon.gif", baseUrl).toString(),
|
|
9
8
|
width,
|
|
10
9
|
height,
|
|
11
10
|
alt: "",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-icon.mjs","names":[],"sources":["../../src/components/ai-icon.tsx"],"sourcesContent":["import { PROD_CHATBOT_URL } from \"../lib/constants\";\n\ntype AiIconProps = {\n width?: number;\n height?: number;\n
|
|
1
|
+
{"version":3,"file":"ai-icon.mjs","names":[],"sources":["../../src/components/ai-icon.tsx"],"sourcesContent":["import { PROD_CHATBOT_URL } from \"../lib/constants\";\n\ntype AiIconProps = {\n width?: number;\n height?: number;\n baseUrl?: string;\n};\n\nexport function AiIcon({\n width = 24,\n height = 24,\n baseUrl = PROD_CHATBOT_URL,\n}: AiIconProps) {\n return (\n <img\n src={new URL(\"/images/ai-icon.gif\", baseUrl).toString()}\n width={width}\n height={height}\n alt=\"\"\n aria-hidden=\"true\"\n draggable={false}\n style={{ display: \"block\" }}\n />\n );\n}\n"],"mappings":";;;;AAQA,SAAgB,OAAO,EACrB,QAAQ,IACR,SAAS,IACT,UAAU,oBACI;AACd,QACE,oBAAC;EACC,KAAK,IAAI,IAAI,uBAAuB,QAAQ,CAAC,UAAU;EAChD;EACC;EACR,KAAI;EACJ,eAAY;EACZ,WAAW;EACX,OAAO,EAAE,SAAS,SAAS;GAC3B"}
|
|
@@ -6,7 +6,6 @@ import { AiIcon } from "./ai-icon.mjs";
|
|
|
6
6
|
import { _objectWithoutProperties } from "../_virtual/_@oxc-project_runtime@0.103.0/helpers/objectWithoutProperties.mjs";
|
|
7
7
|
import { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from "./sheet.mjs";
|
|
8
8
|
import { Tooltip } from "./tooltip.mjs";
|
|
9
|
-
import React from "react";
|
|
10
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
10
|
|
|
12
11
|
//#region src/components/chatbot-sheet.tsx
|
|
@@ -19,7 +18,8 @@ function ChatbotSheet(_ref) {
|
|
|
19
18
|
content: "AIに質問してみましょう",
|
|
20
19
|
trigger: /* @__PURE__ */ jsx(SheetTrigger, { children: /* @__PURE__ */ jsx(AiIcon, {
|
|
21
20
|
width: 24,
|
|
22
|
-
height: 24
|
|
21
|
+
height: 24,
|
|
22
|
+
baseUrl: props.url
|
|
23
23
|
}) })
|
|
24
24
|
}), /* @__PURE__ */ jsxs(SheetContent, {
|
|
25
25
|
style: sheetStyle,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatbot-sheet.mjs","names":[],"sources":["../../src/components/chatbot-sheet.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport { AiIcon } from \"./ai-icon\";\nimport { ChatbotFrame, type ChatbotFrameProps } from \"./chatbot-frame\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"./sheet\";\nimport { Tooltip } from \"./tooltip\";\n\ntype ChatbotSheetProps = ChatbotFrameProps & {\n sheetStyle?: React.CSSProperties;\n};\n\nexport function ChatbotSheet({ sheetStyle, ...props }: ChatbotSheetProps) {\n return (\n <Sheet>\n <Tooltip\n side=\"top\"\n align=\"end\"\n content=\"AIに質問してみましょう\"\n trigger={\n <SheetTrigger>\n <AiIcon width={24} height={24} />\n </SheetTrigger>\n }\n />\n <SheetContent style={sheetStyle}>\n <SheetTitle>AIに質問してみましょう</SheetTitle>\n <SheetDescription>AIに質問してみましょう</SheetDescription>\n <ChatbotFrame {...props} />\n </SheetContent>\n </Sheet>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"chatbot-sheet.mjs","names":[],"sources":["../../src/components/chatbot-sheet.tsx"],"sourcesContent":["\"use client\";\n\nimport type React from \"react\";\nimport { AiIcon } from \"./ai-icon\";\nimport { ChatbotFrame, type ChatbotFrameProps } from \"./chatbot-frame\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"./sheet\";\nimport { Tooltip } from \"./tooltip\";\n\ntype ChatbotSheetProps = ChatbotFrameProps & {\n sheetStyle?: React.CSSProperties;\n};\n\nexport function ChatbotSheet({ sheetStyle, ...props }: ChatbotSheetProps) {\n return (\n <Sheet>\n <Tooltip\n side=\"top\"\n align=\"end\"\n content=\"AIに質問してみましょう\"\n trigger={\n <SheetTrigger>\n <AiIcon width={24} height={24} baseUrl={props.url} />\n </SheetTrigger>\n }\n />\n <SheetContent style={sheetStyle}>\n <SheetTitle>AIに質問してみましょう</SheetTitle>\n <SheetDescription>AIに質問してみましょう</SheetDescription>\n <ChatbotFrame {...props} />\n </SheetContent>\n </Sheet>\n );\n}\n"],"mappings":";;;;;;;;;;;mBAkB+B;AAA/B,SAAgB,aAAa,MAA6C;KAA7C,EAAE,qBAAe;AAC5C,QACE,qBAAC,oBACC,oBAAC;EACC,MAAK;EACL,OAAM;EACN,SAAQ;EACR,SACE,oBAAC,0BACC,oBAAC;GAAO,OAAO;GAAI,QAAQ;GAAI,SAAS,MAAM;IAAO,GACxC;GAEjB,EACF,qBAAC;EAAa,OAAO;;GACnB,oBAAC,wBAAW,iBAAyB;GACrC,oBAAC,8BAAiB,iBAA+B;GACjD,oBAAC,iCAAiB,OAAS;;GACd,IACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-chatbot-frame-handler.mjs","names":[],"sources":["../../../src/components/provider/use-chatbot-frame-handler.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type {\n ClientToolDefinition,\n ClientToolExecuteRequest,\n RegisteredClientTool,\n} from \"../../lib/client-tools\";\n\nexport type IframeMessage =\n | { type: \"CHATBOT_READY\" }\n | { type: \"CHATBOT_INITIALIZED\" }\n | { type: \"CLOSE_CHATBOT\" }\n | { type: \"EXPAND_CHATBOT\" }\n | { type: \"SHRINK_CHATBOT\" }\n | { type: \"FULLSCREEN_CHATBOT\" }\n | { type: \"EXIT_FULLSCREEN_CHATBOT\" }\n | { type: \"RELOAD_CHATBOT\" }\n | ({\n type: \"EXECUTE_CLIENT_TOOL\";\n } & ClientToolExecuteRequest);\n\nexport type MCP = {\n name: string;\n url: string;\n headers?: Record<string, string>;\n};\n\nexport type InitProps = {\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n};\n\nexport type AppMessageAttachment = {\n /** 添付ファイルの表示名です。 */\n fileName: string;\n /** 添付ファイルの MIME type です。 */\n mediaType: string;\n /** 添付ファイルを取得できる URL です。 */\n url: string;\n};\n\nexport type SendAppMessagePayload = {\n /** チャット上に表示するタイトルです。 */\n title?: string;\n /** ユーザーに表示するメッセージ本文です。 */\n message: string;\n /** UI に表示せず、裏側のコンテキストとして渡すメッセージです。 */\n hiddenMessage?: string;\n /** 新規チャットを開始してから送るかを指定します。 */\n startOnNewChat?: boolean;\n /** メッセージと一緒に渡す添付ファイル一覧です。 */\n attachments?: AppMessageAttachment[];\n /** このメッセージ送信で使用するモデルの alias key です。 */\n model?: string;\n};\n\nexport type ParentMessage =\n | {\n type: \"mcps\";\n mcps: MCP[];\n }\n | {\n type: \"appName\";\n appName: string;\n }\n | {\n type: \"sessionToken\";\n sessionToken: string;\n }\n | {\n type: \"init\";\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n }\n | {\n type: \"appMessage\";\n payload: SendAppMessagePayload;\n }\n | {\n type: \"registerClientTools\";\n tools: ClientToolDefinition[];\n }\n | {\n type: \"unregisterClientTools\";\n names: string[];\n }\n | {\n type: \"clientToolResult\";\n callId: string;\n result?: unknown;\n error?: string;\n };\n\nfunction serializeError(error: unknown) {\n if (error instanceof Error) {\n return error.message;\n }\n\n if (typeof error === \"string\") {\n return error;\n }\n\n return \"Unknown client tool error\";\n}\n\ntype UseChatbotFrameHandlerProps = {\n /** チャットボットの開閉状態を更新します。 */\n setOpen: (open: boolean) => void;\n /** 展開状態を更新します。 */\n setIsExpanded: (expanded: boolean) => void;\n /** フルスクリーン状態を更新します。 */\n setIsFullScreen: (fullScreen: boolean) => void;\n};\n\n/**\n * iframe と親アプリ間のメッセージ送受信を管理し、チャットボット制御 API をまとめます。\n *\n * @returns iframe 初期化、メッセージ送信、Client Tool 登録に使うハンドラ一式を返します。\n *\n * @example\n * ```tsx\n * export function FrameBridge() {\n * const [open, setOpen] = React.useState(false);\n * const [isExpanded, setIsExpanded] = React.useState(false);\n * const [isFullScreen, setIsFullScreen] = React.useState(false);\n * const { setIframeEl, init, sendAppMessage, isReady } =\n * useChatbotFrameHandler({\n * setOpen,\n * setIsExpanded,\n * setIsFullScreen,\n * });\n *\n * React.useEffect(() => {\n * if (isReady) {\n * init({ appName: \"EC Force\" });\n * sendAppMessage({ message: \"在庫を確認したいです\" });\n * }\n * }, [init, isReady, sendAppMessage]);\n *\n * return <iframe ref={setIframeEl} src=\"https://example.com/embed\" />;\n * }\n * ```\n */\nexport function useChatbotFrameHandler({\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n}: UseChatbotFrameHandlerProps) {\n const [iframeEl, setIframeEl] = React.useState<HTMLIFrameElement | null>(\n null,\n );\n const [isReady, setIsReady] = React.useState(false);\n const [isInitialized, setIsInitialized] = React.useState(false);\n const pendingAppMessageRef = React.useRef<SendAppMessagePayload | null>(null);\n const clientToolRegistryRef = React.useRef(\n new Map<string, RegisteredClientTool>(),\n );\n\n // helper to post message to the iframe\n const postMessage = React.useCallback(\n (message: ParentMessage) => {\n if (iframeEl?.contentWindow) {\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"sending message to iframe\", message);\n }\n iframeEl.contentWindow.postMessage(message, \"*\");\n return true;\n }\n return false;\n },\n [iframeEl],\n );\n\n const init = React.useCallback(\n (props: InitProps) => {\n postMessage({\n type: \"init\",\n ...props,\n });\n },\n [postMessage],\n );\n\n const setMcps = React.useCallback(\n (mcps: MCP[]) => {\n postMessage({ type: \"mcps\", mcps });\n },\n [postMessage],\n );\n\n const setAppName = React.useCallback(\n (appName: string) => {\n postMessage({ type: \"appName\", appName });\n },\n [postMessage],\n );\n\n const setSessionToken = React.useCallback(\n (sessionToken: string) => {\n postMessage({ type: \"sessionToken\", sessionToken });\n },\n [postMessage],\n );\n\n const flushPendingAppMessage = React.useCallback(() => {\n const pendingPayload = pendingAppMessageRef.current;\n if (!pendingPayload || !isReady || !isInitialized) {\n return false;\n }\n\n const sent = postMessage({\n type: \"appMessage\",\n payload: pendingPayload,\n });\n\n if (sent) {\n pendingAppMessageRef.current = null;\n }\n\n return sent;\n }, [isInitialized, isReady, postMessage]);\n\n const sendAppMessage = React.useCallback(\n (payload: SendAppMessagePayload) => {\n pendingAppMessageRef.current = {\n ...payload,\n startOnNewChat: payload.startOnNewChat ?? true,\n };\n setOpen(true);\n flushPendingAppMessage();\n },\n [flushPendingAppMessage, setOpen],\n );\n\n React.useEffect(() => {\n flushPendingAppMessage();\n }, [flushPendingAppMessage]);\n\n const registerClientTool = React.useCallback(\n (tool: RegisteredClientTool) => {\n clientToolRegistryRef.current.set(tool.definition.name, tool);\n if (!isReady || !isInitialized) {\n return;\n }\n\n postMessage({\n type: \"registerClientTools\",\n tools: [tool.definition],\n });\n },\n [isInitialized, isReady, postMessage],\n );\n\n const unregisterClientTool = React.useCallback(\n (name: string) => {\n const deleted = clientToolRegistryRef.current.delete(name);\n if (!deleted || !isReady || !isInitialized) {\n return;\n }\n\n postMessage({\n type: \"unregisterClientTools\",\n names: [name],\n });\n },\n [isInitialized, isReady, postMessage],\n );\n\n React.useEffect(() => {\n if (!isReady || !isInitialized) {\n return;\n }\n\n const tools = [...clientToolRegistryRef.current.values()].map(\n (tool) => tool.definition,\n );\n if (tools.length === 0) {\n return;\n }\n\n postMessage({\n type: \"registerClientTools\",\n tools,\n });\n }, [isInitialized, isReady, postMessage]);\n\n // Initialize and setup listeners\n React.useEffect(() => {\n const iframe = iframeEl;\n if (!iframe) {\n return;\n }\n\n const handleMessage = (event: MessageEvent<IframeMessage>) => {\n if (event.source !== iframe.contentWindow) {\n return;\n }\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"iframe message\", event.data);\n }\n // Handle iframe messages\n switch (event.data?.type) {\n case \"CHATBOT_READY\":\n setIsReady(true);\n break;\n case \"CHATBOT_INITIALIZED\":\n setIsInitialized(true);\n break;\n case \"CLOSE_CHATBOT\":\n setOpen(false);\n break;\n case \"EXPAND_CHATBOT\":\n setIsExpanded(true);\n break;\n case \"SHRINK_CHATBOT\":\n setIsExpanded(false);\n break;\n case \"FULLSCREEN_CHATBOT\":\n setIsFullScreen(true);\n break;\n case \"EXIT_FULLSCREEN_CHATBOT\":\n setIsFullScreen(false);\n break;\n case \"RELOAD_CHATBOT\":\n // reload iframe\n iframe.src = iframe.src;\n break;\n case \"EXECUTE_CLIENT_TOOL\": {\n const { callId, name, args } = event.data;\n const tool = clientToolRegistryRef.current.get(name);\n if (!tool) {\n postMessage({\n type: \"clientToolResult\",\n callId,\n error: `Client tool not found: ${name}`,\n });\n break;\n }\n\n void (async () => {\n try {\n const result = await tool.execute(args);\n postMessage({\n type: \"clientToolResult\",\n callId,\n result,\n });\n } catch (error) {\n postMessage({\n type: \"clientToolResult\",\n callId,\n error: serializeError(error),\n });\n }\n })();\n break;\n }\n }\n };\n\n const handleIframeLoad = () => {\n setIsReady(false);\n setIsInitialized(false);\n };\n\n window.addEventListener(\"message\", handleMessage);\n iframe.addEventListener(\"load\", handleIframeLoad);\n\n return () => {\n window.removeEventListener(\"message\", handleMessage);\n iframe.removeEventListener(\"load\", handleIframeLoad);\n };\n }, [iframeEl]); // Run when iframe gets mounted\n\n return {\n init,\n setMcps,\n setAppName,\n setSessionToken,\n sendAppMessage,\n registerClientTool,\n unregisterClientTool,\n setIframeEl,\n isReady,\n isInitialized,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-chatbot-frame-handler.mjs","names":[],"sources":["../../../src/components/provider/use-chatbot-frame-handler.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type {\n ClientToolDefinition,\n ClientToolExecuteRequest,\n RegisteredClientTool,\n} from \"../../lib/client-tools\";\n\nexport type IframeMessage =\n | { type: \"CHATBOT_READY\" }\n | { type: \"CHATBOT_INITIALIZED\" }\n | { type: \"CLOSE_CHATBOT\" }\n | { type: \"EXPAND_CHATBOT\" }\n | { type: \"SHRINK_CHATBOT\" }\n | { type: \"FULLSCREEN_CHATBOT\" }\n | { type: \"EXIT_FULLSCREEN_CHATBOT\" }\n | { type: \"RELOAD_CHATBOT\" }\n | ({\n type: \"EXECUTE_CLIENT_TOOL\";\n } & ClientToolExecuteRequest);\n\nexport type MCP = {\n name: string;\n url: string;\n headers?: Record<string, string>;\n};\n\nexport type InitProps = {\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n};\n\nexport type AppMessageAttachment = {\n /** 添付ファイルの表示名です。 */\n fileName: string;\n /** 添付ファイルの MIME type です。 */\n mediaType: string;\n /** 添付ファイルを取得できる URL です。 */\n url: string;\n};\n\nexport type SendAppMessagePayload = {\n /** チャット上に表示するタイトルです。 */\n title?: string;\n /** ユーザーに表示するメッセージ本文です。 */\n message: string;\n /** UI に表示せず、裏側のコンテキストとして渡すメッセージです。 */\n hiddenMessage?: string;\n /** 新規チャットを開始してから送るかを指定します。 */\n startOnNewChat?: boolean;\n /** メッセージと一緒に渡す添付ファイル一覧です。 */\n attachments?: AppMessageAttachment[];\n /** このメッセージ送信で使用するモデルの alias key です。 */\n model?: string;\n};\n\nexport type ParentMessage =\n | {\n type: \"mcps\";\n mcps: MCP[];\n }\n | {\n type: \"appName\";\n appName: string;\n }\n | {\n type: \"sessionToken\";\n sessionToken: string;\n }\n | {\n type: \"init\";\n mcps?: MCP[];\n appName?: string;\n sessionToken?: string;\n }\n | {\n type: \"appMessage\";\n payload: SendAppMessagePayload;\n }\n | {\n type: \"registerClientTools\";\n tools: ClientToolDefinition[];\n }\n | {\n type: \"unregisterClientTools\";\n names: string[];\n }\n | {\n type: \"clientToolResult\";\n callId: string;\n result?: unknown;\n error?: string;\n };\n\nfunction serializeError(error: unknown) {\n if (error instanceof Error) {\n return error.message;\n }\n\n if (typeof error === \"string\") {\n return error;\n }\n\n return \"Unknown client tool error\";\n}\n\ntype UseChatbotFrameHandlerProps = {\n /** チャットボットの開閉状態を更新します。 */\n setOpen: (open: boolean) => void;\n /** 展開状態を更新します。 */\n setIsExpanded: (expanded: boolean) => void;\n /** フルスクリーン状態を更新します。 */\n setIsFullScreen: (fullScreen: boolean) => void;\n};\n\n/**\n * iframe と親アプリ間のメッセージ送受信を管理し、チャットボット制御 API をまとめます。\n *\n * @returns iframe 初期化、メッセージ送信、Client Tool 登録に使うハンドラ一式を返します。\n *\n * @example\n * ```tsx\n * export function FrameBridge() {\n * const [open, setOpen] = React.useState(false);\n * const [isExpanded, setIsExpanded] = React.useState(false);\n * const [isFullScreen, setIsFullScreen] = React.useState(false);\n * const { setIframeEl, init, sendAppMessage, isReady } =\n * useChatbotFrameHandler({\n * setOpen,\n * setIsExpanded,\n * setIsFullScreen,\n * });\n *\n * React.useEffect(() => {\n * if (isReady) {\n * init({ appName: \"EC Force\" });\n * sendAppMessage({ message: \"在庫を確認したいです\" });\n * }\n * }, [init, isReady, sendAppMessage]);\n *\n * return <iframe ref={setIframeEl} src=\"https://example.com/embed\" />;\n * }\n * ```\n */\nexport function useChatbotFrameHandler({\n setOpen,\n setIsExpanded,\n setIsFullScreen,\n}: UseChatbotFrameHandlerProps) {\n const [iframeEl, setIframeEl] = React.useState<HTMLIFrameElement | null>(\n null,\n );\n const [isReady, setIsReady] = React.useState(false);\n const [isInitialized, setIsInitialized] = React.useState(false);\n const pendingAppMessageRef = React.useRef<SendAppMessagePayload | null>(null);\n const clientToolRegistryRef = React.useRef(\n new Map<string, RegisteredClientTool>(),\n );\n\n // helper to post message to the iframe\n const postMessage = React.useCallback(\n (message: ParentMessage) => {\n if (iframeEl?.contentWindow) {\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"sending message to iframe\", message);\n }\n iframeEl.contentWindow.postMessage(message, \"*\");\n return true;\n }\n return false;\n },\n [iframeEl],\n );\n\n const init = React.useCallback(\n (props: InitProps) => {\n postMessage({\n type: \"init\",\n ...props,\n });\n },\n [postMessage],\n );\n\n const setMcps = React.useCallback(\n (mcps: MCP[]) => {\n postMessage({ type: \"mcps\", mcps });\n },\n [postMessage],\n );\n\n const setAppName = React.useCallback(\n (appName: string) => {\n postMessage({ type: \"appName\", appName });\n },\n [postMessage],\n );\n\n const setSessionToken = React.useCallback(\n (sessionToken: string) => {\n postMessage({ type: \"sessionToken\", sessionToken });\n },\n [postMessage],\n );\n\n const flushPendingAppMessage = React.useCallback(() => {\n const pendingPayload = pendingAppMessageRef.current;\n if (!pendingPayload || !isReady || !isInitialized) {\n return false;\n }\n\n const sent = postMessage({\n type: \"appMessage\",\n payload: pendingPayload,\n });\n\n if (sent) {\n pendingAppMessageRef.current = null;\n }\n\n return sent;\n }, [isInitialized, isReady, postMessage]);\n\n const sendAppMessage = React.useCallback(\n (payload: SendAppMessagePayload) => {\n pendingAppMessageRef.current = {\n ...payload,\n startOnNewChat: payload.startOnNewChat ?? true,\n };\n setOpen(true);\n flushPendingAppMessage();\n },\n [flushPendingAppMessage, setOpen],\n );\n\n React.useEffect(() => {\n flushPendingAppMessage();\n }, [flushPendingAppMessage]);\n\n const registerClientTool = React.useCallback(\n (tool: RegisteredClientTool) => {\n clientToolRegistryRef.current.set(tool.definition.name, tool);\n if (!isReady || !isInitialized) {\n return;\n }\n\n postMessage({\n type: \"registerClientTools\",\n tools: [tool.definition],\n });\n },\n [isInitialized, isReady, postMessage],\n );\n\n const unregisterClientTool = React.useCallback(\n (name: string) => {\n const deleted = clientToolRegistryRef.current.delete(name);\n if (!deleted || !isReady || !isInitialized) {\n return;\n }\n\n postMessage({\n type: \"unregisterClientTools\",\n names: [name],\n });\n },\n [isInitialized, isReady, postMessage],\n );\n\n React.useEffect(() => {\n if (!isReady || !isInitialized) {\n return;\n }\n\n const tools = [...clientToolRegistryRef.current.values()].map(\n (tool) => tool.definition,\n );\n if (tools.length === 0) {\n return;\n }\n\n postMessage({\n type: \"registerClientTools\",\n tools,\n });\n }, [isInitialized, isReady, postMessage]);\n\n // Initialize and setup listeners\n React.useEffect(() => {\n const iframe = iframeEl;\n if (!iframe) {\n return;\n }\n\n const handleMessage = (event: MessageEvent<IframeMessage>) => {\n if (event.source !== iframe.contentWindow) {\n return;\n }\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"iframe message\", event.data);\n }\n // Handle iframe messages\n switch (event.data?.type) {\n case \"CHATBOT_READY\":\n setIsReady(true);\n break;\n case \"CHATBOT_INITIALIZED\":\n setIsInitialized(true);\n break;\n case \"CLOSE_CHATBOT\":\n setOpen(false);\n break;\n case \"EXPAND_CHATBOT\":\n setIsExpanded(true);\n break;\n case \"SHRINK_CHATBOT\":\n setIsExpanded(false);\n break;\n case \"FULLSCREEN_CHATBOT\":\n setIsFullScreen(true);\n break;\n case \"EXIT_FULLSCREEN_CHATBOT\":\n setIsFullScreen(false);\n break;\n case \"RELOAD_CHATBOT\":\n // biome-ignore lint/correctness/noSelfAssign: iframeを再読み込みするため\n iframe.src = iframe.src;\n break;\n case \"EXECUTE_CLIENT_TOOL\": {\n const { callId, name, args } = event.data;\n const tool = clientToolRegistryRef.current.get(name);\n if (!tool) {\n postMessage({\n type: \"clientToolResult\",\n callId,\n error: `Client tool not found: ${name}`,\n });\n break;\n }\n\n void (async () => {\n try {\n const result = await tool.execute(args);\n postMessage({\n type: \"clientToolResult\",\n callId,\n result,\n });\n } catch (error) {\n postMessage({\n type: \"clientToolResult\",\n callId,\n error: serializeError(error),\n });\n }\n })();\n break;\n }\n }\n };\n\n const handleIframeLoad = () => {\n setIsReady(false);\n setIsInitialized(false);\n };\n\n window.addEventListener(\"message\", handleMessage);\n iframe.addEventListener(\"load\", handleIframeLoad);\n\n return () => {\n window.removeEventListener(\"message\", handleMessage);\n iframe.removeEventListener(\"load\", handleIframeLoad);\n };\n }, [iframeEl]); // Run when iframe gets mounted\n\n return {\n init,\n setMcps,\n setAppName,\n setSessionToken,\n sendAppMessage,\n registerClientTool,\n unregisterClientTool,\n setIframeEl,\n isReady,\n isInitialized,\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@super_studio/ecforce-ai-agent-react",
|
|
3
|
-
"version": "1.4.0-canary.
|
|
3
|
+
"version": "1.4.0-canary.2",
|
|
4
4
|
"main": "./dist/index.mjs",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.mts",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"@types/node": "22.14.0",
|
|
38
38
|
"@types/react": "19.2.7",
|
|
39
39
|
"@types/react-dom": "19.2.3",
|
|
40
|
-
"react": "19.2.
|
|
41
|
-
"react-dom": "19.2.
|
|
42
|
-
"zod": "4.
|
|
40
|
+
"react": "19.2.6",
|
|
41
|
+
"react-dom": "19.2.6",
|
|
42
|
+
"zod": "4.4.3"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"dev": "tsdown --watch",
|
|
@@ -3,17 +3,17 @@ import { PROD_CHATBOT_URL } from "../lib/constants";
|
|
|
3
3
|
type AiIconProps = {
|
|
4
4
|
width?: number;
|
|
5
5
|
height?: number;
|
|
6
|
+
baseUrl?: string;
|
|
6
7
|
};
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export function AiIcon({ width = 24, height = 24 }: AiIconProps) {
|
|
9
|
+
export function AiIcon({
|
|
10
|
+
width = 24,
|
|
11
|
+
height = 24,
|
|
12
|
+
baseUrl = PROD_CHATBOT_URL,
|
|
13
|
+
}: AiIconProps) {
|
|
14
14
|
return (
|
|
15
15
|
<img
|
|
16
|
-
src={
|
|
16
|
+
src={new URL("/images/ai-icon.gif", baseUrl).toString()}
|
|
17
17
|
width={width}
|
|
18
18
|
height={height}
|
|
19
19
|
alt=""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import React from "react";
|
|
3
|
+
import type React from "react";
|
|
4
4
|
import { AiIcon } from "./ai-icon";
|
|
5
5
|
import { ChatbotFrame, type ChatbotFrameProps } from "./chatbot-frame";
|
|
6
6
|
import {
|
|
@@ -25,7 +25,7 @@ export function ChatbotSheet({ sheetStyle, ...props }: ChatbotSheetProps) {
|
|
|
25
25
|
content="AIに質問してみましょう"
|
|
26
26
|
trigger={
|
|
27
27
|
<SheetTrigger>
|
|
28
|
-
<AiIcon width={24} height={24} />
|
|
28
|
+
<AiIcon width={24} height={24} baseUrl={props.url} />
|
|
29
29
|
</SheetTrigger>
|
|
30
30
|
}
|
|
31
31
|
/>
|
|
@@ -325,7 +325,7 @@ export function useChatbotFrameHandler({
|
|
|
325
325
|
setIsFullScreen(false);
|
|
326
326
|
break;
|
|
327
327
|
case "RELOAD_CHATBOT":
|
|
328
|
-
//
|
|
328
|
+
// biome-ignore lint/correctness/noSelfAssign: iframeを再読み込みするため
|
|
329
329
|
iframe.src = iframe.src;
|
|
330
330
|
break;
|
|
331
331
|
case "EXECUTE_CLIENT_TOOL": {
|