@rizal_ncc/agent-client 1.4.0
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/LICENSE +21 -0
- package/README.md +142 -0
- package/dist/ai-img.svg +54 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +155 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react.cjs +2 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.mjs +600 -0
- package/dist/react.mjs.map +1 -0
- package/dist/style.css +1 -0
- package/dist/types/adapters/react.d.ts +43 -0
- package/dist/types/core/chatbot.d.ts +16 -0
- package/dist/types/core/errors.d.ts +4 -0
- package/dist/types/core/types.d.ts +89 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/lib/recommendation-pagination.d.ts +2 -0
- package/dist/types/lib/tool-results.d.ts +6 -0
- package/dist/types/react.d.ts +3 -0
- package/package.json +72 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.mjs","sources":["../src/lib/recommendation-pagination.ts","../src/adapters/react.tsx"],"sourcesContent":["import type { RecommendationItem } from \"../core/types\";\r\n\r\nfunction asRecommendationItem(value: unknown): RecommendationItem | null {\r\n if (!value || typeof value !== \"object\") {\r\n return null;\r\n }\r\n\r\n const item = value as Partial<RecommendationItem>;\r\n if (typeof item.title !== \"string\" || typeof item.url !== \"string\") {\r\n return null;\r\n }\r\n\r\n return {\r\n id:\r\n typeof item.id === \"number\" ||\r\n typeof item.id === \"string\" ||\r\n item.id === null\r\n ? item.id\r\n : null,\r\n title: item.title,\r\n description: typeof item.description === \"string\" ? item.description : \"\",\r\n url: item.url,\r\n type: typeof item.type === \"string\" ? item.type : \"Course\",\r\n status:\r\n typeof item.status === \"string\" || item.status === null\r\n ? item.status\r\n : null,\r\n progress:\r\n typeof item.progress === \"number\" || item.progress === null\r\n ? item.progress\r\n : null,\r\n is_eligible: Boolean(item.is_eligible),\r\n in_playlist: Boolean(item.in_playlist),\r\n };\r\n}\r\n\r\nexport function mergeRecommendationItems(\r\n current: RecommendationItem[],\r\n incoming: unknown[],\r\n): RecommendationItem[] {\r\n const merged = Array.isArray(current) ? [...current] : [];\r\n\r\n for (const raw of incoming) {\r\n const candidate = asRecommendationItem(raw);\r\n if (!candidate) {\r\n continue;\r\n }\r\n\r\n // misalnya kalo ada duplicate, nanti bakalan di skip/hilang. sementara di allow dulu semua masuk buat ngecek juga sih aowkwk\r\n // const exists = merged.some(\r\n // (existing) =>\r\n // (existing.id !== null && existing.id === candidate.id) ||\r\n // (existing.url && candidate.url && existing.url === candidate.url)\r\n // );\r\n //\r\n // if (!exists) {\r\n // merged.push(candidate);\r\n // }\r\n\r\n merged.push(candidate);\r\n }\r\n\r\n return merged;\r\n}\r\n","import {\r\n type CSSProperties,\r\n useCallback,\r\n useEffect,\r\n useMemo,\r\n useRef,\r\n useState,\r\n type SubmitEvent,\r\n type ReactNode,\r\n} from \"react\";\r\nimport { ChatbotCore } from \"../core/chatbot\";\r\nimport {\r\n extractRecommendationItems,\r\n extractRecommendationOutput,\r\n} from \"../lib/tool-results\";\r\nimport { mergeRecommendationItems } from \"../lib/recommendation-pagination\";\r\nimport type {\r\n AgentMetadata,\r\n ChatMessage,\r\n ChatbotCoreConfig,\r\n ChatbotState,\r\n GenerateResponse,\r\n RespondResponse,\r\n} from \"../core/types\";\r\n\r\nconst EMPTY_METADATA: AgentMetadata = {};\r\n\r\nexport interface UseAiAgentChatResult extends ChatbotState {\r\n sendMessage: (text: string) => Promise<ChatMessage | undefined>;\r\n stop: () => void;\r\n updateMessageById: (\r\n messageId: string,\r\n updater: (message: ChatMessage) => ChatMessage,\r\n ) => void;\r\n}\r\n\r\nexport function useAiAgentChat(\r\n config: ChatbotCoreConfig,\r\n): UseAiAgentChatResult {\r\n const coreRef = useRef<ChatbotCore | null>(null);\r\n const [state, setState] = useState<ChatbotState>({\r\n messages: [],\r\n isLoading: false,\r\n });\r\n\r\n useEffect(() => {\r\n const core = new ChatbotCore(config);\r\n coreRef.current = core;\r\n\r\n const unsubscribe = core.subscribe((nextState) => {\r\n setState(nextState);\r\n });\r\n\r\n return () => {\r\n unsubscribe();\r\n core.destroy();\r\n coreRef.current = null;\r\n };\r\n }, [config]);\r\n\r\n const sendMessage = useCallback(async (text: string) => {\r\n if (!coreRef.current) {\r\n return undefined;\r\n }\r\n return coreRef.current.sendMessage(text);\r\n }, []);\r\n\r\n const stop = useCallback(() => {\r\n if (!coreRef.current) {\r\n return;\r\n }\r\n coreRef.current.stop();\r\n }, []);\r\n\r\n const updateMessageById = useCallback(\r\n (messageId: string, updater: (message: ChatMessage) => ChatMessage) => {\r\n if (!coreRef.current) {\r\n return;\r\n }\r\n coreRef.current.updateMessageById(messageId, updater);\r\n },\r\n [],\r\n );\r\n\r\n return {\r\n ...state,\r\n sendMessage,\r\n stop,\r\n updateMessageById,\r\n };\r\n}\r\n\r\nexport interface AiAgentChatProps {\n generateResponse?: GenerateResponse;\r\n suggestedMessages?: string[];\r\n onMessage?: ChatbotCoreConfig[\"onMessage\"];\r\n onError?: ChatbotCoreConfig[\"onError\"];\r\n baseURL?: string;\r\n accessToken?:\r\n | string\r\n | (() => string | undefined | Promise<string | undefined>);\r\n agent?: string;\r\n metadata?: AgentMetadata;\r\n requestHeaders?: HeadersInit;\r\n respondPath?: string;\r\n headerTitle?: string;\r\n headerDescription?: string;\r\n assistantAvatar?: ReactNode;\r\n assistantAvatarUrl?: string;\r\n assistantInitials?: string;\r\n userInitials?: string;\r\n initials?: boolean;\r\n primaryColor?: string;\r\n primaryForeground?: string;\r\n className?: string;\r\n placeholder?: string;\n sendLabel?: string;\n stopLabel?: string;\n layout?: \"inline\" | \"floating\" | \"dropdown\";\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n panelHeight?: string;\n floatingPosition?: \"bottom-right\" | \"bottom-left\";\n zIndex?: number;\n openLabel?: string;\n closeLabel?: string;\n}\n\r\nasync function resolveAccessToken(\r\n provider: AiAgentChatProps[\"accessToken\"],\r\n): Promise<string | undefined> {\r\n if (!provider) {\r\n return undefined;\r\n }\r\n if (typeof provider === \"string\") {\r\n return provider.trim() || undefined;\r\n }\r\n const token = await provider();\r\n return typeof token === \"string\" ? token.trim() || undefined : undefined;\r\n}\r\n\r\nfunction normalizeBaseURL(baseURL: string): string {\r\n return baseURL.replace(/\\/+$/, \"\");\r\n}\r\n\r\nfunction hexToRgb(hex: string): string | null {\r\n const value = hex.trim().replace(\"#\", \"\");\r\n if (![3, 6].includes(value.length) || !/^[a-fA-F0-9]+$/.test(value)) {\r\n return null;\r\n }\r\n const full =\r\n value.length === 3\r\n ? value\r\n .split(\"\")\r\n .map((char) => `${char}${char}`)\r\n .join(\"\")\r\n : value;\r\n const red = Number.parseInt(full.slice(0, 2), 16);\r\n const green = Number.parseInt(full.slice(2, 4), 16);\r\n const blue = Number.parseInt(full.slice(4, 6), 16);\r\n return `${red}, ${green}, ${blue}`;\r\n}\r\n\r\nfunction resolvePrimaryRgb(color: string): string {\r\n const fromHex = hexToRgb(color);\r\n if (fromHex) {\r\n return fromHex;\r\n }\r\n\r\n const rgbMatch = color.match(/rgba?\\(([^)]+)\\)/i);\r\n if (!rgbMatch) {\r\n return \"17, 104, 187\";\r\n }\r\n\r\n const channels = rgbMatch[1]\r\n .split(\",\")\r\n .slice(0, 3)\r\n .map((part) => Number.parseFloat(part.trim()))\r\n .filter((value) => Number.isFinite(value));\r\n if (channels.length !== 3) {\r\n return \"17, 104, 187\";\r\n }\r\n\r\n return `${channels[0]}, ${channels[1]}, ${channels[2]}`;\r\n}\r\n\r\nfunction resolveRespondPath(baseURL: string, overridePath?: string): string {\r\n if (overridePath && overridePath.trim()) {\r\n return normalizePath(overridePath.trim());\r\n }\r\n\r\n const normalizedBase = normalizeBaseURL(baseURL);\r\n if (normalizedBase.endsWith(\"/api\")) {\r\n return \"/v2/ai-agent/respond/\";\r\n }\r\n\r\n return \"/api/v2/ai-agent/respond/\";\r\n}\r\n\r\nfunction normalizePath(path: string): string {\r\n if (!path) {\r\n return \"/api/v2/ai-agent/respond/\";\r\n }\r\n if (path.startsWith(\"/\")) {\r\n return path;\r\n }\r\n return `/${path}`;\r\n}\r\n\r\nexport function AiAgentChat({\n generateResponse,\r\n baseURL,\r\n accessToken,\r\n agent = \"home-assistant\",\r\n metadata,\r\n requestHeaders,\r\n respondPath = \"/api/v2/ai-agent/respond/\",\r\n suggestedMessages = [],\r\n headerTitle = \"BAWANA Assistant\",\r\n headerDescription = \"Online and ready to help\",\r\n assistantAvatar,\r\n assistantAvatarUrl = \"/ai-img.svg\",\r\n assistantInitials = \"AI\",\r\n userInitials = \"YOU\",\r\n initials = true,\r\n primaryColor = \"#1168bb\",\r\n primaryForeground = \"#ffffff\",\r\n onMessage,\r\n onError,\r\n className = \"\",\n placeholder = \"Ask the assistant...\",\n sendLabel = \"Send\",\n stopLabel = \"Stop\",\n layout = \"inline\",\n open,\n defaultOpen,\n onOpenChange,\n panelHeight,\n floatingPosition = \"bottom-right\",\n zIndex = 60,\n openLabel = \"Open chat\",\n closeLabel = \"Close chat\",\n}: AiAgentChatProps) {\n const [input, setInput] = useState(\"\");\r\n const [errorMessage, setErrorMessage] = useState<string>(\"\");\r\n const [loadingMoreMessageIds, setLoadingMoreMessageIds] = useState<\n Record<string, boolean>\n >({});\n const [internalOpen, setInternalOpen] = useState<boolean>(() => {\n if (layout === \"inline\") {\n return true;\n }\n if (typeof defaultOpen === \"boolean\") {\n return defaultOpen;\n }\n return false;\n });\n const messagesContainerRef = useRef<HTMLDivElement | null>(null);\n const resolvedMetadata = useMemo(\r\n () => metadata || EMPTY_METADATA,\r\n [metadata],\r\n );\r\n const normalizedSuggestions = useMemo(\r\n () =>\r\n Array.isArray(suggestedMessages)\r\n ? suggestedMessages.filter(\r\n (item) => typeof item === \"string\" && item.trim().length > 0,\r\n )\r\n : [],\r\n [suggestedMessages],\r\n );\r\n\r\n const transport = useCallback<GenerateResponse>(\r\n async ({ messages, signal }) => {\r\n if (typeof generateResponse === \"function\") {\r\n return generateResponse({ messages, signal });\r\n }\r\n\r\n if (!baseURL || !baseURL.trim()) {\r\n throw new Error(\r\n \"AiAgentChat requires `baseURL` when `generateResponse` is not provided.\",\r\n );\r\n }\r\n\r\n const token = await resolveAccessToken(accessToken);\r\n if (!token) {\r\n throw new Error(\r\n \"AiAgentChat requires `accessToken` when `generateResponse` is not provided.\",\r\n );\r\n }\r\n\r\n const headers = new Headers(requestHeaders);\r\n headers.set(\"content-type\", \"application/json\");\r\n headers.set(\"authorization\", `Bearer ${token}`);\r\n\r\n const latestUser = [...messages]\r\n .reverse()\r\n .find((item) => item.role === \"user\");\r\n const userMessage = latestUser?.content || \"\";\r\n\r\n const resolvedPath = resolveRespondPath(baseURL, respondPath);\r\n const response = await fetch(\r\n `${normalizeBaseURL(baseURL)}${resolvedPath}`,\r\n {\r\n method: \"POST\",\r\n headers,\r\n body: JSON.stringify({\r\n agent,\r\n message: userMessage,\r\n metadata: resolvedMetadata,\r\n }),\r\n signal,\r\n },\r\n );\r\n\r\n const raw = (await response.json()) as\r\n | RespondResponse\r\n | { detail?: string; message?: string };\r\n if (!response.ok) {\r\n const detail =\r\n typeof raw === \"object\" && raw\r\n ? \"detail\" in raw && typeof raw.detail === \"string\"\r\n ? raw.detail\r\n : \"message\" in raw && typeof raw.message === \"string\"\r\n ? raw.message\r\n : \"\"\r\n : \"\";\r\n throw new Error(\r\n `AI Agent request failed (${response.status})${detail ? `: ${detail}` : \"\"}`,\r\n );\r\n }\r\n\r\n const backendResponse = raw as RespondResponse;\r\n const recommendationOutput = extractRecommendationOutput(backendResponse);\r\n return {\r\n content: backendResponse.message,\r\n toolResults: backendResponse.tool_results,\r\n recommendations: extractRecommendationItems(backendResponse),\r\n recommendationNext: recommendationOutput?.next ?? null,\r\n };\r\n },\r\n [\r\n accessToken,\r\n agent,\r\n baseURL,\r\n generateResponse,\r\n requestHeaders,\r\n respondPath,\r\n resolvedMetadata,\r\n ],\r\n );\r\n\r\n const stableConfig = useMemo<ChatbotCoreConfig>(\r\n () => ({\r\n generateResponse: transport,\r\n onMessage,\r\n onError: (error, messages) => {\r\n setErrorMessage(error.message);\r\n if (typeof onError === \"function\") {\r\n onError(error, messages);\r\n }\r\n },\r\n }),\r\n [onError, onMessage, transport],\r\n );\r\n\r\n const { messages, isLoading, sendMessage, stop, updateMessageById } =\r\n useAiAgentChat(stableConfig);\r\n\r\n const onSubmit = useCallback(\r\n async (event: SubmitEvent<HTMLFormElement>) => {\r\n event.preventDefault();\r\n const value = input.trim();\r\n if (!value.length || isLoading) {\r\n return;\r\n }\r\n setErrorMessage(\"\");\r\n setInput(\"\");\r\n try {\r\n await sendMessage(value);\r\n } catch (error) {\r\n const nextError =\r\n error instanceof Error ? error.message : \"Failed to send message.\";\r\n setErrorMessage(nextError);\r\n }\r\n },\r\n [input, isLoading, sendMessage],\r\n );\r\n\r\n const onSuggestionClick = useCallback(\r\n async (text: string) => {\r\n if (isLoading) {\r\n return;\r\n }\r\n setErrorMessage(\"\");\r\n setInput(\"\");\r\n try {\r\n await sendMessage(text);\r\n } catch (error) {\r\n const nextError =\r\n error instanceof Error ? error.message : \"Failed to send message.\";\r\n setErrorMessage(nextError);\r\n }\r\n },\r\n [isLoading, sendMessage],\r\n );\r\n\r\n const hasUserMessage = messages.some((message) => message.role === \"user\");\n const isControlledOpen = typeof open === \"boolean\";\n const isOpen =\n layout === \"inline\" ? true : isControlledOpen ? (open as boolean) : internalOpen;\n\n const setOpenState = useCallback(\n (nextOpen: boolean) => {\n if (layout === \"inline\") {\n return;\n }\n if (!isControlledOpen) {\n setInternalOpen(nextOpen);\n }\n if (typeof onOpenChange === \"function\") {\n onOpenChange(nextOpen);\n }\n },\n [isControlledOpen, layout, onOpenChange],\n );\n\n useEffect(() => {\n if (isControlledOpen) {\n return;\n }\n if (layout === \"inline\") {\n setInternalOpen(true);\n return;\n }\n if (typeof defaultOpen === \"boolean\") {\n setInternalOpen(defaultOpen);\n return;\n }\n setInternalOpen(false);\n }, [defaultOpen, isControlledOpen, layout]);\n\r\n // auto scroll\r\n useEffect(() => {\r\n const node = messagesContainerRef.current;\r\n if (!node) {\r\n return;\r\n }\r\n node.scrollTop = node.scrollHeight;\r\n }, [messages, isLoading]);\r\n\r\n const loadMoreRecommendations = useCallback(\r\n async (messageId: string, nextUrl: string) => {\r\n if (!nextUrl || loadingMoreMessageIds[messageId]) {\r\n return;\r\n }\r\n if (!baseURL || !baseURL.trim()) {\r\n setErrorMessage(\"Cannot load more: baseURL is missing.\");\r\n return;\r\n }\r\n\r\n const token = await resolveAccessToken(accessToken);\r\n if (!token) {\r\n setErrorMessage(\"Cannot load more: accessToken is missing.\");\r\n return;\r\n }\r\n\r\n setLoadingMoreMessageIds((prev) => ({ ...prev, [messageId]: true }));\r\n try {\r\n const headers = new Headers(requestHeaders);\r\n headers.set(\"authorization\", `Bearer ${token}`);\r\n\r\n const requestUrl = new URL(\r\n nextUrl,\r\n `${normalizeBaseURL(baseURL)}/`,\r\n ).toString();\r\n const response = await fetch(requestUrl, {\r\n method: \"GET\",\r\n headers,\r\n });\r\n const raw = (await response.json()) as {\r\n next?: string | null;\r\n results?: unknown[];\r\n detail?: string;\r\n message?: string;\r\n };\r\n\r\n if (!response.ok) {\r\n const detail =\r\n typeof raw?.detail === \"string\"\r\n ? raw.detail\r\n : typeof raw?.message === \"string\"\r\n ? raw.message\r\n : \"\";\r\n throw new Error(\r\n `Load more failed (${response.status})${detail ? `: ${detail}` : \"\"}`,\r\n );\r\n }\r\n\r\n const newResults = Array.isArray(raw?.results) ? raw.results : [];\r\n const nextPointer =\r\n typeof raw?.next === \"string\" || raw?.next === null ? raw.next : null;\r\n\r\n updateMessageById(messageId, (message) => {\r\n const current = Array.isArray(message.recommendations)\r\n ? message.recommendations\r\n : [];\r\n const merged = mergeRecommendationItems(current, newResults);\r\n\r\n return {\r\n ...message,\r\n recommendations: merged,\r\n recommendationNext: nextPointer,\r\n };\r\n });\r\n } catch (error) {\r\n setErrorMessage(\r\n error instanceof Error\r\n ? error.message\r\n : \"Failed to load more recommendations.\",\r\n );\r\n } finally {\r\n setLoadingMoreMessageIds((prev) => ({ ...prev, [messageId]: false }));\r\n }\r\n },\r\n [\r\n accessToken,\r\n baseURL,\r\n loadingMoreMessageIds,\r\n requestHeaders,\r\n updateMessageById,\r\n ],\r\n );\r\n const shellStyle = useMemo(\n () =>\n ({\n \"--chat-primary\": primaryColor,\n \"--chat-primary-rgb\": resolvePrimaryRgb(primaryColor),\n \"--chat-primary-foreground\": primaryForeground,\n ...(typeof panelHeight === \"string\" && panelHeight.trim()\n ? { \"--chat-panel-height\": panelHeight.trim() }\n : {}),\n \"--chat-shell-z-index\": zIndex,\n }) as CSSProperties,\n [panelHeight, primaryColor, primaryForeground, zIndex],\n );\n\r\n const chatPanel = (\n <section className={`ai-agent-chat ${className}`.trim()}>\n <header className=\"ai-agent-chat__header\">\n <div className=\"ai-agent-chat__header-avatar\" aria-hidden=\"true\">\n {assistantAvatar ? (\r\n assistantAvatar\r\n ) : assistantAvatarUrl ? (\r\n <img src={assistantAvatarUrl} alt=\"\" />\r\n ) : initials ? (\r\n assistantInitials\r\n ) : (\r\n \"\"\r\n )}\r\n </div>\r\n <div className=\"ai-agent-chat__header-copy\">\r\n <strong>{headerTitle}</strong>\r\n <span>{headerDescription}</span>\r\n </div>\r\n </header>\r\n\r\n <div\r\n className=\"ai-agent-chat__messages\"\r\n role=\"log\"\r\n aria-live=\"polite\"\r\n ref={messagesContainerRef}\r\n >\r\n {!messages.length && !isLoading ? (\r\n <div className=\"ai-agent-chat__empty\" aria-hidden=\"true\">\r\n <div className=\"ai-agent-chat__empty-icon\">\r\n <svg viewBox=\"0 0 24 24\" focusable=\"false\">\r\n <path d=\"M12 2.5a.75.75 0 0 1 .73.57l1.02 4a.75.75 0 0 0 .53.53l4 1.02a.75.75 0 0 1 0 1.46l-4 1.02a.75.75 0 0 0-.53.53l-1.02 4a.75.75 0 0 1-1.46 0l-1.02-4a.75.75 0 0 0-.53-.53l-4-1.02a.75.75 0 0 1 0-1.46l4-1.02a.75.75 0 0 0 .53-.53l1.02-4A.75.75 0 0 1 12 2.5Z\" />\r\n <path d=\"M18.5 15a.75.75 0 0 1 .73.57l.35 1.37a.75.75 0 0 0 .53.53l1.37.35a.75.75 0 0 1 0 1.46l-1.37.35a.75.75 0 0 0-.53.53l-.35 1.37a.75.75 0 0 1-1.46 0l-.35-1.37a.75.75 0 0 0-.53-.53l-1.37-.35a.75.75 0 0 1 0-1.46l1.37-.35a.75.75 0 0 0 .53-.53l.35-1.37a.75.75 0 0 1 .73-.57Z\" />\r\n </svg>\r\n </div>\r\n <strong>Start a conversation</strong>\r\n <span>Ask about courses, recommendations, or learning plans.</span>\r\n </div>\r\n ) : null}\r\n {messages.map((message) => (\r\n <article\r\n key={message.id}\r\n className={`ai-agent-chat__message ai-agent-chat__message--${message.role}`}\r\n >\r\n {initials ? (\r\n <span className=\"ai-agent-chat__message-role\">\r\n {message.role === \"assistant\"\r\n ? assistantInitials\r\n : userInitials}\r\n </span>\r\n ) : null}\r\n <p>{message.content}</p>\r\n {Array.isArray(message.recommendations) &&\r\n message.recommendations.length > 0 ? (\r\n <div className=\"ai-agent-chat__recommendation-block\">\r\n <div className=\"chat-carousel\">\r\n {message.recommendations.map((item) => {\r\n const status =\r\n typeof item.status === \"string\" && item.status.trim()\r\n ? item.status.trim()\r\n : \"\";\r\n const type =\r\n typeof item.type === \"string\" && item.type.trim()\r\n ? item.type.trim()\r\n : \"\";\r\n const hasProgress =\r\n typeof item.progress === \"number\" &&\r\n Number.isFinite(item.progress);\r\n const progressValue = hasProgress\r\n ? Math.min(\r\n 100,\r\n Math.max(0, Math.round(item.progress as number)),\r\n )\r\n : 0;\r\n\r\n return (\r\n <a\r\n className=\"chat-carousel-card\"\r\n key={`${item.id || item.title}`}\r\n href={item.url || \"#\"}\r\n target=\"_blank\"\r\n rel=\"noreferrer\"\r\n >\r\n <div className=\"chat-carousel-card-header\">\r\n {type ? (\r\n <span className=\"chat-carousel-chip chat-carousel-chip--type\">\r\n {type}\r\n </span>\r\n ) : null}\r\n {status ? (\r\n <span\r\n className=\"chat-carousel-chip chat-carousel-chip--status\"\r\n data-status={status.toLowerCase()}\r\n >\r\n {status}\r\n </span>\r\n ) : null}\r\n {item.in_playlist ? (\r\n <span className=\"chat-carousel-chip chat-carousel-chip--muted\">\r\n In playlist\r\n </span>\r\n ) : null}\r\n </div>\r\n\r\n <div className=\"chat-carousel-card-content\">\r\n <div className=\"chat-carousel-card-title\">\r\n {item.title || \"Untitled Course\"}\r\n </div>\r\n <div className=\"chat-carousel-card-desc\">\r\n {item.description || \"\"}\r\n </div>\r\n </div>\r\n\r\n <div className=\"chat-carousel-card-footer\">\r\n <div className=\"chat-carousel-meta\">\r\n {hasProgress ? (\r\n <>\r\n <span className=\"chat-carousel-meta-text\">\r\n {progressValue}% complete\r\n </span>\r\n <div className=\"chat-carousel-progress\">\r\n <div\r\n className=\"chat-carousel-progress-bar\"\r\n style={{ width: `${progressValue}%` }}\r\n />\r\n </div>\r\n </>\r\n ) : null}\r\n </div>\r\n\r\n <div className=\"chat-carousel-cta\">\r\n <span>View course</span>\r\n <span className=\"chat-carousel-cta-icon\" />\r\n </div>\r\n </div>\r\n </a>\r\n );\r\n })}\r\n {loadingMoreMessageIds[message.id]\r\n ? Array.from({ length: 3 }).map((_, index) => (\r\n <div\r\n key={`skeleton-${message.id}-${index}`}\r\n className=\"chat-carousel-card chat-carousel-card--skeleton\"\r\n aria-hidden=\"true\"\r\n >\r\n <div className=\"chat-carousel-skeleton-line chat-carousel-skeleton-line--chip\" />\r\n <div className=\"chat-carousel-skeleton-line chat-carousel-skeleton-line--title\" />\r\n <div className=\"chat-carousel-skeleton-line chat-carousel-skeleton-line--desc\" />\r\n <div className=\"chat-carousel-skeleton-line chat-carousel-skeleton-line--desc-short\" />\r\n <div className=\"chat-carousel-skeleton-line chat-carousel-skeleton-line--cta\" />\r\n </div>\r\n ))\r\n : null}\r\n </div>\r\n {message.recommendationNext ? (\r\n <button\r\n type=\"button\"\r\n className=\"ai-agent-chat__loadmore\"\r\n onClick={() =>\r\n void loadMoreRecommendations(\r\n message.id,\r\n message.recommendationNext!,\r\n )\r\n }\r\n disabled={Boolean(loadingMoreMessageIds[message.id])}\r\n >\r\n {loadingMoreMessageIds[message.id] ? (\r\n <>\r\n <span\r\n className=\"ai-agent-chat__spinner\"\r\n aria-hidden=\"true\"\r\n />\r\n Loading...\r\n </>\r\n ) : (\r\n \"Load more\"\r\n )}\r\n </button>\r\n ) : null}\r\n </div>\r\n ) : null}\r\n </article>\r\n ))}\r\n {isLoading ? (\r\n <article className=\"ai-agent-chat__message ai-agent-chat__message--assistant ai-agent-chat__message--typing\">\r\n {initials ? (\r\n <span className=\"ai-agent-chat__message-role\">\r\n {assistantInitials}\r\n </span>\r\n ) : null}\r\n <p className=\"ai-agent-chat__typing\">\r\n <span className=\"ai-agent-chat__typing-dot\" aria-hidden=\"true\" />\r\n <span className=\"ai-agent-chat__typing-dot\" aria-hidden=\"true\" />\r\n <span className=\"ai-agent-chat__typing-dot\" aria-hidden=\"true\" />\r\n </p>\r\n </article>\r\n ) : null}\r\n </div>\r\n\r\n {!hasUserMessage && normalizedSuggestions.length > 0 ? (\r\n <div className=\"ai-agent-chat__suggestions\">\r\n {normalizedSuggestions.map((text) => (\r\n <button\r\n key={text}\r\n type=\"button\"\r\n onClick={() => void onSuggestionClick(text)}\r\n disabled={isLoading}\r\n >\r\n {text}\r\n </button>\r\n ))}\r\n </div>\r\n ) : null}\r\n\r\n <form className=\"ai-agent-chat__composer\" onSubmit={onSubmit}>\r\n <input\r\n value={input}\r\n onChange={(event) => setInput(event.target.value)}\r\n placeholder={placeholder}\r\n disabled={isLoading}\r\n />\r\n <button\r\n type={isLoading ? \"button\" : \"submit\"}\r\n onClick={isLoading ? stop : undefined}\r\n className={`ai-agent-chat__action ${isLoading ? \"is-stop\" : \"is-send\"}`}\r\n disabled={!isLoading && !input.trim().length}\r\n aria-label={isLoading ? stopLabel : sendLabel}\r\n title={isLoading ? stopLabel : sendLabel}\r\n >\r\n {isLoading ? (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 20 20\"\r\n fill=\"currentColor\"\r\n >\r\n <path d=\"M5.25 3A2.25 2.25 0 0 0 3 5.25v9.5A2.25 2.25 0 0 0 5.25 17h9.5A2.25 2.25 0 0 0 17 14.75v-9.5A2.25 2.25 0 0 0 14.75 3h-9.5Z\" />\r\n </svg>\r\n ) : (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 20 20\"\r\n fill=\"currentColor\"\r\n >\r\n <path d=\"M3.105 2.288a.75.75 0 0 0-.826.95l1.414 4.926A1.5 1.5 0 0 0 5.135 9.25h6.115a.75.75 0 0 1 0 1.5H5.135a1.5 1.5 0 0 0-1.442 1.086l-1.414 4.926a.75.75 0 0 0 .826.95 28.897 28.897 0 0 0 15.293-7.155.75.75 0 0 0 0-1.114A28.897 28.897 0 0 0 3.105 2.288Z\" />\r\n </svg>\r\n )}\r\n </button>\r\n </form>\r\n\r\n {errorMessage ? (\n <p className=\"ai-agent-chat__error\">{errorMessage}</p>\n ) : null}\n </section>\n );\n\n if (layout === \"floating\") {\n return (\n <div\n className={`ai-agent-chat-shell ai-agent-chat-shell--floating ai-agent-chat-shell--${floatingPosition} ${isOpen ? \"ai-agent-chat-shell--open\" : \"ai-agent-chat-shell--closed\"}`.trim()}\n style={shellStyle}\n >\n <div className=\"ai-agent-chat-shell__panel\">{chatPanel}</div>\n <button\n type=\"button\"\n className={`ai-agent-chat-shell__toggle ai-agent-chat-shell__toggle--floating ${isOpen ? \"is-open\" : \"\"}`.trim()}\n onClick={() => setOpenState(!isOpen)}\n aria-expanded={isOpen}\n aria-label={isOpen ? closeLabel : openLabel}\n title={isOpen ? closeLabel : openLabel}\n >\n <svg\n className=\"ai-agent-chat-shell__toggle-icon ai-agent-chat-shell__toggle-icon--open\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M12 6V2H8\" />\n <path d=\"M15 11v2\" />\n <path d=\"M2 12h2\" />\n <path d=\"M20 12h2\" />\n <path d=\"M20 16a2 2 0 0 1-2 2H8.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 4 20.286V8a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2z\" />\n <path d=\"M9 11v2\" />\n </svg>\n <svg\n className=\"ai-agent-chat-shell__toggle-icon ai-agent-chat-shell__toggle-icon--close\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\" />\n <path d=\"m14.5 8.5-5 5\" />\n <path d=\"m9.5 8.5 5 5\" />\n </svg>\n </button>\n </div>\n );\n }\n\n if (layout === \"dropdown\") {\n return (\n <div\n className={`ai-agent-chat-shell ai-agent-chat-shell--dropdown ${isOpen ? \"ai-agent-chat-shell--open\" : \"ai-agent-chat-shell--closed\"}`.trim()}\n style={shellStyle}\n >\n <button\n type=\"button\"\n className={`ai-agent-chat-shell__toggle ai-agent-chat-shell__toggle--dropdown ${isOpen ? \"is-open\" : \"\"}`.trim()}\n onClick={() => setOpenState(!isOpen)}\n aria-expanded={isOpen}\n aria-label={isOpen ? closeLabel : openLabel}\n title={isOpen ? closeLabel : openLabel}\n >\n <span className=\"ai-agent-chat-shell__toggle-avatar\" aria-hidden=\"true\">\n {assistantAvatar ? (\n assistantAvatar\n ) : assistantAvatarUrl ? (\n <img src={assistantAvatarUrl} alt=\"\" />\n ) : initials ? (\n assistantInitials\n ) : (\n \"\"\n )}\n </span>\n <span className=\"ai-agent-chat-shell__toggle-copy\">\n <strong>{headerTitle}</strong>\n <span>{headerDescription}</span>\n </span>\n <span className=\"ai-agent-chat-shell__caret\" aria-hidden=\"true\" />\n </button>\n <div className={`ai-agent-chat-shell__panel ${isOpen ? \"is-open\" : \"\"}`.trim()}>\n {chatPanel}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"ai-agent-chat-shell ai-agent-chat-shell--inline\" style={shellStyle}>\n {chatPanel}\n </div>\n );\n}\n"],"names":["asRecommendationItem","value","item","mergeRecommendationItems","current","incoming","merged","raw","candidate","EMPTY_METADATA","useAiAgentChat","config","coreRef","useRef","state","setState","useState","useEffect","core","ChatbotCore","unsubscribe","nextState","sendMessage","useCallback","text","stop","updateMessageById","messageId","updater","resolveAccessToken","provider","token","normalizeBaseURL","baseURL","hexToRgb","hex","full","char","red","green","blue","resolvePrimaryRgb","color","fromHex","rgbMatch","channels","part","resolveRespondPath","overridePath","normalizePath","path","AiAgentChat","generateResponse","accessToken","agent","metadata","requestHeaders","respondPath","suggestedMessages","headerTitle","headerDescription","assistantAvatar","assistantAvatarUrl","assistantInitials","userInitials","initials","primaryColor","primaryForeground","onMessage","onError","className","placeholder","sendLabel","stopLabel","layout","open","defaultOpen","onOpenChange","panelHeight","floatingPosition","zIndex","openLabel","closeLabel","input","setInput","errorMessage","setErrorMessage","loadingMoreMessageIds","setLoadingMoreMessageIds","internalOpen","setInternalOpen","messagesContainerRef","resolvedMetadata","useMemo","normalizedSuggestions","transport","messages","signal","headers","latestUser","userMessage","resolvedPath","response","detail","backendResponse","recommendationOutput","extractRecommendationOutput","extractRecommendationItems","_a","stableConfig","error","isLoading","onSubmit","event","nextError","onSuggestionClick","hasUserMessage","message","isControlledOpen","isOpen","setOpenState","nextOpen","node","loadMoreRecommendations","nextUrl","prev","requestUrl","newResults","nextPointer","shellStyle","chatPanel","jsxs","jsx","status","type","hasProgress","progressValue","Fragment","_","index"],"mappings":"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"}
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ai-agent-chat-shell{--chat-panel-height: 550px;--chat-shell-z-index: 60;position:relative}.ai-agent-chat-shell__panel{min-height:0}.ai-agent-chat-shell__toggle{border:none;cursor:pointer;color:var(--chat-primary-foreground);background:var(--chat-primary)}.ai-agent-chat-shell__toggle:focus-visible{outline:2px solid rgba(var(--chat-primary-rgb),.35);outline-offset:2px}.ai-agent-chat-shell--inline,.ai-agent-chat-shell--dropdown{width:100%}.ai-agent-chat-shell--dropdown .ai-agent-chat-shell__toggle--dropdown{width:100%;display:flex;align-items:center;justify-content:space-between;gap:.75rem;border-radius:.5rem;padding:1rem 1.25rem;box-shadow:0 10px 30px -12px rgba(var(--chat-primary-rgb),.45);transition:opacity .2s ease,transform .2s ease,border-radius .3s ease}.ai-agent-chat-shell--dropdown .ai-agent-chat-shell__toggle--dropdown:hover{opacity:.92}.ai-agent-chat-shell--dropdown .ai-agent-chat-shell__toggle--dropdown.is-open{border-bottom-left-radius:0;border-bottom-right-radius:0}.ai-agent-chat-shell__toggle-copy{display:flex;flex-direction:column;line-height:1.3;text-align:left;flex:1}.ai-agent-chat-shell__toggle-avatar{width:2.25rem;height:2.25rem;border-radius:999px;background:#ffffff29;border:1px solid rgba(255,255,255,.32);display:inline-flex;align-items:center;justify-content:center;font-size:.72rem;font-weight:800;letter-spacing:.04em;flex-shrink:0;overflow:hidden}.ai-agent-chat-shell__toggle-avatar img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.ai-agent-chat-shell__toggle-copy strong{font-size:1rem}.ai-agent-chat-shell__toggle-copy span{font-size:.85rem;opacity:.85;font-weight:500}.ai-agent-chat-shell__caret{width:2rem;height:2rem;border-radius:999px;border:1px solid rgba(255,255,255,.55);display:inline-flex;align-items:center;justify-content:center;background:#ffffff26;transition:transform .2s ease}.ai-agent-chat-shell__caret:before{content:"";width:.4rem;height:.4rem;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(45deg);display:inline-block}.ai-agent-chat-shell--dropdown.ai-agent-chat-shell--open .ai-agent-chat-shell__caret{transform:rotate(180deg)}.ai-agent-chat-shell--dropdown .ai-agent-chat-shell__panel{width:100%;border-radius:0 0 1rem 1rem;border:1px solid var(--chat-border, rgba(15, 23, 42, .08));border-top:none;background-color:var(--chat-card-bg, #ffffff);box-shadow:0 5px 15px -6px rgba(var(--chat-primary-rgb),.45);overflow:hidden;display:flex;flex-direction:column;height:0;max-height:0;min-height:0;opacity:0;transform:translateY(-6px);pointer-events:none;transition:max-height .4s cubic-bezier(.4,0,.2,1),min-height .4s cubic-bezier(.4,0,.2,1),opacity .35s cubic-bezier(.4,0,.2,1),transform .35s cubic-bezier(.4,0,.2,1)}.ai-agent-chat-shell--dropdown.ai-agent-chat-shell--open .ai-agent-chat-shell__panel{height:min(var(--chat-panel-height),calc(100vh - 9rem));max-height:min(var(--chat-panel-height),calc(100vh - 9rem));min-height:min(var(--chat-panel-height),calc(100vh - 9rem));opacity:1;transform:translateY(0);pointer-events:auto}.ai-agent-chat-shell--dropdown .ai-agent-chat{border:none;border-radius:0;box-shadow:none;height:100%;max-height:100%;grid-template-rows:1fr auto auto auto;overflow:hidden}.ai-agent-chat-shell--dropdown .ai-agent-chat__header{display:none}.ai-agent-chat-shell--dropdown .ai-agent-chat-shell__panel>.ai-agent-chat{height:100%;min-height:0}.ai-agent-chat-shell--dropdown .ai-agent-chat__messages{-webkit-overflow-scrolling:touch;animation:ai-agent-dropdown-content-fade-in .4s ease-out .15s both}.ai-agent-chat-shell--floating{position:fixed;bottom:1.5rem;z-index:var(--chat-shell-z-index);width:min(390px,calc(100vw - 1rem))}.ai-agent-chat-shell--bottom-right{right:1.5rem}.ai-agent-chat-shell--bottom-left{left:1rem}.ai-agent-chat-shell--floating .ai-agent-chat-shell__panel{position:absolute;bottom:calc(100% + .65rem);width:100%;opacity:0;transform:translateY(8px) scale(.985);transform-origin:bottom right;pointer-events:none;transition:transform .2s ease,opacity .2s ease}.ai-agent-chat-shell--floating.ai-agent-chat-shell--bottom-left .ai-agent-chat-shell__panel{transform-origin:bottom left}.ai-agent-chat-shell--floating.ai-agent-chat-shell--open .ai-agent-chat-shell__panel{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}.ai-agent-chat-shell--floating .ai-agent-chat{height:min(var(--chat-panel-height),calc(100vh - 6.5rem))}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating{position:relative;width:3.5rem;height:3.5rem;border-radius:999px;margin-left:auto;display:grid;place-items:center;box-shadow:0 20px 45px #0f172a40;transition:transform .2s ease,box-shadow .2s ease,background-color .2s ease}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:after{content:"";position:absolute;inset:0;border-radius:inherit;opacity:0;box-shadow:0 0 rgba(var(--chat-primary-rgb),.15);transition:opacity .2s ease;pointer-events:none}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:not(.is-open){animation:ai-agent-toggle-pulse 3.2s ease-in-out infinite}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:not(.is-open):after{animation:ai-agent-toggle-ring 3.2s ease-out infinite}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating.is-open{animation:ai-agent-toggle-burst .38s ease-out}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating.is-open:after{animation:ai-agent-toggle-burst-ring .38s ease-out forwards}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:not(.is-open):hover{transform:translateY(-2px);box-shadow:0 24px 55px #0f172a52}.ai-agent-chat-shell__toggle-icon{width:1.7rem;height:1.7rem;grid-area:1 / 1;opacity:0;transform:scale(.82) rotate(-8deg);transition:opacity .24s ease,transform .32s ease;pointer-events:none}.ai-agent-chat-shell__toggle-icon--open,.ai-agent-chat-shell__toggle-icon--close{transform-origin:center}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:not(.is-open) .ai-agent-chat-shell__toggle-icon--open{opacity:1;transform:scale(1) rotate(0)}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating.is-open .ai-agent-chat-shell__toggle-icon--close{opacity:1;transform:scale(1) rotate(0)}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating.is-open .ai-agent-chat-shell__toggle-icon--open{opacity:0;transform:scale(.7) rotate(-25deg)}.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:not(.is-open) .ai-agent-chat-shell__toggle-icon--close{opacity:0;transform:scale(.7) rotate(25deg)}.ai-agent-chat{--chat-height: var(--chat-panel-height);--chat-foreground: #0f172a;--chat-muted: #475569;--chat-border: rgba(15, 23, 42, .08);--chat-card-bg: #ffffff;border:1px solid var(--chat-border);border-radius:18px;background:var(--chat-card-bg);box-shadow:0 10px 30px -12px rgba(var(--chat-primary-rgb),.45);display:grid;grid-template-rows:auto 1fr auto auto auto;height:var(--chat-height);overflow:hidden}.ai-agent-chat__header{display:flex;align-items:center;gap:.8rem;padding:.9rem 1rem;background:linear-gradient(145deg,rgba(var(--chat-primary-rgb),.96),rgba(var(--chat-primary-rgb),.9) 65%,rgba(var(--chat-primary-rgb),.8));color:var(--chat-primary-foreground)}.ai-agent-chat__header-avatar{width:2.25rem;height:2.25rem;border-radius:999px;background:#ffffff29;border:1px solid rgba(255,255,255,.32);display:inline-flex;align-items:center;justify-content:center;font-size:.72rem;font-weight:800;letter-spacing:.04em}.ai-agent-chat__header-avatar img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.ai-agent-chat__header-copy{display:flex;flex-direction:column;min-width:0;line-height:1.2}.ai-agent-chat__header-copy strong{font-size:.98rem}.ai-agent-chat__header-copy span{font-size:.78rem;opacity:.92}.ai-agent-chat__suggestions{display:flex;flex-wrap:wrap;align-items:flex-start;gap:.5rem;padding:0 .9rem .75rem}.ai-agent-chat__suggestions button{border:1px solid rgba(var(--chat-primary-rgb),.25);border-radius:999px;background:rgba(var(--chat-primary-rgb),.08);color:var(--chat-primary);padding:.34rem .7rem;font-size:.8rem;font-weight:700;cursor:pointer}.ai-agent-chat__messages{display:flex;flex-direction:column;gap:.6rem;min-height:0;overflow-y:auto;padding:.8rem .9rem}.ai-agent-chat__empty{min-height:100%;display:grid;place-content:center;justify-items:center;text-align:center;gap:.45rem;padding:1rem}.ai-agent-chat__empty-icon{width:2.8rem;height:2.8rem;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;border:1px solid rgba(var(--chat-primary-rgb),.22);background:rgba(var(--chat-primary-rgb),.08);color:var(--chat-primary)}.ai-agent-chat__empty-icon svg{width:1.2rem;height:1.2rem;fill:currentColor}.ai-agent-chat__empty strong{color:var(--chat-foreground);font-size:.9rem}.ai-agent-chat__empty span{color:var(--chat-muted);font-size:.8rem;max-width:30ch;line-height:1.45}.ai-agent-chat__message{border-radius:1rem;padding:.62rem .72rem;max-width:88%;border:1px solid var(--chat-border);box-shadow:0 6px 20px #0f172a0f}.ai-agent-chat__message p{margin:0;color:var(--chat-foreground);font-size:.92rem;line-height:1.5}.ai-agent-chat__message-role{display:inline-flex;margin-bottom:.4rem;font-size:.66rem;font-weight:800;letter-spacing:.05em;text-transform:uppercase}.ai-agent-chat__message--user{background:rgba(var(--chat-primary-rgb),.14);border-color:rgba(var(--chat-primary-rgb),.28);align-self:flex-end}.ai-agent-chat__message--assistant{background:#f8fafc;align-self:flex-start}.ai-agent-chat__message--typing{opacity:.95}.ai-agent-chat__typing{display:inline-flex;align-items:center;gap:.32rem}.ai-agent-chat__typing-dot{width:.38rem;height:.38rem;border-radius:999px;background:rgba(var(--chat-primary-rgb),.9);animation:ai-agent-typing 1.2s ease-in-out infinite}.ai-agent-chat__typing-dot:nth-child(2){animation-delay:.15s}.ai-agent-chat__typing-dot:nth-child(3){animation-delay:.3s}.ai-agent-chat__recommendations{list-style:none;margin:.65rem 0 0;padding:0;display:flex;flex-direction:column;gap:.45rem}.ai-agent-chat__recommendation-card{border-radius:.8rem;border:1px solid rgba(15,23,42,.08);background:#fff;overflow:hidden}.ai-agent-chat__recommendation-card a{display:grid;gap:.22rem;padding:.58rem .65rem;text-decoration:none}.ai-agent-chat__recommendation-card strong{color:#0f172a;font-size:.86rem}.ai-agent-chat__recommendation-card span{color:#475569;font-size:.78rem;line-height:1.4;display:-webkit-box;-webkit-box-orient:vertical;line-clamp:2;overflow:hidden}.chat-carousel{display:flex;overflow-x:auto;gap:.5rem;padding:.25rem 0 0;margin-top:.55rem;width:100%;scroll-snap-type:x mandatory;scrollbar-width:none;-ms-overflow-style:none}.chat-carousel::-webkit-scrollbar{display:none}.chat-carousel-card{flex:0 0 260px;scroll-snap-align:start;border-radius:1rem;border:1px solid rgba(15,23,42,.08);background:#fff;color:var(--chat-foreground);overflow:hidden;display:flex;flex-direction:column;text-decoration:none;transition:transform .2s ease,box-shadow .2s ease}.chat-carousel-card:hover{transform:translateY(-2px);border-color:rgba(var(--chat-primary-rgb),.65)}.chat-carousel-card--skeleton{pointer-events:none;border-style:dashed;border-color:rgba(var(--chat-primary-rgb),.22);background:#fff;padding:.78rem .82rem;gap:.58rem;justify-content:space-between}.chat-carousel-skeleton-line{width:100%;border-radius:999px;background:linear-gradient(90deg,#e2e8f0e6 20%,#f1f5f9f2,#e2e8f0e6 56%);background-size:200% 100%;animation:ai-agent-skeleton 1.2s linear infinite}.chat-carousel-skeleton-line--chip{width:34%;height:.9rem}.chat-carousel-skeleton-line--title{height:1rem}.chat-carousel-skeleton-line--desc{height:.72rem}.chat-carousel-skeleton-line--desc-short{width:72%;height:.72rem}.chat-carousel-skeleton-line--cta{margin-top:.65rem;height:2rem}.chat-carousel-card-header{padding:.58rem .82rem .12rem;display:flex;gap:.38rem;flex-wrap:wrap;align-items:center}.chat-carousel-card-content{padding:.64rem .82rem .56rem;display:flex;flex-direction:column;gap:.35rem;flex:1}.chat-carousel-card-title{font-weight:700;font-size:.94rem;line-height:1.45;display:-webkit-box;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.chat-carousel-card-desc{font-size:.78rem;color:var(--chat-muted);display:-webkit-box;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-bottom:auto}.chat-carousel-card-footer{padding:.62rem .82rem .72rem;border-top:1px solid rgba(15,23,42,.06);background:#fff;display:flex;flex-direction:column;gap:.55rem}.chat-carousel-chip{display:inline-flex;align-items:center;gap:.25rem;padding:.2rem .58rem;border-radius:999px;border:1px solid rgba(203,213,225,.9);background:#f1f5f9e6;color:#334155e6;font-weight:700;font-size:.67rem}.chat-carousel-chip--type{background:#f8fafcf2}.chat-carousel-chip--muted{background:#fff;color:var(--chat-muted)}.chat-carousel-chip--status[data-status=started]{background:#16a34a1f;color:#16a34a;border-color:#16a34a40}.chat-carousel-chip--status[data-status=completed]{background:#2563eb1f;color:#2563eb;border-color:#2563eb40}.chat-carousel-meta{display:flex;flex-direction:column;gap:.34rem;min-height:1px}.chat-carousel-meta-text{font-size:.74rem;font-weight:700;color:var(--chat-foreground)}.chat-carousel-progress{width:100%;height:6px;border-radius:999px;background:#e8edf5;overflow:hidden}.chat-carousel-progress-bar{height:100%;background:rgba(var(--chat-primary-rgb),1);border-radius:inherit}.chat-carousel-cta{display:inline-flex;align-items:center;justify-content:center;gap:.35rem;width:100%;padding:.52rem .78rem;border-radius:999px;border:1px solid rgba(var(--chat-primary-rgb),.28);background:rgba(var(--chat-primary-rgb),.12);color:var(--chat-primary);font-weight:800;font-size:.82rem}.chat-carousel-cta-icon{width:.5rem;height:.5rem;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);margin-top:1px}.chat-carousel-loadmore{flex:0 0 180px;scroll-snap-align:start;border-radius:1rem;border:1px dashed rgba(var(--chat-primary-rgb),.45);background:rgba(var(--chat-primary-rgb),.06);color:var(--chat-primary);font-weight:700;font-size:.86rem;cursor:pointer;min-height:210px;display:inline-flex;align-items:center;justify-content:center;padding:.8rem}.chat-carousel-loadmore:disabled{cursor:not-allowed;opacity:.6}.ai-agent-chat__recommendation-block{display:grid;gap:.55rem}.ai-agent-chat__loadmore{display:inline-flex;align-items:center;gap:.45rem;align-self:stretch;justify-self:stretch;width:100%;justify-content:center;border-radius:999px;border:1px dashed rgba(var(--chat-primary-rgb),.45);background:rgba(var(--chat-primary-rgb),.06);color:var(--chat-primary);font-weight:700;font-size:.84rem;cursor:pointer;padding:.45rem .95rem}.ai-agent-chat__loadmore:disabled{cursor:not-allowed;opacity:.6}.ai-agent-chat__spinner{width:.9rem;height:.9rem;border-radius:999px;border:2px solid rgba(var(--chat-primary-rgb),.2);border-top-color:rgba(var(--chat-primary-rgb),.95);animation:ai-agent-spin .8s linear infinite}@keyframes ai-agent-spin{to{transform:rotate(360deg)}}@keyframes ai-agent-typing{0%,80%,to{transform:translateY(0);opacity:.35}40%{transform:translateY(-2px);opacity:1}}@keyframes ai-agent-skeleton{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes ai-agent-toggle-pulse{0%,to{box-shadow:0 20px 45px #0f172a38}50%{box-shadow:0 26px 65px rgba(var(--chat-primary-rgb),.42)}}@keyframes ai-agent-toggle-ring{0%{opacity:.6;transform:scale(1);box-shadow:0 0 rgba(var(--chat-primary-rgb),.28)}70%,to{opacity:0;transform:scale(1.25);box-shadow:0 0 0 14px rgba(var(--chat-primary-rgb),0)}}@keyframes ai-agent-toggle-burst{0%{transform:scale(.94)}60%{transform:scale(1.08)}to{transform:scale(1)}}@keyframes ai-agent-toggle-burst-ring{0%{opacity:.9;transform:scale(.9);box-shadow:0 0 rgba(var(--chat-primary-rgb),.55)}70%{opacity:.35;transform:scale(1.25);box-shadow:0 0 0 10px rgba(var(--chat-primary-rgb),.15)}to{opacity:0;transform:scale(1.4);box-shadow:0 0 0 18px rgba(var(--chat-primary-rgb),0)}}@keyframes ai-agent-dropdown-content-fade-in{0%{opacity:0}to{opacity:1}}.ai-agent-chat__composer{display:grid;grid-template-columns:1fr auto;gap:.45rem;padding:.75rem .9rem;border-top:1px solid var(--chat-border);background:#fff}.ai-agent-chat__composer input{min-width:0;border:1px solid #cbd5e1;border-radius:.7rem;padding:.6rem .72rem;font-size:.9rem}.ai-agent-chat__composer button{border:none;border-radius:.7rem;width:2.6rem;height:2.6rem;padding:0;cursor:pointer;background:var(--chat-primary);color:var(--chat-primary-foreground);font-weight:700;display:inline-flex;align-items:center;justify-content:center}.ai-agent-chat__action svg{width:1rem;height:1rem;fill:currentColor}.ai-agent-chat__action.is-stop{background:#750000}.ai-agent-chat__composer button[disabled]{cursor:not-allowed;opacity:.55}.ai-agent-chat__error{margin:0;padding:0 .9rem .8rem;font-size:.84rem;color:#b91c1c}@media (max-width: 640px){.ai-agent-chat-shell--floating{right:.5rem;left:.5rem;width:auto}.ai-agent-chat{border-radius:14px;height:min(72vh,var(--chat-height))}.ai-agent-chat__composer{grid-template-columns:1fr auto;align-items:center}.ai-agent-chat-shell--dropdown.ai-agent-chat-shell--open .ai-agent-chat-shell__panel{height:min(var(--chat-panel-height),calc(100vh - 6rem));max-height:min(var(--chat-panel-height),calc(100vh - 6rem));min-height:min(var(--chat-panel-height),calc(100vh - 6rem))}}@media (prefers-reduced-motion: reduce){.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:not(.is-open),.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating:not(.is-open):after,.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating.is-open,.ai-agent-chat-shell--floating .ai-agent-chat-shell__toggle--floating.is-open:after{animation:none}.ai-agent-chat-shell__toggle-icon,.ai-agent-chat-shell--floating .ai-agent-chat-shell__panel{transition:none}}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { AgentMetadata, ChatMessage, ChatbotCoreConfig, ChatbotState, GenerateResponse } from "../core/types";
|
|
3
|
+
export interface UseAiAgentChatResult extends ChatbotState {
|
|
4
|
+
sendMessage: (text: string) => Promise<ChatMessage | undefined>;
|
|
5
|
+
stop: () => void;
|
|
6
|
+
updateMessageById: (messageId: string, updater: (message: ChatMessage) => ChatMessage) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function useAiAgentChat(config: ChatbotCoreConfig): UseAiAgentChatResult;
|
|
9
|
+
export interface AiAgentChatProps {
|
|
10
|
+
generateResponse?: GenerateResponse;
|
|
11
|
+
suggestedMessages?: string[];
|
|
12
|
+
onMessage?: ChatbotCoreConfig["onMessage"];
|
|
13
|
+
onError?: ChatbotCoreConfig["onError"];
|
|
14
|
+
baseURL?: string;
|
|
15
|
+
accessToken?: string | (() => string | undefined | Promise<string | undefined>);
|
|
16
|
+
agent?: string;
|
|
17
|
+
metadata?: AgentMetadata;
|
|
18
|
+
requestHeaders?: HeadersInit;
|
|
19
|
+
respondPath?: string;
|
|
20
|
+
headerTitle?: string;
|
|
21
|
+
headerDescription?: string;
|
|
22
|
+
assistantAvatar?: ReactNode;
|
|
23
|
+
assistantAvatarUrl?: string;
|
|
24
|
+
assistantInitials?: string;
|
|
25
|
+
userInitials?: string;
|
|
26
|
+
initials?: boolean;
|
|
27
|
+
primaryColor?: string;
|
|
28
|
+
primaryForeground?: string;
|
|
29
|
+
className?: string;
|
|
30
|
+
placeholder?: string;
|
|
31
|
+
sendLabel?: string;
|
|
32
|
+
stopLabel?: string;
|
|
33
|
+
layout?: "inline" | "floating" | "dropdown";
|
|
34
|
+
open?: boolean;
|
|
35
|
+
defaultOpen?: boolean;
|
|
36
|
+
onOpenChange?: (open: boolean) => void;
|
|
37
|
+
panelHeight?: string;
|
|
38
|
+
floatingPosition?: "bottom-right" | "bottom-left";
|
|
39
|
+
zIndex?: number;
|
|
40
|
+
openLabel?: string;
|
|
41
|
+
closeLabel?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function AiAgentChat({ generateResponse, baseURL, accessToken, agent, metadata, requestHeaders, respondPath, suggestedMessages, headerTitle, headerDescription, assistantAvatar, assistantAvatarUrl, assistantInitials, userInitials, initials, primaryColor, primaryForeground, onMessage, onError, className, placeholder, sendLabel, stopLabel, layout, open, defaultOpen, onOpenChange, panelHeight, floatingPosition, zIndex, openLabel, closeLabel, }: AiAgentChatProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ChatMessage, ChatbotCoreConfig, ChatbotState, ChatbotSubscriber } from "./types";
|
|
2
|
+
export declare class ChatbotCore {
|
|
3
|
+
private config;
|
|
4
|
+
private subscribers;
|
|
5
|
+
private state;
|
|
6
|
+
private abortController;
|
|
7
|
+
constructor(config: ChatbotCoreConfig);
|
|
8
|
+
getState(): ChatbotState;
|
|
9
|
+
subscribe(subscriber: ChatbotSubscriber): () => void;
|
|
10
|
+
stop(): void;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
sendMessage(text: string): Promise<ChatMessage | undefined>;
|
|
13
|
+
updateMessageById(messageId: string, updater: (message: ChatMessage) => ChatMessage): void;
|
|
14
|
+
private createAssistantMessage;
|
|
15
|
+
private setState;
|
|
16
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export type AgentName = string;
|
|
2
|
+
export interface AgentMetadata {
|
|
3
|
+
course_id?: number;
|
|
4
|
+
}
|
|
5
|
+
export interface PromptInfo {
|
|
6
|
+
version: string;
|
|
7
|
+
hash: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ToolResult {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
output: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface RespondResponse {
|
|
15
|
+
session_id: number;
|
|
16
|
+
user_message_id: number;
|
|
17
|
+
assistant_message_id: number;
|
|
18
|
+
message: string;
|
|
19
|
+
model: string;
|
|
20
|
+
response_id: string;
|
|
21
|
+
prompt: PromptInfo;
|
|
22
|
+
tool_results?: ToolResult[];
|
|
23
|
+
}
|
|
24
|
+
export interface RecommendationItem {
|
|
25
|
+
id: number | string | null;
|
|
26
|
+
title: string;
|
|
27
|
+
description: string;
|
|
28
|
+
url: string;
|
|
29
|
+
type: string;
|
|
30
|
+
status: string | null;
|
|
31
|
+
progress: number | null;
|
|
32
|
+
is_eligible: boolean;
|
|
33
|
+
in_playlist: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface RecommendationOutput {
|
|
36
|
+
count: number;
|
|
37
|
+
next: string | null;
|
|
38
|
+
previous: string | null;
|
|
39
|
+
results: RecommendationItem[];
|
|
40
|
+
}
|
|
41
|
+
export interface CourseDetailOutput {
|
|
42
|
+
course: {
|
|
43
|
+
id: number;
|
|
44
|
+
title: string;
|
|
45
|
+
description: string;
|
|
46
|
+
modality: string;
|
|
47
|
+
status: string | null;
|
|
48
|
+
content_in_sequence: boolean;
|
|
49
|
+
min_percentage_finish: number;
|
|
50
|
+
tags: string[];
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export type ChatRole = "system" | "assistant" | "user";
|
|
54
|
+
export interface ChatMessage {
|
|
55
|
+
id: string;
|
|
56
|
+
role: ChatRole;
|
|
57
|
+
content: string;
|
|
58
|
+
createdAt: string;
|
|
59
|
+
usage?: {
|
|
60
|
+
prompt_tokens?: number;
|
|
61
|
+
completion_tokens?: number;
|
|
62
|
+
total_tokens?: number;
|
|
63
|
+
};
|
|
64
|
+
recommendations?: RecommendationItem[];
|
|
65
|
+
recommendationNext?: string | null;
|
|
66
|
+
toolResults?: ToolResult[];
|
|
67
|
+
}
|
|
68
|
+
export interface GenerateResponseRequest {
|
|
69
|
+
messages: ChatMessage[];
|
|
70
|
+
signal: AbortSignal;
|
|
71
|
+
}
|
|
72
|
+
export interface GenerateResponseResult {
|
|
73
|
+
content: string;
|
|
74
|
+
usage?: ChatMessage["usage"];
|
|
75
|
+
recommendations?: RecommendationItem[];
|
|
76
|
+
recommendationNext?: string | null;
|
|
77
|
+
toolResults?: ToolResult[];
|
|
78
|
+
}
|
|
79
|
+
export type GenerateResponse = (request: GenerateResponseRequest) => Promise<GenerateResponseResult>;
|
|
80
|
+
export interface ChatbotCoreConfig {
|
|
81
|
+
generateResponse: GenerateResponse;
|
|
82
|
+
onMessage?: (message: ChatMessage, messages: ChatMessage[]) => void;
|
|
83
|
+
onError?: (error: Error, messages: ChatMessage[]) => void;
|
|
84
|
+
}
|
|
85
|
+
export interface ChatbotState {
|
|
86
|
+
messages: ChatMessage[];
|
|
87
|
+
isLoading: boolean;
|
|
88
|
+
}
|
|
89
|
+
export type ChatbotSubscriber = (state: ChatbotState) => void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ChatbotCore } from "./core/chatbot";
|
|
2
|
+
export { AiAgentCoreError } from "./core/errors";
|
|
3
|
+
export { extractCourseDetail, extractRecommendationItems, extractRecommendationOutput, getToolErrors, getToolResultsByName } from "./lib/tool-results";
|
|
4
|
+
export type { AgentMetadata, AgentName, ChatMessage, ChatRole, ChatbotCoreConfig, ChatbotState, ChatbotSubscriber, CourseDetailOutput, GenerateResponse, GenerateResponseRequest, GenerateResponseResult, PromptInfo, RecommendationItem, RecommendationOutput, RespondResponse, ToolResult } from "./core/types";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CourseDetailOutput, RecommendationOutput, RespondResponse, ToolResult } from "../core/types";
|
|
2
|
+
export declare function getToolResultsByName(response: RespondResponse, toolName: string): ToolResult[];
|
|
3
|
+
export declare function getToolErrors(response: RespondResponse): string[];
|
|
4
|
+
export declare function extractCourseDetail(response: RespondResponse): CourseDetailOutput | null;
|
|
5
|
+
export declare function extractRecommendationOutput(response: RespondResponse): RecommendationOutput | null;
|
|
6
|
+
export declare function extractRecommendationItems(response: RespondResponse): import("..").RecommendationItem[];
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rizal_ncc/agent-client",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "UI wrapper and helpers for BAWANA AI agent integrations",
|
|
5
|
+
"author": "Rizal Suryawan - (BAWANA Team)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/index.cjs",
|
|
12
|
+
"module": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/types/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/types/index.d.ts",
|
|
17
|
+
"import": "./dist/index.mjs",
|
|
18
|
+
"require": "./dist/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./react": {
|
|
21
|
+
"types": "./dist/types/react.d.ts",
|
|
22
|
+
"import": "./dist/react.mjs",
|
|
23
|
+
"require": "./dist/react.cjs"
|
|
24
|
+
},
|
|
25
|
+
"./style.css": "./dist/style.css",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"dev": "vite",
|
|
35
|
+
"clean": "rimraf dist",
|
|
36
|
+
"build": "npm run clean && npm run build:lib && npm run build:types",
|
|
37
|
+
"build:lib": "vite build",
|
|
38
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
39
|
+
"release:check": "npm test && npm run build && npm pack --dry-run",
|
|
40
|
+
"release:publish": "npm publish --access public",
|
|
41
|
+
"prepublishOnly": "npm run build",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"react": ">=18.0.0",
|
|
47
|
+
"react-dom": ">=18.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"react": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"react-dom": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@testing-library/react": "^16.3.2",
|
|
59
|
+
"@testing-library/user-event": "^14.6.1",
|
|
60
|
+
"@types/node": "^24.7.1",
|
|
61
|
+
"@types/react": "^19.1.13",
|
|
62
|
+
"@types/react-dom": "^19.1.9",
|
|
63
|
+
"@vitejs/plugin-react": "^5.0.0",
|
|
64
|
+
"jsdom": "^28.0.0",
|
|
65
|
+
"react": "^19.1.1",
|
|
66
|
+
"react-dom": "^19.1.1",
|
|
67
|
+
"rimraf": "^6.1.2",
|
|
68
|
+
"typescript": "^5.6.3",
|
|
69
|
+
"vite": "^5.4.8",
|
|
70
|
+
"vitest": "^2.1.4"
|
|
71
|
+
}
|
|
72
|
+
}
|