@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.
@@ -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
- const AI_ICON_GIF_URL = new URL("/images/ai-icon.gif", PROD_CHATBOT_URL).toString();
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: AI_ICON_GIF_URL,
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};\n\nconst AI_ICON_GIF_URL = new URL(\n \"/images/ai-icon.gif\",\n PROD_CHATBOT_URL,\n).toString();\n\nexport function AiIcon({ width = 24, height = 24 }: AiIconProps) {\n return (\n <img\n src={AI_ICON_GIF_URL}\n width={width}\n height={height}\n alt=\"\"\n aria-hidden=\"true\"\n draggable={false}\n style={{ display: \"block\" }}\n />\n );\n}\n"],"mappings":";;;;AAOA,MAAM,kBAAkB,IAAI,IAC1B,uBACA,iBACD,CAAC,UAAU;AAEZ,SAAgB,OAAO,EAAE,QAAQ,IAAI,SAAS,MAAmB;AAC/D,QACE,oBAAC;EACC,KAAK;EACE;EACC;EACR,KAAI;EACJ,eAAY;EACZ,WAAW;EACX,OAAO,EAAE,SAAS,SAAS;GAC3B"}
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":";;;;;;;;;;;;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;IAAM,GACpB;GAEjB,EACF,qBAAC;EAAa,OAAO;;GACnB,oBAAC,wBAAW,iBAAyB;GACrC,oBAAC,8BAAiB,iBAA+B;GACjD,oBAAC,iCAAiB,OAAS;;GACd,IACT"}
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.0",
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.4",
41
- "react-dom": "19.2.4",
42
- "zod": "4.1.12"
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
- const AI_ICON_GIF_URL = new URL(
9
- "/images/ai-icon.gif",
10
- PROD_CHATBOT_URL,
11
- ).toString();
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={AI_ICON_GIF_URL}
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
- // reload iframe
328
+ // biome-ignore lint/correctness/noSelfAssign: iframeを再読み込みするため
329
329
  iframe.src = iframe.src;
330
330
  break;
331
331
  case "EXECUTE_CLIENT_TOOL": {