@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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BAWANA Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # @rizal_ncc/agent-client
2
+
3
+ Frontend UI wrapper + typed helpers for `nems/ai_agent`.
4
+
5
+ `backend-documentation.md` is the source-of-truth contract for backend payload and `tool_results` schema.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @rizal_ncc/agent-client
11
+ ```
12
+
13
+ ## React Usage
14
+
15
+ ```tsx
16
+ import { AiAgentChat } from "@rizal_ncc/agent-client/react";
17
+ import "@rizal_ncc/agent-client/style.css";
18
+
19
+ export function App() {
20
+ return (
21
+ <AiAgentChat
22
+ baseURL="https://api.example.com/api"
23
+ accessToken="your-access-token-here"
24
+ agent="home-assistant"
25
+ primaryColor="#0f766e"
26
+ primaryForeground="#ffffff"
27
+ suggestedMessages={[
28
+ "recommend leadership course",
29
+ "recommend data analysis course"
30
+ ]}
31
+ />
32
+ );
33
+ }
34
+ ```
35
+
36
+ Layout examples:
37
+
38
+ ```tsx
39
+ <AiAgentChat layout="floating" defaultOpen={false} />
40
+ <AiAgentChat layout="dropdown" defaultOpen={false} panelHeight="560px" />
41
+ ```
42
+
43
+ ## Chat Component Props (AiAgentChat)
44
+
45
+ Common props:
46
+
47
+ - `baseURL: string` backend base URL
48
+ - `accessToken: string | () => string | Promise<string>` bearer token provider
49
+ - `agent?: string` default `home-assistant`
50
+ - `suggestedMessages?: string[]` clickable prompt chips
51
+ - `headerTitle?: string`
52
+ - `headerDescription?: string`
53
+ - `assistantAvatar?: ReactNode` custom avatar component slot
54
+ - `assistantAvatarUrl?: string` avatar URL override (default `/ai-img.svg`)
55
+ - `initials?: boolean` show/hide assistant and user initials (default `true`)
56
+ - `primaryColor?: string` theme color (default `#1168bb`)
57
+ - `primaryForeground?: string` text color on primary surfaces (default `#ffffff`)
58
+ - `metadata?: { course_id?: number }`
59
+ - `requestHeaders?: HeadersInit`
60
+ - `layout?: "inline" | "floating" | "dropdown"` (default `inline`)
61
+ - `open?: boolean` controlled open state for `floating`/`dropdown`
62
+ - `defaultOpen?: boolean` uncontrolled initial open state
63
+ - `onOpenChange?: (open: boolean) => void`
64
+ - `panelHeight?: string` panel height (default `"620px"`)
65
+ - `floatingPosition?: "bottom-right" | "bottom-left"` (default `bottom-right`)
66
+ - `zIndex?: number` (default `60`)
67
+
68
+ UX behavior:
69
+
70
+ - Composer uses one combined icon action button:
71
+ - idle state: send icon
72
+ - loading state: stop icon
73
+
74
+ Advanced:
75
+
76
+ - `generateResponse?: (request) => Promise<{ content: string }>` custom transport override
77
+ - `respondPath?: string` manual endpoint override
78
+ - `onMessage?`, `onError?`
79
+
80
+ Path behavior (built-in transport):
81
+
82
+ - If `baseURL` ends with `/api` -> uses `/v2/ai-agent/respond/`
83
+ - Otherwise -> uses `/api/v2/ai-agent/respond/`
84
+
85
+ Recommendation UI behavior:
86
+
87
+ - `get_course_recommendation` results are rendered as a horizontal carousel card list.
88
+ - If backend returns `next` in recommendation output, a `Load more` button appears below the carousel.
89
+ - Clicking `Load more` fetches the `next` URL automatically (with current bearer token) and appends deduplicated results.
90
+
91
+ ## Headless Core Usage
92
+
93
+ ```ts
94
+ import { ChatbotCore } from "@rizal_ncc/agent-client";
95
+
96
+ const bot = new ChatbotCore({
97
+ generateResponse: async () => ({ content: "Hello" })
98
+ });
99
+
100
+ await bot.sendMessage("Hi");
101
+ console.log(bot.getState().messages);
102
+ ```
103
+
104
+ ## Backend Tool Helpers
105
+
106
+ Helpers for backend `tool_results`:
107
+
108
+ - `getToolResultsByName(response, toolName)`
109
+ - `extractRecommendationOutput(response)`
110
+ - `extractRecommendationItems(response)`
111
+ - `extractCourseDetail(response)`
112
+ - `getToolErrors(response)`
113
+
114
+ Tool names follow backend contracts:
115
+
116
+ - `get_course_recommendation`
117
+ - `get_course_detail`
118
+
119
+ ## Exports
120
+
121
+ - Core: `@rizal_ncc/agent-client`
122
+ - React adapter: `@rizal_ncc/agent-client/react`
123
+ - Styles: `@rizal_ncc/agent-client/style.css`
124
+
125
+ ## Development
126
+
127
+ ```bash
128
+ npm install
129
+ npm run dev
130
+ npm test
131
+ npm run build
132
+ ```
133
+
134
+ `npm run dev` starts the root-level Vite playground (`index.html` + `demo/*`).
135
+
136
+ Demo env:
137
+
138
+ ```bash
139
+ VITE_API_BASE_URL=http://ncc-stg.api.bawana:8000/api/
140
+ VITE_AI_AGENT_TOKEN=<access_token>
141
+ VITE_AI_AGENT_AGENT=home-assistant
142
+ ```
@@ -0,0 +1,54 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 362.96 373.73">
3
+ <defs>
4
+ <style>
5
+ .cls-1 {
6
+ fill: url(#linear-gradient);
7
+ }
8
+
9
+ .cls-1, .cls-2, .cls-3, .cls-4 {
10
+ stroke-width: 0px;
11
+ }
12
+
13
+ .cls-2 {
14
+ fill: #002c6b;
15
+ }
16
+
17
+ .cls-3 {
18
+ fill: #6ab4e3;
19
+ }
20
+
21
+ .cls-4, .cls-5 {
22
+ fill: #fff;
23
+ }
24
+
25
+ .cls-5 {
26
+ font-family: AllianzNeoW02-Bold, AllianzNeoW02-Bold;
27
+ font-size: 73.89px;
28
+ font-weight: 700;
29
+ }
30
+ </style>
31
+ <linearGradient id="linear-gradient" x1="-112.98" y1="190.98" x2="-35.94" y2="190.06" gradientUnits="userSpaceOnUse">
32
+ <stop offset="0" stop-color="#6ab4e3"/>
33
+ <stop offset="1" stop-color="#1d62ae"/>
34
+ </linearGradient>
35
+ </defs>
36
+ <g id="Layer_2-2" data-name="Layer 2">
37
+ <g>
38
+ <g>
39
+ <g>
40
+ <path class="cls-1" d="m276.87,335.88c51.66-31.99,86.09-89.17,86.09-154.4C362.96,81.25,281.71,0,181.48,0S0,81.25,0,181.48s81.25,181.48,181.48,181.48c19.04,0,37.38-2.94,54.62-8.37,38.13,37.48,92.19,8.37,92.19,8.37-32.74,0-46.21-16.73-51.42-27.08Z"/>
41
+ <circle class="cls-3" cx="181.48" cy="181.48" r="167.03"/>
42
+ </g>
43
+ <path class="cls-2" d="m258.93,250.46c.91-2.72,2.23-5.34,1.91-8.31-.15-2.19-.26-4.39-.79-6.52-.66,1.5-.8,3.13-1.03,4.75-.88,6.74-3.03,13.43-6.96,19.03-.08.77-.66,1.29-1.32,1.61-.87.64-1.68,1.36-2.49,2.1-1.85,2.08-4.43,3.32-6.91,4.48-2.93,1.06-6.24.19-9.26.91,3.08,3.38,5.81,7.08,9.27,10.1,4.83,3.79,8.89,8.42,13.26,12.72,4.38,4.08,7.91,9.02,10.74,14.29-23.93,16.21-52.79,25.67-83.87,25.67-24.74,0-48.08-6-68.64-16.62.74-3.05,1.65-6.04,2.96-8.9,2.44-5.92,6.16-11.52,12.04-14.49,8.23-3.26,16.8-5.83,24.26-10.72l.19-.58c.9-2.73,2.71-5.19,2.97-8.11.18-3.15,1.06-6.19,1.45-9.3.9-1.73,3.2-1.96,4.8-2.8.07-1.13.19-3.39.25-4.52-2.06-7.83-5.11-15.69-10.43-21.91-2.07-.2-4.21-.03-6.15.74-5.88,2.88-11.98,5.47-18.41,6.81-3.01.79-5.57-.96-7.22-3.23-1.65-1.85-.83-4.57-.93-6.76-.46-1.92-.95-3.85-1.78-5.65-1.35-1.43-3.38-1.92-4.76-3.2-1.08-1.5-.31-3.67.13-5.26.57-1.2.72-2.53.84-3.85-2.34-1.24-5.13-1.94-6.75-4.21-.15-1.65.04-3.29-.41-4.89-.52-1.41-.98-2.86-1.85-4.1-1.3-.61-2.63-1.15-3.99-1.58-2.17-.35-3.47-2.36-4.62-4.01-1.39-1.12-.84-2.95.29-4.02.39-.4.8-.79,1.22-1.15,2.16-3.51,5.2-6.46,6.88-10.25.4-.73-.15-1.51-.28-2.23-.47-.88-.91-1.77-1.33-2.66-2.68-2.02-6.33-2.22-8.84-4.47-6.33-4.33-10.88-11.24-12.36-18.75-.29-1.02-.46-2.08-.62-3.13-.18-1.12-.3-2.25-.38-3.38l-.12-5.7c.08-12.84,5.18-25.48,13.25-35.38,2.17-2.33,4.25-4.89,7.2-6.26,3.39-2.08,6.57-4.72,10.45-5.85,1.97-.53,3.81-1.58,5.88-1.63l.4-.04c.83-.96,1.68-1.92,2.63-2.78,7.18-5.08,15.58-9.16,24.52-9.64,1.81-.36,3.52-1.08,5.23-1.76,1.06-.45,2.12-.89,3.19-1.31,1.59-.62,3.21-1.17,4.87-1.59.46-.2.92-.38,1.39-.54,2.63-.91,5.42-1.26,8.17-1.58,3.22-.62,6.55-.67,9.78,0,2.22.3,4.47.81,6.74.78.37-3.99,1.06-8.5,3.81-11.57.13-.13.4-.41.52-.54,2.46-3.31,5.57-6.12,9.46-7.63,3.04-1.41,6.39-1.94,9.5-3.16,1.69-.79,3.56-.35,5.39-.36,11.26-.89,22.39,4.72,29.72,13.06.4.41.81.82,1.21,1.23,2.35,2.08,3.48,5.09,4.96,7.77,2.27,3.29,3.35,7.22,4.53,10.99.98,2.88,1.04,5.99,1.02,9,.11,1.8-.12,3.59-.32,5.38-.15,2.25-.82,4.43-1.91,6.4-1.36,2.67-3.14,5.35-5.93,6.66-.12.34-.37,1.01-.49,1.34,1.42,3.81,4.03,6.98,5.75,10.63,1.66,3.45,3.18,7.02,4.21,10.72.53,2.06,1.24,4.1,1.29,6.25,1.15,2.81.88,5.94,1.48,8.88,1.01,2.51.27,5.32-.01,7.9-1.08,6.65-2.05,13.46-5.11,19.55-3.17,6.25-6.35,12.63-11.21,17.77-3.08,3.88-6.44,7.59-9.79,11.23,1.95,5.16,8.92,5.78,12.99,8.78,2.33.51,4.62,1.25,6.75,2.35,3.27,1.8,7.56,2.76,9.28,6.41,2.57,3.06,4.01,6.8,4.65,10.74.54,2.2.55,4.4.02,6.61.01,2.06-.79,3.95-1.86,5.67-1.2,2.7-2.64,5.31-4.57,7.56Z"/>
44
+ </g>
45
+ <path class="cls-4" d="m174.11,307.58l-8.29,22.91s-10.49-1.26-15.82-2.5l4.2-35,2.3-7.34,7.11.92s9.54,5.35,10.5,21.02"/>
46
+ <path class="cls-2" d="m154.02,294.52s3.11-3.88,6.27-8.36c3.15-4.47,0,0,0,0h0l-2.43-.34-3.65,7.17-.18,1.54"/>
47
+ <path class="cls-2" d="m161.68,287.78s-4.1,21.88-5.22,41.4h0l5.22-41.4Z"/>
48
+ <path class="cls-4" d="m154.2,292.98c-4.73,5.04-6.87,5.96-6.87,5.96,0,0,4.73-12.25,4.96-18.96.9-2.73,2.71-5.19,2.97-8.11.18-3.15,1.06-6.19,1.45-9.3.9-1.73,3.2-1.96,4.8-2.8,0,0-1.04,12.26.64,14.71,1.69,2.45-3.21,13.45-7.95,18.5Z"/>
49
+ <text class="cls-5" transform="translate(139.53 165.18)"><tspan x="0" y="0">AI</tspan></text>
50
+ <path class="cls-2" d="m173.15,310.23s-4.71-15.68-8.74-19.88-1.92-3.93-1.92-3.93c0,0,8.59,11.91,11.62,21.16,3.03,9.25,0,0,0,0l-.96,2.65Z"/>
51
+ <path class="cls-4" d="m225.44,265.35c3.64-1.82,5.73-5.72,5.25-9.76-.68-5.77-1.73-13.35-2.65-14.74-1.53-2.29-6.42-2.68-6.42-2.68,0,0,5.73,3.21,2.29,6.19-3.44,2.98-33.94,13.3-47.24,18.34-13.3,5.04-13.07,23.85-13.07,23.85,2.98,2.75,13.07,27.06,13.07,27.06,0,0,1.15-23.39,10.09-28.43,6.65-3.75,28.11-14.54,38.68-19.83Z"/>
52
+ </g>
53
+ </g>
54
+ </svg>
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class a extends Error{constructor(t,e="response_error"){super(t),this.name="AiAgentCoreError",this.code=e}}function c(s,t){return{id:`${s}_${Date.now()}_${Math.random().toString(36).slice(2,10)}`,role:s,content:t,createdAt:new Date().toISOString()}}class h{constructor(t){if(this.subscribers=new Set,this.abortController=null,!t||typeof t.generateResponse!="function")throw new a("generateResponse function is required.","invalid_config");this.config=t,this.state={messages:[],isLoading:!1}}getState(){return{messages:[...this.state.messages],isLoading:this.state.isLoading}}subscribe(t){return this.subscribers.add(t),t(this.getState()),()=>{this.subscribers.delete(t)}}stop(){this.abortController&&(this.abortController.abort(),this.abortController=null,this.setState({isLoading:!1}))}destroy(){this.stop(),this.subscribers.clear()}async sendMessage(t){const e=typeof t=="string"?t.trim():"";if(!e)return;this.abortController&&this.abortController.abort();const o=c("user",e);this.setState({messages:[...this.state.messages,o],isLoading:!0});const r=new AbortController;this.abortController=r;try{const n=await this.config.generateResponse({messages:[...this.state.messages],signal:r.signal});if(r.signal.aborted)throw new a("Generation aborted.","aborted");const i=this.createAssistantMessage(n),l=[...this.state.messages,i];return this.setState({messages:l,isLoading:!1}),typeof this.config.onMessage=="function"&&this.config.onMessage(i,[...l]),i}catch(n){if(r.signal.aborted){this.setState({isLoading:!1});return}const i=n instanceof Error?n:new a("Failed to generate assistant response.");throw this.setState({isLoading:!1}),typeof this.config.onError=="function"&&this.config.onError(i,[...this.state.messages]),i}finally{this.abortController===r&&(this.abortController=null)}}updateMessageById(t,e){const o=this.state.messages.findIndex(n=>n.id===t);if(o<0)return;const r=[...this.state.messages];r[o]=e(r[o]),this.setState({messages:r})}createAssistantMessage(t){var o;const e=t&&typeof t.content=="string"?t.content.trim():"";if(!e)throw new a("generateResponse must return a non-empty content string.","response_error");return{...c("assistant",e),usage:t.usage,recommendations:t.recommendations,recommendationNext:(o=t.recommendationNext)!=null?o:null,toolResults:t.toolResults}}setState(t){this.state={messages:t.messages?[...t.messages]:this.state.messages,isLoading:typeof t.isLoading=="boolean"?t.isLoading:this.state.isLoading};const e=this.getState();for(const o of this.subscribers)o(e)}}function g(s){return Array.isArray(s.tool_results)?s.tool_results:[]}function u(s,t){return g(s).filter(e=>(e==null?void 0:e.name)===t)}function d(s){return g(s).map(t=>{const e=t.output;return typeof(e==null?void 0:e.error)=="string"?e.error:""}).filter(Boolean)}function m(s){const t=u(s,"get_course_detail")[0];if(!t||!t.output||typeof t.output!="object")return null;const e=t.output;return!e.course||typeof e.course!="object"?null:e}function f(s){const t=u(s,"get_course_recommendation")[0];if(!t||!t.output||typeof t.output!="object")return null;const e=t.output;return Array.isArray(e.results)?{count:typeof e.count=="number"?e.count:e.results.length,next:typeof e.next=="string"||e.next===null?e.next:null,previous:typeof e.previous=="string"||e.previous===null?e.previous:null,results:e.results}:null}function p(s){const t=f(s);return t?t.results:[]}exports.AiAgentCoreError=a;exports.ChatbotCore=h;exports.extractCourseDetail=m;exports.extractRecommendationItems=p;exports.extractRecommendationOutput=f;exports.getToolErrors=d;exports.getToolResultsByName=u;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/core/errors.ts","../src/core/chatbot.ts","../src/lib/tool-results.ts"],"sourcesContent":["export class AiAgentCoreError extends Error {\r\n readonly code: \"invalid_config\" | \"aborted\" | \"response_error\";\r\n\r\n constructor(\r\n message: string,\r\n code: \"invalid_config\" | \"aborted\" | \"response_error\" = \"response_error\"\r\n ) {\r\n super(message);\r\n this.name = \"AiAgentCoreError\";\r\n this.code = code;\r\n }\r\n}\r\n","import { AiAgentCoreError } from \"./errors\";\r\nimport type {\r\n ChatMessage,\r\n ChatbotCoreConfig,\r\n ChatbotState,\r\n ChatbotSubscriber,\r\n GenerateResponseResult\r\n} from \"./types\";\r\n\r\nfunction createMessage(role: ChatMessage[\"role\"], content: string): ChatMessage {\r\n return {\r\n id: `${role}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,\r\n role,\r\n content,\r\n createdAt: new Date().toISOString()\r\n };\r\n}\r\n\r\nexport class ChatbotCore {\r\n private config: ChatbotCoreConfig;\r\n private subscribers = new Set<ChatbotSubscriber>();\r\n private state: ChatbotState;\r\n private abortController: AbortController | null = null;\r\n\r\n constructor(config: ChatbotCoreConfig) {\r\n if (!config || typeof config.generateResponse !== \"function\") {\r\n throw new AiAgentCoreError(\r\n \"generateResponse function is required.\",\r\n \"invalid_config\"\r\n );\r\n }\r\n\r\n this.config = config;\r\n this.state = {\r\n messages: [],\r\n isLoading: false\r\n };\r\n }\r\n\r\n getState(): ChatbotState {\r\n return {\r\n messages: [...this.state.messages],\r\n isLoading: this.state.isLoading\r\n };\r\n }\r\n\r\n subscribe(subscriber: ChatbotSubscriber): () => void {\r\n this.subscribers.add(subscriber);\r\n subscriber(this.getState());\r\n return () => {\r\n this.subscribers.delete(subscriber);\r\n };\r\n }\r\n\r\n stop(): void {\r\n if (this.abortController) {\r\n this.abortController.abort();\r\n this.abortController = null;\r\n this.setState({ isLoading: false });\r\n }\r\n }\r\n\r\n destroy(): void {\r\n this.stop();\r\n this.subscribers.clear();\r\n }\r\n\r\n async sendMessage(text: string): Promise<ChatMessage | undefined> {\r\n const message = typeof text === \"string\" ? text.trim() : \"\";\r\n if (!message) {\r\n return undefined;\r\n }\r\n\r\n if (this.abortController) {\r\n this.abortController.abort();\r\n }\r\n\r\n const userMessage = createMessage(\"user\", message);\r\n this.setState({\r\n messages: [...this.state.messages, userMessage],\r\n isLoading: true\r\n });\r\n\r\n const controller = new AbortController();\r\n this.abortController = controller;\r\n\r\n try {\r\n const response = await this.config.generateResponse({\r\n messages: [...this.state.messages],\r\n signal: controller.signal\r\n });\r\n\r\n if (controller.signal.aborted) {\r\n throw new AiAgentCoreError(\"Generation aborted.\", \"aborted\");\r\n }\r\n\r\n const assistantMessage = this.createAssistantMessage(response);\r\n const nextMessages = [...this.state.messages, assistantMessage];\r\n\r\n this.setState({\r\n messages: nextMessages,\r\n isLoading: false\r\n });\r\n\r\n if (typeof this.config.onMessage === \"function\") {\r\n this.config.onMessage(assistantMessage, [...nextMessages]);\r\n }\r\n\r\n return assistantMessage;\r\n } catch (error) {\r\n if (controller.signal.aborted) {\r\n this.setState({ isLoading: false });\r\n return undefined;\r\n }\r\n\r\n const normalizedError =\r\n error instanceof Error\r\n ? error\r\n : new AiAgentCoreError(\"Failed to generate assistant response.\");\r\n\r\n this.setState({ isLoading: false });\r\n\r\n if (typeof this.config.onError === \"function\") {\r\n this.config.onError(normalizedError, [...this.state.messages]);\r\n }\r\n\r\n throw normalizedError;\r\n } finally {\r\n if (this.abortController === controller) {\r\n this.abortController = null;\r\n }\r\n }\r\n }\r\n\r\n updateMessageById(\r\n messageId: string,\r\n updater: (message: ChatMessage) => ChatMessage\r\n ): void {\r\n const index = this.state.messages.findIndex((message) => message.id === messageId);\r\n if (index < 0) {\r\n return;\r\n }\r\n\r\n const nextMessages = [...this.state.messages];\r\n nextMessages[index] = updater(nextMessages[index]);\r\n this.setState({ messages: nextMessages });\r\n }\r\n\r\n private createAssistantMessage(response: GenerateResponseResult): ChatMessage {\r\n const content =\r\n response && typeof response.content === \"string\" ? response.content.trim() : \"\";\r\n\r\n if (!content) {\r\n throw new AiAgentCoreError(\r\n \"generateResponse must return a non-empty content string.\",\r\n \"response_error\"\r\n );\r\n }\r\n\r\n return {\r\n ...createMessage(\"assistant\", content),\r\n usage: response.usage,\r\n recommendations: response.recommendations,\r\n recommendationNext: response.recommendationNext ?? null,\r\n toolResults: response.toolResults\r\n };\r\n }\r\n\r\n private setState(next: Partial<ChatbotState>): void {\r\n this.state = {\r\n messages: next.messages ? [...next.messages] : this.state.messages,\r\n isLoading: typeof next.isLoading === \"boolean\" ? next.isLoading : this.state.isLoading\r\n };\r\n\r\n const snapshot = this.getState();\r\n for (const subscriber of this.subscribers) {\r\n subscriber(snapshot);\r\n }\r\n }\r\n}\r\n","import type {\r\n CourseDetailOutput,\r\n RecommendationOutput,\r\n RespondResponse,\r\n ToolResult\r\n} from \"../core/types\";\r\n\r\nfunction ensureToolResults(response: RespondResponse): ToolResult[] {\r\n return Array.isArray(response.tool_results) ? response.tool_results : [];\r\n}\r\n\r\nexport function getToolResultsByName(\r\n response: RespondResponse,\r\n toolName: string\r\n): ToolResult[] {\r\n return ensureToolResults(response).filter((item) => item?.name === toolName);\r\n}\r\n\r\nexport function getToolErrors(response: RespondResponse): string[] {\r\n return ensureToolResults(response)\r\n .map((item) => {\r\n const output = item.output as { error?: unknown };\r\n return typeof output?.error === \"string\" ? output.error : \"\";\r\n })\r\n .filter(Boolean);\r\n}\r\n\r\nexport function extractCourseDetail(\r\n response: RespondResponse\r\n): CourseDetailOutput | null {\r\n const first = getToolResultsByName(response, \"get_course_detail\")[0];\r\n if (!first || !first.output || typeof first.output !== \"object\") {\r\n return null;\r\n }\r\n\r\n const output = first.output as Partial<CourseDetailOutput>;\r\n if (!output.course || typeof output.course !== \"object\") {\r\n return null;\r\n }\r\n\r\n return output as CourseDetailOutput;\r\n}\r\n\r\nexport function extractRecommendationOutput(\r\n response: RespondResponse\r\n): RecommendationOutput | null {\r\n const first = getToolResultsByName(response, \"get_course_recommendation\")[0];\r\n if (!first || !first.output || typeof first.output !== \"object\") {\r\n return null;\r\n }\r\n\r\n const output = first.output as Partial<RecommendationOutput>;\r\n if (!Array.isArray(output.results)) {\r\n return null;\r\n }\r\n\r\n return {\r\n count: typeof output.count === \"number\" ? output.count : output.results.length,\r\n next: typeof output.next === \"string\" || output.next === null ? output.next : null,\r\n previous:\r\n typeof output.previous === \"string\" || output.previous === null\r\n ? output.previous\r\n : null,\r\n results: output.results\r\n } as RecommendationOutput;\r\n}\r\n\r\nexport function extractRecommendationItems(response: RespondResponse) {\r\n const output = extractRecommendationOutput(response);\r\n return output ? output.results : [];\r\n}\r\n"],"names":["AiAgentCoreError","message","code","createMessage","role","content","ChatbotCore","config","subscriber","text","userMessage","controller","response","assistantMessage","nextMessages","error","normalizedError","messageId","updater","index","_a","next","snapshot","ensureToolResults","getToolResultsByName","toolName","item","getToolErrors","output","extractCourseDetail","first","extractRecommendationOutput","extractRecommendationItems"],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1,155 @@
1
+ class a extends Error {
2
+ constructor(t, e = "response_error") {
3
+ super(t), this.name = "AiAgentCoreError", this.code = e;
4
+ }
5
+ }
6
+ function l(s, t) {
7
+ return {
8
+ id: `${s}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
9
+ role: s,
10
+ content: t,
11
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
12
+ };
13
+ }
14
+ class h {
15
+ constructor(t) {
16
+ if (this.subscribers = /* @__PURE__ */ new Set(), this.abortController = null, !t || typeof t.generateResponse != "function")
17
+ throw new a(
18
+ "generateResponse function is required.",
19
+ "invalid_config"
20
+ );
21
+ this.config = t, this.state = {
22
+ messages: [],
23
+ isLoading: !1
24
+ };
25
+ }
26
+ getState() {
27
+ return {
28
+ messages: [...this.state.messages],
29
+ isLoading: this.state.isLoading
30
+ };
31
+ }
32
+ subscribe(t) {
33
+ return this.subscribers.add(t), t(this.getState()), () => {
34
+ this.subscribers.delete(t);
35
+ };
36
+ }
37
+ stop() {
38
+ this.abortController && (this.abortController.abort(), this.abortController = null, this.setState({ isLoading: !1 }));
39
+ }
40
+ destroy() {
41
+ this.stop(), this.subscribers.clear();
42
+ }
43
+ async sendMessage(t) {
44
+ const e = typeof t == "string" ? t.trim() : "";
45
+ if (!e)
46
+ return;
47
+ this.abortController && this.abortController.abort();
48
+ const o = l("user", e);
49
+ this.setState({
50
+ messages: [...this.state.messages, o],
51
+ isLoading: !0
52
+ });
53
+ const r = new AbortController();
54
+ this.abortController = r;
55
+ try {
56
+ const n = await this.config.generateResponse({
57
+ messages: [...this.state.messages],
58
+ signal: r.signal
59
+ });
60
+ if (r.signal.aborted)
61
+ throw new a("Generation aborted.", "aborted");
62
+ const i = this.createAssistantMessage(n), u = [...this.state.messages, i];
63
+ return this.setState({
64
+ messages: u,
65
+ isLoading: !1
66
+ }), typeof this.config.onMessage == "function" && this.config.onMessage(i, [...u]), i;
67
+ } catch (n) {
68
+ if (r.signal.aborted) {
69
+ this.setState({ isLoading: !1 });
70
+ return;
71
+ }
72
+ const i = n instanceof Error ? n : new a("Failed to generate assistant response.");
73
+ throw this.setState({ isLoading: !1 }), typeof this.config.onError == "function" && this.config.onError(i, [...this.state.messages]), i;
74
+ } finally {
75
+ this.abortController === r && (this.abortController = null);
76
+ }
77
+ }
78
+ updateMessageById(t, e) {
79
+ const o = this.state.messages.findIndex((n) => n.id === t);
80
+ if (o < 0)
81
+ return;
82
+ const r = [...this.state.messages];
83
+ r[o] = e(r[o]), this.setState({ messages: r });
84
+ }
85
+ createAssistantMessage(t) {
86
+ var o;
87
+ const e = t && typeof t.content == "string" ? t.content.trim() : "";
88
+ if (!e)
89
+ throw new a(
90
+ "generateResponse must return a non-empty content string.",
91
+ "response_error"
92
+ );
93
+ return {
94
+ ...l("assistant", e),
95
+ usage: t.usage,
96
+ recommendations: t.recommendations,
97
+ recommendationNext: (o = t.recommendationNext) != null ? o : null,
98
+ toolResults: t.toolResults
99
+ };
100
+ }
101
+ setState(t) {
102
+ this.state = {
103
+ messages: t.messages ? [...t.messages] : this.state.messages,
104
+ isLoading: typeof t.isLoading == "boolean" ? t.isLoading : this.state.isLoading
105
+ };
106
+ const e = this.getState();
107
+ for (const o of this.subscribers)
108
+ o(e);
109
+ }
110
+ }
111
+ function c(s) {
112
+ return Array.isArray(s.tool_results) ? s.tool_results : [];
113
+ }
114
+ function g(s, t) {
115
+ return c(s).filter((e) => (e == null ? void 0 : e.name) === t);
116
+ }
117
+ function d(s) {
118
+ return c(s).map((t) => {
119
+ const e = t.output;
120
+ return typeof (e == null ? void 0 : e.error) == "string" ? e.error : "";
121
+ }).filter(Boolean);
122
+ }
123
+ function m(s) {
124
+ const t = g(s, "get_course_detail")[0];
125
+ if (!t || !t.output || typeof t.output != "object")
126
+ return null;
127
+ const e = t.output;
128
+ return !e.course || typeof e.course != "object" ? null : e;
129
+ }
130
+ function f(s) {
131
+ const t = g(s, "get_course_recommendation")[0];
132
+ if (!t || !t.output || typeof t.output != "object")
133
+ return null;
134
+ const e = t.output;
135
+ return Array.isArray(e.results) ? {
136
+ count: typeof e.count == "number" ? e.count : e.results.length,
137
+ next: typeof e.next == "string" || e.next === null ? e.next : null,
138
+ previous: typeof e.previous == "string" || e.previous === null ? e.previous : null,
139
+ results: e.results
140
+ } : null;
141
+ }
142
+ function p(s) {
143
+ const t = f(s);
144
+ return t ? t.results : [];
145
+ }
146
+ export {
147
+ a as AiAgentCoreError,
148
+ h as ChatbotCore,
149
+ m as extractCourseDetail,
150
+ p as extractRecommendationItems,
151
+ f as extractRecommendationOutput,
152
+ d as getToolErrors,
153
+ g as getToolResultsByName
154
+ };
155
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/core/errors.ts","../src/core/chatbot.ts","../src/lib/tool-results.ts"],"sourcesContent":["export class AiAgentCoreError extends Error {\r\n readonly code: \"invalid_config\" | \"aborted\" | \"response_error\";\r\n\r\n constructor(\r\n message: string,\r\n code: \"invalid_config\" | \"aborted\" | \"response_error\" = \"response_error\"\r\n ) {\r\n super(message);\r\n this.name = \"AiAgentCoreError\";\r\n this.code = code;\r\n }\r\n}\r\n","import { AiAgentCoreError } from \"./errors\";\r\nimport type {\r\n ChatMessage,\r\n ChatbotCoreConfig,\r\n ChatbotState,\r\n ChatbotSubscriber,\r\n GenerateResponseResult\r\n} from \"./types\";\r\n\r\nfunction createMessage(role: ChatMessage[\"role\"], content: string): ChatMessage {\r\n return {\r\n id: `${role}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,\r\n role,\r\n content,\r\n createdAt: new Date().toISOString()\r\n };\r\n}\r\n\r\nexport class ChatbotCore {\r\n private config: ChatbotCoreConfig;\r\n private subscribers = new Set<ChatbotSubscriber>();\r\n private state: ChatbotState;\r\n private abortController: AbortController | null = null;\r\n\r\n constructor(config: ChatbotCoreConfig) {\r\n if (!config || typeof config.generateResponse !== \"function\") {\r\n throw new AiAgentCoreError(\r\n \"generateResponse function is required.\",\r\n \"invalid_config\"\r\n );\r\n }\r\n\r\n this.config = config;\r\n this.state = {\r\n messages: [],\r\n isLoading: false\r\n };\r\n }\r\n\r\n getState(): ChatbotState {\r\n return {\r\n messages: [...this.state.messages],\r\n isLoading: this.state.isLoading\r\n };\r\n }\r\n\r\n subscribe(subscriber: ChatbotSubscriber): () => void {\r\n this.subscribers.add(subscriber);\r\n subscriber(this.getState());\r\n return () => {\r\n this.subscribers.delete(subscriber);\r\n };\r\n }\r\n\r\n stop(): void {\r\n if (this.abortController) {\r\n this.abortController.abort();\r\n this.abortController = null;\r\n this.setState({ isLoading: false });\r\n }\r\n }\r\n\r\n destroy(): void {\r\n this.stop();\r\n this.subscribers.clear();\r\n }\r\n\r\n async sendMessage(text: string): Promise<ChatMessage | undefined> {\r\n const message = typeof text === \"string\" ? text.trim() : \"\";\r\n if (!message) {\r\n return undefined;\r\n }\r\n\r\n if (this.abortController) {\r\n this.abortController.abort();\r\n }\r\n\r\n const userMessage = createMessage(\"user\", message);\r\n this.setState({\r\n messages: [...this.state.messages, userMessage],\r\n isLoading: true\r\n });\r\n\r\n const controller = new AbortController();\r\n this.abortController = controller;\r\n\r\n try {\r\n const response = await this.config.generateResponse({\r\n messages: [...this.state.messages],\r\n signal: controller.signal\r\n });\r\n\r\n if (controller.signal.aborted) {\r\n throw new AiAgentCoreError(\"Generation aborted.\", \"aborted\");\r\n }\r\n\r\n const assistantMessage = this.createAssistantMessage(response);\r\n const nextMessages = [...this.state.messages, assistantMessage];\r\n\r\n this.setState({\r\n messages: nextMessages,\r\n isLoading: false\r\n });\r\n\r\n if (typeof this.config.onMessage === \"function\") {\r\n this.config.onMessage(assistantMessage, [...nextMessages]);\r\n }\r\n\r\n return assistantMessage;\r\n } catch (error) {\r\n if (controller.signal.aborted) {\r\n this.setState({ isLoading: false });\r\n return undefined;\r\n }\r\n\r\n const normalizedError =\r\n error instanceof Error\r\n ? error\r\n : new AiAgentCoreError(\"Failed to generate assistant response.\");\r\n\r\n this.setState({ isLoading: false });\r\n\r\n if (typeof this.config.onError === \"function\") {\r\n this.config.onError(normalizedError, [...this.state.messages]);\r\n }\r\n\r\n throw normalizedError;\r\n } finally {\r\n if (this.abortController === controller) {\r\n this.abortController = null;\r\n }\r\n }\r\n }\r\n\r\n updateMessageById(\r\n messageId: string,\r\n updater: (message: ChatMessage) => ChatMessage\r\n ): void {\r\n const index = this.state.messages.findIndex((message) => message.id === messageId);\r\n if (index < 0) {\r\n return;\r\n }\r\n\r\n const nextMessages = [...this.state.messages];\r\n nextMessages[index] = updater(nextMessages[index]);\r\n this.setState({ messages: nextMessages });\r\n }\r\n\r\n private createAssistantMessage(response: GenerateResponseResult): ChatMessage {\r\n const content =\r\n response && typeof response.content === \"string\" ? response.content.trim() : \"\";\r\n\r\n if (!content) {\r\n throw new AiAgentCoreError(\r\n \"generateResponse must return a non-empty content string.\",\r\n \"response_error\"\r\n );\r\n }\r\n\r\n return {\r\n ...createMessage(\"assistant\", content),\r\n usage: response.usage,\r\n recommendations: response.recommendations,\r\n recommendationNext: response.recommendationNext ?? null,\r\n toolResults: response.toolResults\r\n };\r\n }\r\n\r\n private setState(next: Partial<ChatbotState>): void {\r\n this.state = {\r\n messages: next.messages ? [...next.messages] : this.state.messages,\r\n isLoading: typeof next.isLoading === \"boolean\" ? next.isLoading : this.state.isLoading\r\n };\r\n\r\n const snapshot = this.getState();\r\n for (const subscriber of this.subscribers) {\r\n subscriber(snapshot);\r\n }\r\n }\r\n}\r\n","import type {\r\n CourseDetailOutput,\r\n RecommendationOutput,\r\n RespondResponse,\r\n ToolResult\r\n} from \"../core/types\";\r\n\r\nfunction ensureToolResults(response: RespondResponse): ToolResult[] {\r\n return Array.isArray(response.tool_results) ? response.tool_results : [];\r\n}\r\n\r\nexport function getToolResultsByName(\r\n response: RespondResponse,\r\n toolName: string\r\n): ToolResult[] {\r\n return ensureToolResults(response).filter((item) => item?.name === toolName);\r\n}\r\n\r\nexport function getToolErrors(response: RespondResponse): string[] {\r\n return ensureToolResults(response)\r\n .map((item) => {\r\n const output = item.output as { error?: unknown };\r\n return typeof output?.error === \"string\" ? output.error : \"\";\r\n })\r\n .filter(Boolean);\r\n}\r\n\r\nexport function extractCourseDetail(\r\n response: RespondResponse\r\n): CourseDetailOutput | null {\r\n const first = getToolResultsByName(response, \"get_course_detail\")[0];\r\n if (!first || !first.output || typeof first.output !== \"object\") {\r\n return null;\r\n }\r\n\r\n const output = first.output as Partial<CourseDetailOutput>;\r\n if (!output.course || typeof output.course !== \"object\") {\r\n return null;\r\n }\r\n\r\n return output as CourseDetailOutput;\r\n}\r\n\r\nexport function extractRecommendationOutput(\r\n response: RespondResponse\r\n): RecommendationOutput | null {\r\n const first = getToolResultsByName(response, \"get_course_recommendation\")[0];\r\n if (!first || !first.output || typeof first.output !== \"object\") {\r\n return null;\r\n }\r\n\r\n const output = first.output as Partial<RecommendationOutput>;\r\n if (!Array.isArray(output.results)) {\r\n return null;\r\n }\r\n\r\n return {\r\n count: typeof output.count === \"number\" ? output.count : output.results.length,\r\n next: typeof output.next === \"string\" || output.next === null ? output.next : null,\r\n previous:\r\n typeof output.previous === \"string\" || output.previous === null\r\n ? output.previous\r\n : null,\r\n results: output.results\r\n } as RecommendationOutput;\r\n}\r\n\r\nexport function extractRecommendationItems(response: RespondResponse) {\r\n const output = extractRecommendationOutput(response);\r\n return output ? output.results : [];\r\n}\r\n"],"names":["AiAgentCoreError","message","code","createMessage","role","content","ChatbotCore","config","subscriber","text","userMessage","controller","response","assistantMessage","nextMessages","error","normalizedError","messageId","updater","index","_a","next","snapshot","ensureToolResults","getToolResultsByName","toolName","item","getToolErrors","output","extractCourseDetail","first","extractRecommendationOutput","extractRecommendationItems"],"mappings":"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"}
package/dist/react.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),r=require("react"),K=require("./index.cjs");function ke(a){if(!a||typeof a!="object")return null;const t=a;return typeof t.title!="string"||typeof t.url!="string"?null:{id:typeof t.id=="number"||typeof t.id=="string"||t.id===null?t.id:null,title:t.title,description:typeof t.description=="string"?t.description:"",url:t.url,type:typeof t.type=="string"?t.type:"Course",status:typeof t.status=="string"||t.status===null?t.status:null,progress:typeof t.progress=="number"||t.progress===null?t.progress:null,is_eligible:!!t.is_eligible,in_playlist:!!t.in_playlist}}function Ae(a,t){const c=Array.isArray(a)?[...a]:[];for(const h of t){const u=ke(h);u&&c.push(u)}return c}const we={};function ue(a){const t=r.useRef(null),[c,h]=r.useState({messages:[],isLoading:!1});r.useEffect(()=>{const m=new K.ChatbotCore(a);t.current=m;const b=m.subscribe(C=>{h(C)});return()=>{b(),m.destroy(),t.current=null}},[a]);const u=r.useCallback(async m=>{if(t.current)return t.current.sendMessage(m)},[]),x=r.useCallback(()=>{t.current&&t.current.stop()},[]),v=r.useCallback((m,b)=>{t.current&&t.current.updateMessageById(m,b)},[]);return{...c,sendMessage:u,stop:x,updateMessageById:v}}async function he(a){if(!a)return;if(typeof a=="string")return a.trim()||void 0;const t=await a();return typeof t=="string"&&t.trim()||void 0}function Q(a){return a.replace(/\/+$/,"")}function Me(a){const t=a.trim().replace("#","");if(![3,6].includes(t.length)||!/^[a-fA-F0-9]+$/.test(t))return null;const c=t.length===3?t.split("").map(v=>`${v}${v}`).join(""):t,h=Number.parseInt(c.slice(0,2),16),u=Number.parseInt(c.slice(2,4),16),x=Number.parseInt(c.slice(4,6),16);return`${h}, ${u}, ${x}`}function $e(a){const t=Me(a);if(t)return t;const c=a.match(/rgba?\(([^)]+)\)/i);if(!c)return"17, 104, 187";const h=c[1].split(",").slice(0,3).map(u=>Number.parseFloat(u.trim())).filter(u=>Number.isFinite(u));return h.length!==3?"17, 104, 187":`${h[0]}, ${h[1]}, ${h[2]}`}function Ce(a,t){return t&&t.trim()?Se(t.trim()):Q(a).endsWith("/api")?"/v2/ai-agent/respond/":"/api/v2/ai-agent/respond/"}function Se(a){return a?a.startsWith("/")?a:`/${a}`:"/api/v2/ai-agent/respond/"}function Be({generateResponse:a,baseURL:t,accessToken:c,agent:h="home-assistant",metadata:u,requestHeaders:x,respondPath:v="/api/v2/ai-agent/respond/",suggestedMessages:m=[],headerTitle:b="BAWANA Assistant",headerDescription:C="Online and ready to help",assistantAvatar:S,assistantAvatarUrl:B="/ai-img.svg",assistantInitials:E="AI",userInitials:ge="YOU",initials:R=!0,primaryColor:Z="#1168bb",primaryForeground:X="#ffffff",onMessage:L,onError:H,className:me="",placeholder:pe="Ask the assistant...",sendLabel:U="Send",stopLabel:ee="Stop",layout:j="inline",open:te,defaultOpen:k,onOpenChange:Y,panelHeight:z,floatingPosition:fe="bottom-right",zIndex:se=60,openLabel:I="Open chat",closeLabel:F="Close chat"}){const[P,D]=r.useState(""),[ae,y]=r.useState(""),[A,ne]=r.useState({}),[xe,T]=r.useState(()=>j==="inline"?!0:typeof k=="boolean"?k:!1),re=r.useRef(null),ie=r.useMemo(()=>u||we,[u]),le=r.useMemo(()=>Array.isArray(m)?m.filter(s=>typeof s=="string"&&s.trim().length>0):[],[m]),ce=r.useCallback(async({messages:s,signal:n})=>{var q;if(typeof a=="function")return a({messages:s,signal:n});if(!t||!t.trim())throw new Error("AiAgentChat requires `baseURL` when `generateResponse` is not provided.");const d=await he(c);if(!d)throw new Error("AiAgentChat requires `accessToken` when `generateResponse` is not provided.");const l=new Headers(x);l.set("content-type","application/json"),l.set("authorization",`Bearer ${d}`);const _=[...s].reverse().find(O=>O.role==="user"),N=(_==null?void 0:_.content)||"",i=Ce(t,v),M=await fetch(`${Q(t)}${i}`,{method:"POST",headers:l,body:JSON.stringify({agent:h,message:N,metadata:ie}),signal:n}),p=await M.json();if(!M.ok){const O=typeof p=="object"&&p?"detail"in p&&typeof p.detail=="string"?p.detail:"message"in p&&typeof p.message=="string"?p.message:"":"";throw new Error(`AI Agent request failed (${M.status})${O?`: ${O}`:""}`)}const f=p,$=K.extractRecommendationOutput(f);return{content:f.message,toolResults:f.tool_results,recommendations:K.extractRecommendationItems(f),recommendationNext:(q=$==null?void 0:$.next)!=null?q:null}},[c,h,t,a,x,v,ie]),je=r.useMemo(()=>({generateResponse:ce,onMessage:L,onError:(s,n)=>{y(s.message),typeof H=="function"&&H(s,n)}}),[H,L,ce]),{messages:V,isLoading:o,sendMessage:W,stop:ye,updateMessageById:oe}=ue(je),_e=r.useCallback(async s=>{s.preventDefault();const n=P.trim();if(!(!n.length||o)){y(""),D("");try{await W(n)}catch(d){const l=d instanceof Error?d.message:"Failed to send message.";y(l)}}},[P,o,W]),Ne=r.useCallback(async s=>{if(!o){y(""),D("");try{await W(s)}catch(n){const d=n instanceof Error?n.message:"Failed to send message.";y(d)}}},[o,W]),ve=V.some(s=>s.role==="user"),w=typeof te=="boolean",g=j==="inline"?!0:w?te:xe,de=r.useCallback(s=>{j!=="inline"&&(w||T(s),typeof Y=="function"&&Y(s))},[w,j,Y]);r.useEffect(()=>{if(!w){if(j==="inline"){T(!0);return}if(typeof k=="boolean"){T(k);return}T(!1)}},[k,w,j]),r.useEffect(()=>{const s=re.current;s&&(s.scrollTop=s.scrollHeight)},[V,o]);const be=r.useCallback(async(s,n)=>{if(!n||A[s])return;if(!t||!t.trim()){y("Cannot load more: baseURL is missing.");return}const d=await he(c);if(!d){y("Cannot load more: accessToken is missing.");return}ne(l=>({...l,[s]:!0}));try{const l=new Headers(x);l.set("authorization",`Bearer ${d}`);const _=new URL(n,`${Q(t)}/`).toString(),N=await fetch(_,{method:"GET",headers:l}),i=await N.json();if(!N.ok){const f=typeof(i==null?void 0:i.detail)=="string"?i.detail:typeof(i==null?void 0:i.message)=="string"?i.message:"";throw new Error(`Load more failed (${N.status})${f?`: ${f}`:""}`)}const M=Array.isArray(i==null?void 0:i.results)?i.results:[],p=typeof(i==null?void 0:i.next)=="string"||(i==null?void 0:i.next)===null?i.next:null;oe(s,f=>{const $=Array.isArray(f.recommendations)?f.recommendations:[],q=Ae($,M);return{...f,recommendations:q,recommendationNext:p}})}catch(l){y(l instanceof Error?l.message:"Failed to load more recommendations.")}finally{ne(l=>({...l,[s]:!1}))}},[c,t,A,x,oe]),G=r.useMemo(()=>({"--chat-primary":Z,"--chat-primary-rgb":$e(Z),"--chat-primary-foreground":X,...typeof z=="string"&&z.trim()?{"--chat-panel-height":z.trim()}:{},"--chat-shell-z-index":se}),[z,Z,X,se]),J=e.jsxs("section",{className:`ai-agent-chat ${me}`.trim(),children:[e.jsxs("header",{className:"ai-agent-chat__header",children:[e.jsx("div",{className:"ai-agent-chat__header-avatar","aria-hidden":"true",children:S||(B?e.jsx("img",{src:B,alt:""}):R?E:"")}),e.jsxs("div",{className:"ai-agent-chat__header-copy",children:[e.jsx("strong",{children:b}),e.jsx("span",{children:C})]})]}),e.jsxs("div",{className:"ai-agent-chat__messages",role:"log","aria-live":"polite",ref:re,children:[!V.length&&!o?e.jsxs("div",{className:"ai-agent-chat__empty","aria-hidden":"true",children:[e.jsx("div",{className:"ai-agent-chat__empty-icon",children:e.jsxs("svg",{viewBox:"0 0 24 24",focusable:"false",children:[e.jsx("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"}),e.jsx("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"})]})}),e.jsx("strong",{children:"Start a conversation"}),e.jsx("span",{children:"Ask about courses, recommendations, or learning plans."})]}):null,V.map(s=>e.jsxs("article",{className:`ai-agent-chat__message ai-agent-chat__message--${s.role}`,children:[R?e.jsx("span",{className:"ai-agent-chat__message-role",children:s.role==="assistant"?E:ge}):null,e.jsx("p",{children:s.content}),Array.isArray(s.recommendations)&&s.recommendations.length>0?e.jsxs("div",{className:"ai-agent-chat__recommendation-block",children:[e.jsxs("div",{className:"chat-carousel",children:[s.recommendations.map(n=>{const d=typeof n.status=="string"&&n.status.trim()?n.status.trim():"",l=typeof n.type=="string"&&n.type.trim()?n.type.trim():"",_=typeof n.progress=="number"&&Number.isFinite(n.progress),N=_?Math.min(100,Math.max(0,Math.round(n.progress))):0;return e.jsxs("a",{className:"chat-carousel-card",href:n.url||"#",target:"_blank",rel:"noreferrer",children:[e.jsxs("div",{className:"chat-carousel-card-header",children:[l?e.jsx("span",{className:"chat-carousel-chip chat-carousel-chip--type",children:l}):null,d?e.jsx("span",{className:"chat-carousel-chip chat-carousel-chip--status","data-status":d.toLowerCase(),children:d}):null,n.in_playlist?e.jsx("span",{className:"chat-carousel-chip chat-carousel-chip--muted",children:"In playlist"}):null]}),e.jsxs("div",{className:"chat-carousel-card-content",children:[e.jsx("div",{className:"chat-carousel-card-title",children:n.title||"Untitled Course"}),e.jsx("div",{className:"chat-carousel-card-desc",children:n.description||""})]}),e.jsxs("div",{className:"chat-carousel-card-footer",children:[e.jsx("div",{className:"chat-carousel-meta",children:_?e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"chat-carousel-meta-text",children:[N,"% complete"]}),e.jsx("div",{className:"chat-carousel-progress",children:e.jsx("div",{className:"chat-carousel-progress-bar",style:{width:`${N}%`}})})]}):null}),e.jsxs("div",{className:"chat-carousel-cta",children:[e.jsx("span",{children:"View course"}),e.jsx("span",{className:"chat-carousel-cta-icon"})]})]})]},`${n.id||n.title}`)}),A[s.id]?Array.from({length:3}).map((n,d)=>e.jsxs("div",{className:"chat-carousel-card chat-carousel-card--skeleton","aria-hidden":"true",children:[e.jsx("div",{className:"chat-carousel-skeleton-line chat-carousel-skeleton-line--chip"}),e.jsx("div",{className:"chat-carousel-skeleton-line chat-carousel-skeleton-line--title"}),e.jsx("div",{className:"chat-carousel-skeleton-line chat-carousel-skeleton-line--desc"}),e.jsx("div",{className:"chat-carousel-skeleton-line chat-carousel-skeleton-line--desc-short"}),e.jsx("div",{className:"chat-carousel-skeleton-line chat-carousel-skeleton-line--cta"})]},`skeleton-${s.id}-${d}`)):null]}),s.recommendationNext?e.jsx("button",{type:"button",className:"ai-agent-chat__loadmore",onClick:()=>void be(s.id,s.recommendationNext),disabled:!!A[s.id],children:A[s.id]?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"ai-agent-chat__spinner","aria-hidden":"true"}),"Loading..."]}):"Load more"}):null]}):null]},s.id)),o?e.jsxs("article",{className:"ai-agent-chat__message ai-agent-chat__message--assistant ai-agent-chat__message--typing",children:[R?e.jsx("span",{className:"ai-agent-chat__message-role",children:E}):null,e.jsxs("p",{className:"ai-agent-chat__typing",children:[e.jsx("span",{className:"ai-agent-chat__typing-dot","aria-hidden":"true"}),e.jsx("span",{className:"ai-agent-chat__typing-dot","aria-hidden":"true"}),e.jsx("span",{className:"ai-agent-chat__typing-dot","aria-hidden":"true"})]})]}):null]}),!ve&&le.length>0?e.jsx("div",{className:"ai-agent-chat__suggestions",children:le.map(s=>e.jsx("button",{type:"button",onClick:()=>void Ne(s),disabled:o,children:s},s))}):null,e.jsxs("form",{className:"ai-agent-chat__composer",onSubmit:_e,children:[e.jsx("input",{value:P,onChange:s=>D(s.target.value),placeholder:pe,disabled:o}),e.jsx("button",{type:o?"button":"submit",onClick:o?ye:void 0,className:`ai-agent-chat__action ${o?"is-stop":"is-send"}`,disabled:!o&&!P.trim().length,"aria-label":o?ee:U,title:o?ee:U,children:o?e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",children:e.jsx("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"})}):e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",children:e.jsx("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"})})})]}),ae?e.jsx("p",{className:"ai-agent-chat__error",children:ae}):null]});return j==="floating"?e.jsxs("div",{className:`ai-agent-chat-shell ai-agent-chat-shell--floating ai-agent-chat-shell--${fe} ${g?"ai-agent-chat-shell--open":"ai-agent-chat-shell--closed"}`.trim(),style:G,children:[e.jsx("div",{className:"ai-agent-chat-shell__panel",children:J}),e.jsxs("button",{type:"button",className:`ai-agent-chat-shell__toggle ai-agent-chat-shell__toggle--floating ${g?"is-open":""}`.trim(),onClick:()=>de(!g),"aria-expanded":g,"aria-label":g?F:I,title:g?F:I,children:[e.jsxs("svg",{className:"ai-agent-chat-shell__toggle-icon ai-agent-chat-shell__toggle-icon--open",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",children:[e.jsx("path",{d:"M12 6V2H8"}),e.jsx("path",{d:"M15 11v2"}),e.jsx("path",{d:"M2 12h2"}),e.jsx("path",{d:"M20 12h2"}),e.jsx("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"}),e.jsx("path",{d:"M9 11v2"})]}),e.jsxs("svg",{className:"ai-agent-chat-shell__toggle-icon ai-agent-chat-shell__toggle-icon--close",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",children:[e.jsx("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"}),e.jsx("path",{d:"m14.5 8.5-5 5"}),e.jsx("path",{d:"m9.5 8.5 5 5"})]})]})]}):j==="dropdown"?e.jsxs("div",{className:`ai-agent-chat-shell ai-agent-chat-shell--dropdown ${g?"ai-agent-chat-shell--open":"ai-agent-chat-shell--closed"}`.trim(),style:G,children:[e.jsxs("button",{type:"button",className:`ai-agent-chat-shell__toggle ai-agent-chat-shell__toggle--dropdown ${g?"is-open":""}`.trim(),onClick:()=>de(!g),"aria-expanded":g,"aria-label":g?F:I,title:g?F:I,children:[e.jsx("span",{className:"ai-agent-chat-shell__toggle-avatar","aria-hidden":"true",children:S||(B?e.jsx("img",{src:B,alt:""}):R?E:"")}),e.jsxs("span",{className:"ai-agent-chat-shell__toggle-copy",children:[e.jsx("strong",{children:b}),e.jsx("span",{children:C})]}),e.jsx("span",{className:"ai-agent-chat-shell__caret","aria-hidden":"true"})]}),e.jsx("div",{className:`ai-agent-chat-shell__panel ${g?"is-open":""}`.trim(),children:J})]}):e.jsx("div",{className:"ai-agent-chat-shell ai-agent-chat-shell--inline",style:G,children:J})}exports.AiAgentChat=Be;exports.useAiAgentChat=ue;
2
+ //# sourceMappingURL=react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.cjs","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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"}