@plucky-ai/react 0.6.0 → 0.7.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/dist/index.cjs CHANGED
@@ -1,38 +1,56 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
-
23
- //#endregion
24
- let __plucky_ai_chat_sdk = require("@plucky-ai/chat-sdk");
25
- __plucky_ai_chat_sdk = __toESM(__plucky_ai_chat_sdk);
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _plucky_ai_chat_sdk = require("@plucky-ai/chat-sdk");
26
3
  let react = require("react");
27
- react = __toESM(react);
28
-
29
4
  //#region src/hooks/useChat.ts
5
+ /**
6
+ * React hook that initializes the Plucky chat widget.
7
+ *
8
+ * Calls {@link Plucky} on mount to inject the widget scripts into the page.
9
+ * The widget is only attached once — subsequent renders with different params
10
+ * will not re-initialize it.
11
+ *
12
+ * Pair with {@link useTools} to register custom tools the AI assistant can invoke.
13
+ *
14
+ * @param params - Widget configuration. Required fields are `appId` and `baseUrl`.
15
+ * See {@link UseChatParams} (alias for `PluckySettingsParams`) for the full
16
+ * list of options including `user`, `mode`, `autoOpen`, and `triggerButton`.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * import { useChat } from '@plucky-ai/react'
21
+ *
22
+ * function App() {
23
+ * useChat({
24
+ * appId: 'your-app-id',
25
+ * baseUrl: 'https://widget.plucky.ai',
26
+ * user: { id: 'user-123', name: 'Jane' },
27
+ * mode: 'push',
28
+ * autoOpen: false,
29
+ * })
30
+ *
31
+ * return <div>My App</div>
32
+ * }
33
+ * ```
34
+ *
35
+ * @example With inline mode
36
+ * ```tsx
37
+ * function ChatPage() {
38
+ * useChat({
39
+ * appId: 'your-app-id',
40
+ * baseUrl: 'https://widget.plucky.ai',
41
+ * mode: 'inline',
42
+ * containerId: 'chat-container',
43
+ * })
44
+ *
45
+ * return <div id="chat-container" style={{ height: '600px' }} />
46
+ * }
47
+ * ```
48
+ */
30
49
  function useChat(params) {
31
50
  (0, react.useEffect)(() => {
32
- (0, __plucky_ai_chat_sdk.Plucky)(params);
51
+ (0, _plucky_ai_chat_sdk.Plucky)(params);
33
52
  }, [params]);
34
53
  }
35
-
36
54
  //#endregion
37
55
  //#region src/hooks/useTools.ts
38
56
  function useLatest(value) {
@@ -42,6 +60,60 @@ function useLatest(value) {
42
60
  }, [value]);
43
61
  return ref;
44
62
  }
63
+ /**
64
+ * React hook that registers custom tools the AI assistant can invoke.
65
+ *
66
+ * Tools are registered on mount (via {@link addTools}) and automatically
67
+ * unregistered on unmount or when the `tools` array reference changes.
68
+ *
69
+ * The `context` parameter is kept up-to-date via a ref, so tool callbacks
70
+ * always receive the latest value even if React state has changed since
71
+ * the tools were registered.
72
+ *
73
+ * @typeParam TContext - Type of the shared context object passed to every
74
+ * tool callback as the second argument.
75
+ *
76
+ * @param params - Tool registration parameters.
77
+ * @param params.tools - Array of tool definitions. Each must have `name`,
78
+ * `description`, and `cb`. Optionally include `inputSchema` (Zod or JSON Schema),
79
+ * `defaultLoadingText`, and `defaultSuccessText`.
80
+ * See {@link UseToolsParams} for the full type definition.
81
+ * @param params.context - Shared context passed as the second argument to every
82
+ * tool callback. Useful for injecting API clients, user state, or other
83
+ * dependencies that may change between renders.
84
+ *
85
+ * @example
86
+ * ```tsx
87
+ * import { useChat, useTools } from '@plucky-ai/react'
88
+ * import { z } from 'zod'
89
+ *
90
+ * function App() {
91
+ * useChat({ appId: 'my-app', baseUrl: 'https://widget.plucky.ai' })
92
+ *
93
+ * const [user] = useState({ id: 'user-123' })
94
+ * const apiClient = useApiClient()
95
+ *
96
+ * useTools({
97
+ * context: { apiClient, user },
98
+ * tools: [
99
+ * {
100
+ * name: 'getOrders',
101
+ * description: 'Fetches recent orders for the current user',
102
+ * inputSchema: z.object({
103
+ * limit: z.number().optional().describe('Max results to return'),
104
+ * }),
105
+ * cb: async ({ limit }, ctx) => {
106
+ * const orders = await ctx.apiClient.getOrders(ctx.user.id, { limit })
107
+ * return JSON.stringify(orders)
108
+ * },
109
+ * },
110
+ * ],
111
+ * })
112
+ *
113
+ * return <div>My App</div>
114
+ * }
115
+ * ```
116
+ */
45
117
  function useTools(params) {
46
118
  const contextRef = useLatest(params.context);
47
119
  const { tools } = params;
@@ -57,14 +129,14 @@ function useTools(params) {
57
129
  }), [tools, contextRef]);
58
130
  (0, react.useEffect)(() => {
59
131
  if (!tools || tools.length === 0) return;
60
- (0, __plucky_ai_chat_sdk.addTools)(wrappedTools);
132
+ (0, _plucky_ai_chat_sdk.addTools)(wrappedTools);
61
133
  return () => {
62
- (0, __plucky_ai_chat_sdk.removeTools)(wrappedTools.map((tool) => tool.name));
134
+ (0, _plucky_ai_chat_sdk.removeTools)(wrappedTools.map((tool) => tool.name));
63
135
  };
64
136
  }, [wrappedTools]);
65
137
  }
66
-
67
138
  //#endregion
68
139
  exports.useChat = useChat;
69
140
  exports.useTools = useTools;
141
+
70
142
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/hooks/useChat.ts","../src/hooks/useTools.ts"],"sourcesContent":["import { UseChatParams } from '@/types'\nimport { Plucky } from '@plucky-ai/chat-sdk'\nimport { useEffect } from 'react'\n\nexport function useChat(params: UseChatParams) {\n useEffect(() => {\n Plucky(params)\n }, [params])\n}\n","import { UseToolsParams } from '@/types'\nimport { addTools, removeTools } from '@plucky-ai/chat-sdk'\nimport { useEffect, useMemo, useRef } from 'react'\nfunction useLatest<T>(value: T) {\n const ref = useRef(value)\n useEffect(() => {\n ref.current = value\n }, [value])\n return ref\n}\n\nexport function useTools<TContext = Record<string, unknown>>(\n params: UseToolsParams<TContext>,\n) {\n const contextRef = useLatest(params.context)\n\n const { tools } = params\n const wrappedTools = useMemo(\n () =>\n tools.map((tool) => {\n const originalCb = tool.cb\n return {\n ...tool,\n cb: async (input: Record<string, unknown>) => {\n if (!contextRef.current) return 'Tool not yet loaded.'\n return originalCb(input, contextRef.current)\n },\n }\n }),\n [tools, contextRef],\n )\n\n useEffect(() => {\n if (!tools || tools.length === 0) return\n addTools(wrappedTools)\n return () => {\n removeTools(wrappedTools.map((tool) => tool.name))\n }\n }, [wrappedTools])\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,SAAgB,QAAQ,QAAuB;AAC7C,4BAAgB;AACd,mCAAO,OAAO;IACb,CAAC,OAAO,CAAC;;;;;ACJd,SAAS,UAAa,OAAU;CAC9B,MAAM,wBAAa,MAAM;AACzB,4BAAgB;AACd,MAAI,UAAU;IACb,CAAC,MAAM,CAAC;AACX,QAAO;;AAGT,SAAgB,SACd,QACA;CACA,MAAM,aAAa,UAAU,OAAO,QAAQ;CAE5C,MAAM,EAAE,UAAU;CAClB,MAAM,wCAEF,MAAM,KAAK,SAAS;EAClB,MAAM,aAAa,KAAK;AACxB,SAAO;GACL,GAAG;GACH,IAAI,OAAO,UAAmC;AAC5C,QAAI,CAAC,WAAW,QAAS,QAAO;AAChC,WAAO,WAAW,OAAO,WAAW,QAAQ;;GAE/C;GACD,EACJ,CAAC,OAAO,WAAW,CACpB;AAED,4BAAgB;AACd,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAClC,qCAAS,aAAa;AACtB,eAAa;AACX,yCAAY,aAAa,KAAK,SAAS,KAAK,KAAK,CAAC;;IAEnD,CAAC,aAAa,CAAC"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/hooks/useChat.ts","../src/hooks/useTools.ts"],"sourcesContent":["import { UseChatParams } from '@/types'\nimport { Plucky } from '@plucky-ai/chat-sdk'\nimport { useEffect } from 'react'\n\n/**\n * React hook that initializes the Plucky chat widget.\n *\n * Calls {@link Plucky} on mount to inject the widget scripts into the page.\n * The widget is only attached once — subsequent renders with different params\n * will not re-initialize it.\n *\n * Pair with {@link useTools} to register custom tools the AI assistant can invoke.\n *\n * @param params - Widget configuration. Required fields are `appId` and `baseUrl`.\n * See {@link UseChatParams} (alias for `PluckySettingsParams`) for the full\n * list of options including `user`, `mode`, `autoOpen`, and `triggerButton`.\n *\n * @example\n * ```tsx\n * import { useChat } from '@plucky-ai/react'\n *\n * function App() {\n * useChat({\n * appId: 'your-app-id',\n * baseUrl: 'https://widget.plucky.ai',\n * user: { id: 'user-123', name: 'Jane' },\n * mode: 'push',\n * autoOpen: false,\n * })\n *\n * return <div>My App</div>\n * }\n * ```\n *\n * @example With inline mode\n * ```tsx\n * function ChatPage() {\n * useChat({\n * appId: 'your-app-id',\n * baseUrl: 'https://widget.plucky.ai',\n * mode: 'inline',\n * containerId: 'chat-container',\n * })\n *\n * return <div id=\"chat-container\" style={{ height: '600px' }} />\n * }\n * ```\n */\nexport function useChat(params: UseChatParams) {\n useEffect(() => {\n Plucky(params)\n }, [params])\n}\n","import { UseToolsParams } from '@/types'\nimport { addTools, removeTools } from '@plucky-ai/chat-sdk'\nimport { useEffect, useMemo, useRef } from 'react'\nfunction useLatest<T>(value: T) {\n const ref = useRef(value)\n useEffect(() => {\n ref.current = value\n }, [value])\n return ref\n}\n\n/**\n * React hook that registers custom tools the AI assistant can invoke.\n *\n * Tools are registered on mount (via {@link addTools}) and automatically\n * unregistered on unmount or when the `tools` array reference changes.\n *\n * The `context` parameter is kept up-to-date via a ref, so tool callbacks\n * always receive the latest value even if React state has changed since\n * the tools were registered.\n *\n * @typeParam TContext - Type of the shared context object passed to every\n * tool callback as the second argument.\n *\n * @param params - Tool registration parameters.\n * @param params.tools - Array of tool definitions. Each must have `name`,\n * `description`, and `cb`. Optionally include `inputSchema` (Zod or JSON Schema),\n * `defaultLoadingText`, and `defaultSuccessText`.\n * See {@link UseToolsParams} for the full type definition.\n * @param params.context - Shared context passed as the second argument to every\n * tool callback. Useful for injecting API clients, user state, or other\n * dependencies that may change between renders.\n *\n * @example\n * ```tsx\n * import { useChat, useTools } from '@plucky-ai/react'\n * import { z } from 'zod'\n *\n * function App() {\n * useChat({ appId: 'my-app', baseUrl: 'https://widget.plucky.ai' })\n *\n * const [user] = useState({ id: 'user-123' })\n * const apiClient = useApiClient()\n *\n * useTools({\n * context: { apiClient, user },\n * tools: [\n * {\n * name: 'getOrders',\n * description: 'Fetches recent orders for the current user',\n * inputSchema: z.object({\n * limit: z.number().optional().describe('Max results to return'),\n * }),\n * cb: async ({ limit }, ctx) => {\n * const orders = await ctx.apiClient.getOrders(ctx.user.id, { limit })\n * return JSON.stringify(orders)\n * },\n * },\n * ],\n * })\n *\n * return <div>My App</div>\n * }\n * ```\n */\nexport function useTools<TContext = Record<string, unknown>>(params: UseToolsParams<TContext>) {\n const contextRef = useLatest(params.context)\n\n const { tools } = params\n const wrappedTools = useMemo(\n () =>\n tools.map((tool) => {\n const originalCb = tool.cb\n return {\n ...tool,\n cb: async (input: Record<string, unknown>) => {\n if (!contextRef.current) return 'Tool not yet loaded.'\n return originalCb(input, contextRef.current)\n },\n }\n }),\n [tools, contextRef],\n )\n\n useEffect(() => {\n if (!tools || tools.length === 0) return\n addTools(wrappedTools)\n return () => {\n removeTools(wrappedTools.map((tool) => tool.name))\n }\n }, [wrappedTools])\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,QAAQ,QAAuB;AAC7C,EAAA,GAAA,MAAA,iBAAgB;AACd,GAAA,GAAA,oBAAA,QAAO,OAAO;IACb,CAAC,OAAO,CAAC;;;;AChDd,SAAS,UAAa,OAAU;CAC9B,MAAM,OAAA,GAAA,MAAA,QAAa,MAAM;AACzB,EAAA,GAAA,MAAA,iBAAgB;AACd,MAAI,UAAU;IACb,CAAC,MAAM,CAAC;AACX,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDT,SAAgB,SAA6C,QAAkC;CAC7F,MAAM,aAAa,UAAU,OAAO,QAAQ;CAE5C,MAAM,EAAE,UAAU;CAClB,MAAM,gBAAA,GAAA,MAAA,eAEF,MAAM,KAAK,SAAS;EAClB,MAAM,aAAa,KAAK;AACxB,SAAO;GACL,GAAG;GACH,IAAI,OAAO,UAAmC;AAC5C,QAAI,CAAC,WAAW,QAAS,QAAO;AAChC,WAAO,WAAW,OAAO,WAAW,QAAQ;;GAE/C;GACD,EACJ,CAAC,OAAO,WAAW,CACpB;AAED,EAAA,GAAA,MAAA,iBAAgB;AACd,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAClC,GAAA,GAAA,oBAAA,UAAS,aAAa;AACtB,eAAa;AACX,IAAA,GAAA,oBAAA,aAAY,aAAa,KAAK,SAAS,KAAK,KAAK,CAAC;;IAEnD,CAAC,aAAa,CAAC"}
package/dist/index.d.cts CHANGED
@@ -1,19 +1,354 @@
1
1
  import { ToolConfig } from "@plucky-ai/chat-sdk";
2
- import { PluckySettingsParams, ToolCallbackResult } from "@plucky-ai/loader-types";
3
2
 
3
+ //#region ../loader-types/dist/index.d.mts
4
+ //#region src/index.d.ts
5
+ /**
6
+ * Configuration options for initializing the Plucky chat widget.
7
+ *
8
+ * Pass this object to {@link Plucky} (chat-sdk) or {@link useChat} (React)
9
+ * to embed the widget on the page.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * Plucky({
14
+ * appId: 'my-app-id',
15
+ * baseUrl: 'https://widget.plucky.ai',
16
+ * user: { id: 'user-123', name: 'Jane Doe', email: 'jane@example.com' },
17
+ * mode: 'push',
18
+ * autoOpen: false,
19
+ * })
20
+ * ```
21
+ */
22
+ type PluckySettingsParams = {
23
+ /**
24
+ * Base URL of the Plucky widget server (e.g., `'https://widget.plucky.ai'`).
25
+ * The loader script and widget iframe are served from this origin.
26
+ */
27
+ baseUrl: string;
28
+ /**
29
+ * Unique identifier for your Plucky app, obtained from the Plucky dashboard.
30
+ */
31
+ appId: string;
32
+ /**
33
+ * Optional user identification and metadata. When provided, the widget
34
+ * associates conversations with this user and displays their name/email
35
+ * in the dashboard.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * user: {
40
+ * id: 'user-123',
41
+ * name: 'Jane Doe',
42
+ * email: 'jane@example.com',
43
+ * createdAt: '2024-01-15T00:00:00Z',
44
+ * metadata: { plan: 'pro', company: 'Acme' },
45
+ * }
46
+ * ```
47
+ */
48
+ user?: {
49
+ /** Unique identifier for the user in your system. */id: string; /** Display name shown in the Plucky dashboard. */
50
+ name?: string; /** Email address shown in the Plucky dashboard. */
51
+ email?: string;
52
+ /**
53
+ * ISO 8601 timestamp of when the user was created in your system.
54
+ * Used for analytics and segmentation in the dashboard.
55
+ */
56
+ createdAt?: string;
57
+ /**
58
+ * Arbitrary key-value metadata attached to the user.
59
+ * Visible in the Plucky dashboard and can be used for filtering.
60
+ */
61
+ metadata?: Record<string, any>;
62
+ };
63
+ /**
64
+ * Built-in system tools to enable for the AI assistant.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * systemTools: { readPage: true }
69
+ * ```
70
+ */
71
+ systemTools?: {
72
+ /**
73
+ * When `true`, enables the `readPage` system tool that allows the AI
74
+ * assistant to read the content of the current page. Defaults to `false`.
75
+ */
76
+ readPage?: boolean;
77
+ };
78
+ /**
79
+ * Display mode for the widget.
80
+ * - `'push'` (default) — fixed sidebar that pushes page content.
81
+ * - `'overlay'` — fixed sidebar that overlays page content.
82
+ * - `'inline'` — widget is mounted inside a container element specified by {@link containerId}.
83
+ */
84
+ mode?: 'push' | 'overlay' | 'inline';
85
+ /**
86
+ * The `id` of the container element to mount the widget into.
87
+ * Required when `mode` is `'inline'`. The element must exist in the DOM
88
+ * before calling init / mounting the widget.
89
+ */
90
+ containerId?: string;
91
+ /**
92
+ * Whether to auto-open the widget when it loads. Defaults to `true`.
93
+ * Set to `false` to start with the widget closed.
94
+ */
95
+ autoOpen?: boolean;
96
+ /**
97
+ * Whether to show a floating trigger button in the bottom-right corner.
98
+ * When clicked, the trigger button toggles the widget open/closed.
99
+ * Defaults to `false`.
100
+ */
101
+ triggerButton?: boolean;
102
+ /**
103
+ * URL patterns the widget should be **visible** on.
104
+ * Uses Chrome-style match patterns (e.g. `'https://*.example.com/app/*'`).
105
+ * When omitted or empty, every page is included by default.
106
+ * If a URL matches both `include` and `exclude`, `exclude` wins.
107
+ */
108
+ include?: string[];
109
+ /**
110
+ * URL patterns the widget should be **hidden** on.
111
+ * Uses Chrome-style match patterns (e.g. `'https://example.com/login'`).
112
+ * Takes priority over `include` — if a URL matches both, it is excluded.
113
+ * The widget stays mounted but is hidden on excluded pages.
114
+ */
115
+ exclude?: string[];
116
+ };
117
+ /**
118
+ * Serializable subset of a tool definition sent across the iframe boundary.
119
+ * This does not include the callback — only metadata used by the widget
120
+ * to display tool information and validate inputs.
121
+ *
122
+ * @see {@link ToolConfig} for the full tool definition including the callback.
123
+ */
124
+ /**
125
+ * Return type for a tool callback. Either a plain string (used as the tool
126
+ * result content) or an object with `content` and an optional `successText`
127
+ * override.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * // Simple string result
132
+ * cb: async ({ city }) => `The weather in ${city} is sunny.`
133
+ *
134
+ * // Object result with custom success text
135
+ * cb: async ({ city }) => ({
136
+ * content: JSON.stringify({ temp: 72, condition: 'sunny' }),
137
+ * successText: `Fetched weather for ${city}`,
138
+ * })
139
+ * ```
140
+ */
141
+ type ToolCallbackResult = string | {
142
+ /** The content returned to the AI assistant as the tool result. */content: string; /** Optional override for the success text displayed in the chat UI after the tool completes. */
143
+ successText?: string;
144
+ };
145
+ /**
146
+ * Full tool definition including the callback function.
147
+ *
148
+ * Register tools with {@link addTools} (chat-sdk) or {@link useTools} (React)
149
+ * to let the AI assistant invoke custom functions on the host page.
150
+ *
151
+ * @typeParam TInputSchema - The type of the input schema (Zod object or plain JSON Schema).
152
+ * When a Zod schema is provided, the callback `input` parameter is automatically
153
+ * inferred from it.
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * import { z } from 'zod'
158
+ *
159
+ * const weatherTool: ToolConfig = {
160
+ * name: 'getWeather',
161
+ * description: 'Fetches current weather for a city',
162
+ * inputSchema: z.object({
163
+ * city: z.string().describe('City name'),
164
+ * }),
165
+ * cb: async ({ city }) => `The weather in ${city} is sunny.`,
166
+ * }
167
+ * ```
168
+ */
169
+ //#endregion
4
170
  //#region src/types.d.ts
171
+ /**
172
+ * Parameters for the {@link useChat} hook.
173
+ *
174
+ * This is an alias for {@link PluckySettingsParams} — see that type for
175
+ * the full list of configuration properties.
176
+ *
177
+ * @example
178
+ * ```tsx
179
+ * useChat({
180
+ * appId: 'your-app-id',
181
+ * baseUrl: 'https://widget.plucky.ai',
182
+ * user: { id: 'user-123', name: 'Jane' },
183
+ * })
184
+ * ```
185
+ */
5
186
  type UseChatParams = PluckySettingsParams;
187
+ /**
188
+ * Parameters for the {@link useTools} hook.
189
+ *
190
+ * @typeParam TContext - Type of the shared context object passed as the second
191
+ * argument to every tool callback. Defaults to `Record<string, unknown>`.
192
+ *
193
+ * @example
194
+ * ```tsx
195
+ * useTools({
196
+ * context: { apiClient, currentUser },
197
+ * tools: [
198
+ * {
199
+ * name: 'getOrders',
200
+ * description: 'Fetches recent orders for the user',
201
+ * cb: async (input, ctx) => {
202
+ * const orders = await ctx.apiClient.getOrders(ctx.currentUser.id)
203
+ * return JSON.stringify(orders)
204
+ * },
205
+ * },
206
+ * ],
207
+ * })
208
+ * ```
209
+ */
6
210
  type UseToolsParams<TContext = Record<string, unknown>> = {
211
+ /**
212
+ * Shared context object passed as the second argument to every tool callback.
213
+ * Use this to give tools access to React state, API clients, or other
214
+ * dependencies without closing over stale values.
215
+ *
216
+ * The context ref is kept up-to-date on every render, so callbacks always
217
+ * receive the latest value.
218
+ */
7
219
  context?: TContext;
220
+ /**
221
+ * Array of tool definitions to register with the Plucky widget.
222
+ *
223
+ * Each tool extends {@link ToolConfig} but replaces the `cb` callback
224
+ * signature to include the `context` as a second parameter.
225
+ *
226
+ * Tools are automatically registered on mount and unregistered on unmount
227
+ * or when the `tools` array reference changes.
228
+ *
229
+ * | Property | Type | Description |
230
+ * |---|---|---|
231
+ * | `name` | `string` | **(required)** Unique tool name. |
232
+ * | `description` | `string` | **(required)** Tells the AI when to use this tool. |
233
+ * | `inputSchema` | `ZodObject \| Record<string, unknown>` | Schema describing expected input. |
234
+ * | `cb` | `(input, context) => ToolCallbackResult` | Callback invoked by the AI. Receives `context` as second arg. |
235
+ * | `defaultLoadingText` | `string \| null` | Text shown while the tool runs. |
236
+ * | `defaultSuccessText` | `string \| null` | Text shown on completion. |
237
+ */
8
238
  tools: Array<Omit<ToolConfig, 'cb'> & {
239
+ /**
240
+ * Callback executed when the AI assistant invokes this tool.
241
+ *
242
+ * @param input - The input arguments from the AI assistant.
243
+ * @param context - The current value of {@link UseToolsParams.context}.
244
+ * @returns The tool result — either a plain string or `{ content, successText? }`.
245
+ */
9
246
  cb: (input: Record<string, unknown>, context: TContext) => Promise<ToolCallbackResult> | ToolCallbackResult;
10
247
  }>;
11
248
  };
12
249
  //#endregion
13
250
  //#region src/hooks/useChat.d.ts
251
+ /**
252
+ * React hook that initializes the Plucky chat widget.
253
+ *
254
+ * Calls {@link Plucky} on mount to inject the widget scripts into the page.
255
+ * The widget is only attached once — subsequent renders with different params
256
+ * will not re-initialize it.
257
+ *
258
+ * Pair with {@link useTools} to register custom tools the AI assistant can invoke.
259
+ *
260
+ * @param params - Widget configuration. Required fields are `appId` and `baseUrl`.
261
+ * See {@link UseChatParams} (alias for `PluckySettingsParams`) for the full
262
+ * list of options including `user`, `mode`, `autoOpen`, and `triggerButton`.
263
+ *
264
+ * @example
265
+ * ```tsx
266
+ * import { useChat } from '@plucky-ai/react'
267
+ *
268
+ * function App() {
269
+ * useChat({
270
+ * appId: 'your-app-id',
271
+ * baseUrl: 'https://widget.plucky.ai',
272
+ * user: { id: 'user-123', name: 'Jane' },
273
+ * mode: 'push',
274
+ * autoOpen: false,
275
+ * })
276
+ *
277
+ * return <div>My App</div>
278
+ * }
279
+ * ```
280
+ *
281
+ * @example With inline mode
282
+ * ```tsx
283
+ * function ChatPage() {
284
+ * useChat({
285
+ * appId: 'your-app-id',
286
+ * baseUrl: 'https://widget.plucky.ai',
287
+ * mode: 'inline',
288
+ * containerId: 'chat-container',
289
+ * })
290
+ *
291
+ * return <div id="chat-container" style={{ height: '600px' }} />
292
+ * }
293
+ * ```
294
+ */
14
295
  declare function useChat(params: UseChatParams): void;
15
296
  //#endregion
16
297
  //#region src/hooks/useTools.d.ts
298
+ /**
299
+ * React hook that registers custom tools the AI assistant can invoke.
300
+ *
301
+ * Tools are registered on mount (via {@link addTools}) and automatically
302
+ * unregistered on unmount or when the `tools` array reference changes.
303
+ *
304
+ * The `context` parameter is kept up-to-date via a ref, so tool callbacks
305
+ * always receive the latest value even if React state has changed since
306
+ * the tools were registered.
307
+ *
308
+ * @typeParam TContext - Type of the shared context object passed to every
309
+ * tool callback as the second argument.
310
+ *
311
+ * @param params - Tool registration parameters.
312
+ * @param params.tools - Array of tool definitions. Each must have `name`,
313
+ * `description`, and `cb`. Optionally include `inputSchema` (Zod or JSON Schema),
314
+ * `defaultLoadingText`, and `defaultSuccessText`.
315
+ * See {@link UseToolsParams} for the full type definition.
316
+ * @param params.context - Shared context passed as the second argument to every
317
+ * tool callback. Useful for injecting API clients, user state, or other
318
+ * dependencies that may change between renders.
319
+ *
320
+ * @example
321
+ * ```tsx
322
+ * import { useChat, useTools } from '@plucky-ai/react'
323
+ * import { z } from 'zod'
324
+ *
325
+ * function App() {
326
+ * useChat({ appId: 'my-app', baseUrl: 'https://widget.plucky.ai' })
327
+ *
328
+ * const [user] = useState({ id: 'user-123' })
329
+ * const apiClient = useApiClient()
330
+ *
331
+ * useTools({
332
+ * context: { apiClient, user },
333
+ * tools: [
334
+ * {
335
+ * name: 'getOrders',
336
+ * description: 'Fetches recent orders for the current user',
337
+ * inputSchema: z.object({
338
+ * limit: z.number().optional().describe('Max results to return'),
339
+ * }),
340
+ * cb: async ({ limit }, ctx) => {
341
+ * const orders = await ctx.apiClient.getOrders(ctx.user.id, { limit })
342
+ * return JSON.stringify(orders)
343
+ * },
344
+ * },
345
+ * ],
346
+ * })
347
+ *
348
+ * return <div>My App</div>
349
+ * }
350
+ * ```
351
+ */
17
352
  declare function useTools<TContext = Record<string, unknown>>(params: UseToolsParams<TContext>): void;
18
353
  //#endregion
19
354
  export { UseChatParams, UseToolsParams, useChat, useTools };
@@ -0,0 +1,355 @@
1
+ import { ToolConfig } from "@plucky-ai/chat-sdk";
2
+
3
+ //#region ../loader-types/dist/index.d.mts
4
+ //#region src/index.d.ts
5
+ /**
6
+ * Configuration options for initializing the Plucky chat widget.
7
+ *
8
+ * Pass this object to {@link Plucky} (chat-sdk) or {@link useChat} (React)
9
+ * to embed the widget on the page.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * Plucky({
14
+ * appId: 'my-app-id',
15
+ * baseUrl: 'https://widget.plucky.ai',
16
+ * user: { id: 'user-123', name: 'Jane Doe', email: 'jane@example.com' },
17
+ * mode: 'push',
18
+ * autoOpen: false,
19
+ * })
20
+ * ```
21
+ */
22
+ type PluckySettingsParams = {
23
+ /**
24
+ * Base URL of the Plucky widget server (e.g., `'https://widget.plucky.ai'`).
25
+ * The loader script and widget iframe are served from this origin.
26
+ */
27
+ baseUrl: string;
28
+ /**
29
+ * Unique identifier for your Plucky app, obtained from the Plucky dashboard.
30
+ */
31
+ appId: string;
32
+ /**
33
+ * Optional user identification and metadata. When provided, the widget
34
+ * associates conversations with this user and displays their name/email
35
+ * in the dashboard.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * user: {
40
+ * id: 'user-123',
41
+ * name: 'Jane Doe',
42
+ * email: 'jane@example.com',
43
+ * createdAt: '2024-01-15T00:00:00Z',
44
+ * metadata: { plan: 'pro', company: 'Acme' },
45
+ * }
46
+ * ```
47
+ */
48
+ user?: {
49
+ /** Unique identifier for the user in your system. */id: string; /** Display name shown in the Plucky dashboard. */
50
+ name?: string; /** Email address shown in the Plucky dashboard. */
51
+ email?: string;
52
+ /**
53
+ * ISO 8601 timestamp of when the user was created in your system.
54
+ * Used for analytics and segmentation in the dashboard.
55
+ */
56
+ createdAt?: string;
57
+ /**
58
+ * Arbitrary key-value metadata attached to the user.
59
+ * Visible in the Plucky dashboard and can be used for filtering.
60
+ */
61
+ metadata?: Record<string, any>;
62
+ };
63
+ /**
64
+ * Built-in system tools to enable for the AI assistant.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * systemTools: { readPage: true }
69
+ * ```
70
+ */
71
+ systemTools?: {
72
+ /**
73
+ * When `true`, enables the `readPage` system tool that allows the AI
74
+ * assistant to read the content of the current page. Defaults to `false`.
75
+ */
76
+ readPage?: boolean;
77
+ };
78
+ /**
79
+ * Display mode for the widget.
80
+ * - `'push'` (default) — fixed sidebar that pushes page content.
81
+ * - `'overlay'` — fixed sidebar that overlays page content.
82
+ * - `'inline'` — widget is mounted inside a container element specified by {@link containerId}.
83
+ */
84
+ mode?: 'push' | 'overlay' | 'inline';
85
+ /**
86
+ * The `id` of the container element to mount the widget into.
87
+ * Required when `mode` is `'inline'`. The element must exist in the DOM
88
+ * before calling init / mounting the widget.
89
+ */
90
+ containerId?: string;
91
+ /**
92
+ * Whether to auto-open the widget when it loads. Defaults to `true`.
93
+ * Set to `false` to start with the widget closed.
94
+ */
95
+ autoOpen?: boolean;
96
+ /**
97
+ * Whether to show a floating trigger button in the bottom-right corner.
98
+ * When clicked, the trigger button toggles the widget open/closed.
99
+ * Defaults to `false`.
100
+ */
101
+ triggerButton?: boolean;
102
+ /**
103
+ * URL patterns the widget should be **visible** on.
104
+ * Uses Chrome-style match patterns (e.g. `'https://*.example.com/app/*'`).
105
+ * When omitted or empty, every page is included by default.
106
+ * If a URL matches both `include` and `exclude`, `exclude` wins.
107
+ */
108
+ include?: string[];
109
+ /**
110
+ * URL patterns the widget should be **hidden** on.
111
+ * Uses Chrome-style match patterns (e.g. `'https://example.com/login'`).
112
+ * Takes priority over `include` — if a URL matches both, it is excluded.
113
+ * The widget stays mounted but is hidden on excluded pages.
114
+ */
115
+ exclude?: string[];
116
+ };
117
+ /**
118
+ * Serializable subset of a tool definition sent across the iframe boundary.
119
+ * This does not include the callback — only metadata used by the widget
120
+ * to display tool information and validate inputs.
121
+ *
122
+ * @see {@link ToolConfig} for the full tool definition including the callback.
123
+ */
124
+ /**
125
+ * Return type for a tool callback. Either a plain string (used as the tool
126
+ * result content) or an object with `content` and an optional `successText`
127
+ * override.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * // Simple string result
132
+ * cb: async ({ city }) => `The weather in ${city} is sunny.`
133
+ *
134
+ * // Object result with custom success text
135
+ * cb: async ({ city }) => ({
136
+ * content: JSON.stringify({ temp: 72, condition: 'sunny' }),
137
+ * successText: `Fetched weather for ${city}`,
138
+ * })
139
+ * ```
140
+ */
141
+ type ToolCallbackResult = string | {
142
+ /** The content returned to the AI assistant as the tool result. */content: string; /** Optional override for the success text displayed in the chat UI after the tool completes. */
143
+ successText?: string;
144
+ };
145
+ /**
146
+ * Full tool definition including the callback function.
147
+ *
148
+ * Register tools with {@link addTools} (chat-sdk) or {@link useTools} (React)
149
+ * to let the AI assistant invoke custom functions on the host page.
150
+ *
151
+ * @typeParam TInputSchema - The type of the input schema (Zod object or plain JSON Schema).
152
+ * When a Zod schema is provided, the callback `input` parameter is automatically
153
+ * inferred from it.
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * import { z } from 'zod'
158
+ *
159
+ * const weatherTool: ToolConfig = {
160
+ * name: 'getWeather',
161
+ * description: 'Fetches current weather for a city',
162
+ * inputSchema: z.object({
163
+ * city: z.string().describe('City name'),
164
+ * }),
165
+ * cb: async ({ city }) => `The weather in ${city} is sunny.`,
166
+ * }
167
+ * ```
168
+ */
169
+ //#endregion
170
+ //#region src/types.d.ts
171
+ /**
172
+ * Parameters for the {@link useChat} hook.
173
+ *
174
+ * This is an alias for {@link PluckySettingsParams} — see that type for
175
+ * the full list of configuration properties.
176
+ *
177
+ * @example
178
+ * ```tsx
179
+ * useChat({
180
+ * appId: 'your-app-id',
181
+ * baseUrl: 'https://widget.plucky.ai',
182
+ * user: { id: 'user-123', name: 'Jane' },
183
+ * })
184
+ * ```
185
+ */
186
+ type UseChatParams = PluckySettingsParams;
187
+ /**
188
+ * Parameters for the {@link useTools} hook.
189
+ *
190
+ * @typeParam TContext - Type of the shared context object passed as the second
191
+ * argument to every tool callback. Defaults to `Record<string, unknown>`.
192
+ *
193
+ * @example
194
+ * ```tsx
195
+ * useTools({
196
+ * context: { apiClient, currentUser },
197
+ * tools: [
198
+ * {
199
+ * name: 'getOrders',
200
+ * description: 'Fetches recent orders for the user',
201
+ * cb: async (input, ctx) => {
202
+ * const orders = await ctx.apiClient.getOrders(ctx.currentUser.id)
203
+ * return JSON.stringify(orders)
204
+ * },
205
+ * },
206
+ * ],
207
+ * })
208
+ * ```
209
+ */
210
+ type UseToolsParams<TContext = Record<string, unknown>> = {
211
+ /**
212
+ * Shared context object passed as the second argument to every tool callback.
213
+ * Use this to give tools access to React state, API clients, or other
214
+ * dependencies without closing over stale values.
215
+ *
216
+ * The context ref is kept up-to-date on every render, so callbacks always
217
+ * receive the latest value.
218
+ */
219
+ context?: TContext;
220
+ /**
221
+ * Array of tool definitions to register with the Plucky widget.
222
+ *
223
+ * Each tool extends {@link ToolConfig} but replaces the `cb` callback
224
+ * signature to include the `context` as a second parameter.
225
+ *
226
+ * Tools are automatically registered on mount and unregistered on unmount
227
+ * or when the `tools` array reference changes.
228
+ *
229
+ * | Property | Type | Description |
230
+ * |---|---|---|
231
+ * | `name` | `string` | **(required)** Unique tool name. |
232
+ * | `description` | `string` | **(required)** Tells the AI when to use this tool. |
233
+ * | `inputSchema` | `ZodObject \| Record<string, unknown>` | Schema describing expected input. |
234
+ * | `cb` | `(input, context) => ToolCallbackResult` | Callback invoked by the AI. Receives `context` as second arg. |
235
+ * | `defaultLoadingText` | `string \| null` | Text shown while the tool runs. |
236
+ * | `defaultSuccessText` | `string \| null` | Text shown on completion. |
237
+ */
238
+ tools: Array<Omit<ToolConfig, 'cb'> & {
239
+ /**
240
+ * Callback executed when the AI assistant invokes this tool.
241
+ *
242
+ * @param input - The input arguments from the AI assistant.
243
+ * @param context - The current value of {@link UseToolsParams.context}.
244
+ * @returns The tool result — either a plain string or `{ content, successText? }`.
245
+ */
246
+ cb: (input: Record<string, unknown>, context: TContext) => Promise<ToolCallbackResult> | ToolCallbackResult;
247
+ }>;
248
+ };
249
+ //#endregion
250
+ //#region src/hooks/useChat.d.ts
251
+ /**
252
+ * React hook that initializes the Plucky chat widget.
253
+ *
254
+ * Calls {@link Plucky} on mount to inject the widget scripts into the page.
255
+ * The widget is only attached once — subsequent renders with different params
256
+ * will not re-initialize it.
257
+ *
258
+ * Pair with {@link useTools} to register custom tools the AI assistant can invoke.
259
+ *
260
+ * @param params - Widget configuration. Required fields are `appId` and `baseUrl`.
261
+ * See {@link UseChatParams} (alias for `PluckySettingsParams`) for the full
262
+ * list of options including `user`, `mode`, `autoOpen`, and `triggerButton`.
263
+ *
264
+ * @example
265
+ * ```tsx
266
+ * import { useChat } from '@plucky-ai/react'
267
+ *
268
+ * function App() {
269
+ * useChat({
270
+ * appId: 'your-app-id',
271
+ * baseUrl: 'https://widget.plucky.ai',
272
+ * user: { id: 'user-123', name: 'Jane' },
273
+ * mode: 'push',
274
+ * autoOpen: false,
275
+ * })
276
+ *
277
+ * return <div>My App</div>
278
+ * }
279
+ * ```
280
+ *
281
+ * @example With inline mode
282
+ * ```tsx
283
+ * function ChatPage() {
284
+ * useChat({
285
+ * appId: 'your-app-id',
286
+ * baseUrl: 'https://widget.plucky.ai',
287
+ * mode: 'inline',
288
+ * containerId: 'chat-container',
289
+ * })
290
+ *
291
+ * return <div id="chat-container" style={{ height: '600px' }} />
292
+ * }
293
+ * ```
294
+ */
295
+ declare function useChat(params: UseChatParams): void;
296
+ //#endregion
297
+ //#region src/hooks/useTools.d.ts
298
+ /**
299
+ * React hook that registers custom tools the AI assistant can invoke.
300
+ *
301
+ * Tools are registered on mount (via {@link addTools}) and automatically
302
+ * unregistered on unmount or when the `tools` array reference changes.
303
+ *
304
+ * The `context` parameter is kept up-to-date via a ref, so tool callbacks
305
+ * always receive the latest value even if React state has changed since
306
+ * the tools were registered.
307
+ *
308
+ * @typeParam TContext - Type of the shared context object passed to every
309
+ * tool callback as the second argument.
310
+ *
311
+ * @param params - Tool registration parameters.
312
+ * @param params.tools - Array of tool definitions. Each must have `name`,
313
+ * `description`, and `cb`. Optionally include `inputSchema` (Zod or JSON Schema),
314
+ * `defaultLoadingText`, and `defaultSuccessText`.
315
+ * See {@link UseToolsParams} for the full type definition.
316
+ * @param params.context - Shared context passed as the second argument to every
317
+ * tool callback. Useful for injecting API clients, user state, or other
318
+ * dependencies that may change between renders.
319
+ *
320
+ * @example
321
+ * ```tsx
322
+ * import { useChat, useTools } from '@plucky-ai/react'
323
+ * import { z } from 'zod'
324
+ *
325
+ * function App() {
326
+ * useChat({ appId: 'my-app', baseUrl: 'https://widget.plucky.ai' })
327
+ *
328
+ * const [user] = useState({ id: 'user-123' })
329
+ * const apiClient = useApiClient()
330
+ *
331
+ * useTools({
332
+ * context: { apiClient, user },
333
+ * tools: [
334
+ * {
335
+ * name: 'getOrders',
336
+ * description: 'Fetches recent orders for the current user',
337
+ * inputSchema: z.object({
338
+ * limit: z.number().optional().describe('Max results to return'),
339
+ * }),
340
+ * cb: async ({ limit }, ctx) => {
341
+ * const orders = await ctx.apiClient.getOrders(ctx.user.id, { limit })
342
+ * return JSON.stringify(orders)
343
+ * },
344
+ * },
345
+ * ],
346
+ * })
347
+ *
348
+ * return <div>My App</div>
349
+ * }
350
+ * ```
351
+ */
352
+ declare function useTools<TContext = Record<string, unknown>>(params: UseToolsParams<TContext>): void;
353
+ //#endregion
354
+ export { UseChatParams, UseToolsParams, useChat, useTools };
355
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,140 @@
1
+ import { Plucky, addTools, removeTools } from "@plucky-ai/chat-sdk";
2
+ import { useEffect, useMemo, useRef } from "react";
3
+ //#region src/hooks/useChat.ts
4
+ /**
5
+ * React hook that initializes the Plucky chat widget.
6
+ *
7
+ * Calls {@link Plucky} on mount to inject the widget scripts into the page.
8
+ * The widget is only attached once — subsequent renders with different params
9
+ * will not re-initialize it.
10
+ *
11
+ * Pair with {@link useTools} to register custom tools the AI assistant can invoke.
12
+ *
13
+ * @param params - Widget configuration. Required fields are `appId` and `baseUrl`.
14
+ * See {@link UseChatParams} (alias for `PluckySettingsParams`) for the full
15
+ * list of options including `user`, `mode`, `autoOpen`, and `triggerButton`.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * import { useChat } from '@plucky-ai/react'
20
+ *
21
+ * function App() {
22
+ * useChat({
23
+ * appId: 'your-app-id',
24
+ * baseUrl: 'https://widget.plucky.ai',
25
+ * user: { id: 'user-123', name: 'Jane' },
26
+ * mode: 'push',
27
+ * autoOpen: false,
28
+ * })
29
+ *
30
+ * return <div>My App</div>
31
+ * }
32
+ * ```
33
+ *
34
+ * @example With inline mode
35
+ * ```tsx
36
+ * function ChatPage() {
37
+ * useChat({
38
+ * appId: 'your-app-id',
39
+ * baseUrl: 'https://widget.plucky.ai',
40
+ * mode: 'inline',
41
+ * containerId: 'chat-container',
42
+ * })
43
+ *
44
+ * return <div id="chat-container" style={{ height: '600px' }} />
45
+ * }
46
+ * ```
47
+ */
48
+ function useChat(params) {
49
+ useEffect(() => {
50
+ Plucky(params);
51
+ }, [params]);
52
+ }
53
+ //#endregion
54
+ //#region src/hooks/useTools.ts
55
+ function useLatest(value) {
56
+ const ref = useRef(value);
57
+ useEffect(() => {
58
+ ref.current = value;
59
+ }, [value]);
60
+ return ref;
61
+ }
62
+ /**
63
+ * React hook that registers custom tools the AI assistant can invoke.
64
+ *
65
+ * Tools are registered on mount (via {@link addTools}) and automatically
66
+ * unregistered on unmount or when the `tools` array reference changes.
67
+ *
68
+ * The `context` parameter is kept up-to-date via a ref, so tool callbacks
69
+ * always receive the latest value even if React state has changed since
70
+ * the tools were registered.
71
+ *
72
+ * @typeParam TContext - Type of the shared context object passed to every
73
+ * tool callback as the second argument.
74
+ *
75
+ * @param params - Tool registration parameters.
76
+ * @param params.tools - Array of tool definitions. Each must have `name`,
77
+ * `description`, and `cb`. Optionally include `inputSchema` (Zod or JSON Schema),
78
+ * `defaultLoadingText`, and `defaultSuccessText`.
79
+ * See {@link UseToolsParams} for the full type definition.
80
+ * @param params.context - Shared context passed as the second argument to every
81
+ * tool callback. Useful for injecting API clients, user state, or other
82
+ * dependencies that may change between renders.
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * import { useChat, useTools } from '@plucky-ai/react'
87
+ * import { z } from 'zod'
88
+ *
89
+ * function App() {
90
+ * useChat({ appId: 'my-app', baseUrl: 'https://widget.plucky.ai' })
91
+ *
92
+ * const [user] = useState({ id: 'user-123' })
93
+ * const apiClient = useApiClient()
94
+ *
95
+ * useTools({
96
+ * context: { apiClient, user },
97
+ * tools: [
98
+ * {
99
+ * name: 'getOrders',
100
+ * description: 'Fetches recent orders for the current user',
101
+ * inputSchema: z.object({
102
+ * limit: z.number().optional().describe('Max results to return'),
103
+ * }),
104
+ * cb: async ({ limit }, ctx) => {
105
+ * const orders = await ctx.apiClient.getOrders(ctx.user.id, { limit })
106
+ * return JSON.stringify(orders)
107
+ * },
108
+ * },
109
+ * ],
110
+ * })
111
+ *
112
+ * return <div>My App</div>
113
+ * }
114
+ * ```
115
+ */
116
+ function useTools(params) {
117
+ const contextRef = useLatest(params.context);
118
+ const { tools } = params;
119
+ const wrappedTools = useMemo(() => tools.map((tool) => {
120
+ const originalCb = tool.cb;
121
+ return {
122
+ ...tool,
123
+ cb: async (input) => {
124
+ if (!contextRef.current) return "Tool not yet loaded.";
125
+ return originalCb(input, contextRef.current);
126
+ }
127
+ };
128
+ }), [tools, contextRef]);
129
+ useEffect(() => {
130
+ if (!tools || tools.length === 0) return;
131
+ addTools(wrappedTools);
132
+ return () => {
133
+ removeTools(wrappedTools.map((tool) => tool.name));
134
+ };
135
+ }, [wrappedTools]);
136
+ }
137
+ //#endregion
138
+ export { useChat, useTools };
139
+
140
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/hooks/useChat.ts","../src/hooks/useTools.ts"],"sourcesContent":["import { UseChatParams } from '@/types'\nimport { Plucky } from '@plucky-ai/chat-sdk'\nimport { useEffect } from 'react'\n\n/**\n * React hook that initializes the Plucky chat widget.\n *\n * Calls {@link Plucky} on mount to inject the widget scripts into the page.\n * The widget is only attached once — subsequent renders with different params\n * will not re-initialize it.\n *\n * Pair with {@link useTools} to register custom tools the AI assistant can invoke.\n *\n * @param params - Widget configuration. Required fields are `appId` and `baseUrl`.\n * See {@link UseChatParams} (alias for `PluckySettingsParams`) for the full\n * list of options including `user`, `mode`, `autoOpen`, and `triggerButton`.\n *\n * @example\n * ```tsx\n * import { useChat } from '@plucky-ai/react'\n *\n * function App() {\n * useChat({\n * appId: 'your-app-id',\n * baseUrl: 'https://widget.plucky.ai',\n * user: { id: 'user-123', name: 'Jane' },\n * mode: 'push',\n * autoOpen: false,\n * })\n *\n * return <div>My App</div>\n * }\n * ```\n *\n * @example With inline mode\n * ```tsx\n * function ChatPage() {\n * useChat({\n * appId: 'your-app-id',\n * baseUrl: 'https://widget.plucky.ai',\n * mode: 'inline',\n * containerId: 'chat-container',\n * })\n *\n * return <div id=\"chat-container\" style={{ height: '600px' }} />\n * }\n * ```\n */\nexport function useChat(params: UseChatParams) {\n useEffect(() => {\n Plucky(params)\n }, [params])\n}\n","import { UseToolsParams } from '@/types'\nimport { addTools, removeTools } from '@plucky-ai/chat-sdk'\nimport { useEffect, useMemo, useRef } from 'react'\nfunction useLatest<T>(value: T) {\n const ref = useRef(value)\n useEffect(() => {\n ref.current = value\n }, [value])\n return ref\n}\n\n/**\n * React hook that registers custom tools the AI assistant can invoke.\n *\n * Tools are registered on mount (via {@link addTools}) and automatically\n * unregistered on unmount or when the `tools` array reference changes.\n *\n * The `context` parameter is kept up-to-date via a ref, so tool callbacks\n * always receive the latest value even if React state has changed since\n * the tools were registered.\n *\n * @typeParam TContext - Type of the shared context object passed to every\n * tool callback as the second argument.\n *\n * @param params - Tool registration parameters.\n * @param params.tools - Array of tool definitions. Each must have `name`,\n * `description`, and `cb`. Optionally include `inputSchema` (Zod or JSON Schema),\n * `defaultLoadingText`, and `defaultSuccessText`.\n * See {@link UseToolsParams} for the full type definition.\n * @param params.context - Shared context passed as the second argument to every\n * tool callback. Useful for injecting API clients, user state, or other\n * dependencies that may change between renders.\n *\n * @example\n * ```tsx\n * import { useChat, useTools } from '@plucky-ai/react'\n * import { z } from 'zod'\n *\n * function App() {\n * useChat({ appId: 'my-app', baseUrl: 'https://widget.plucky.ai' })\n *\n * const [user] = useState({ id: 'user-123' })\n * const apiClient = useApiClient()\n *\n * useTools({\n * context: { apiClient, user },\n * tools: [\n * {\n * name: 'getOrders',\n * description: 'Fetches recent orders for the current user',\n * inputSchema: z.object({\n * limit: z.number().optional().describe('Max results to return'),\n * }),\n * cb: async ({ limit }, ctx) => {\n * const orders = await ctx.apiClient.getOrders(ctx.user.id, { limit })\n * return JSON.stringify(orders)\n * },\n * },\n * ],\n * })\n *\n * return <div>My App</div>\n * }\n * ```\n */\nexport function useTools<TContext = Record<string, unknown>>(params: UseToolsParams<TContext>) {\n const contextRef = useLatest(params.context)\n\n const { tools } = params\n const wrappedTools = useMemo(\n () =>\n tools.map((tool) => {\n const originalCb = tool.cb\n return {\n ...tool,\n cb: async (input: Record<string, unknown>) => {\n if (!contextRef.current) return 'Tool not yet loaded.'\n return originalCb(input, contextRef.current)\n },\n }\n }),\n [tools, contextRef],\n )\n\n useEffect(() => {\n if (!tools || tools.length === 0) return\n addTools(wrappedTools)\n return () => {\n removeTools(wrappedTools.map((tool) => tool.name))\n }\n }, [wrappedTools])\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,QAAQ,QAAuB;AAC7C,iBAAgB;AACd,SAAO,OAAO;IACb,CAAC,OAAO,CAAC;;;;AChDd,SAAS,UAAa,OAAU;CAC9B,MAAM,MAAM,OAAO,MAAM;AACzB,iBAAgB;AACd,MAAI,UAAU;IACb,CAAC,MAAM,CAAC;AACX,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDT,SAAgB,SAA6C,QAAkC;CAC7F,MAAM,aAAa,UAAU,OAAO,QAAQ;CAE5C,MAAM,EAAE,UAAU;CAClB,MAAM,eAAe,cAEjB,MAAM,KAAK,SAAS;EAClB,MAAM,aAAa,KAAK;AACxB,SAAO;GACL,GAAG;GACH,IAAI,OAAO,UAAmC;AAC5C,QAAI,CAAC,WAAW,QAAS,QAAO;AAChC,WAAO,WAAW,OAAO,WAAW,QAAQ;;GAE/C;GACD,EACJ,CAAC,OAAO,WAAW,CACpB;AAED,iBAAgB;AACd,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAClC,WAAS,aAAa;AACtB,eAAa;AACX,eAAY,aAAa,KAAK,SAAS,KAAK,KAAK,CAAC;;IAEnD,CAAC,aAAa,CAAC"}
package/dist/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@plucky-ai/react",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "main": "./index.cjs",
6
6
  "module": "./index.js",
7
7
  "types": "./index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
10
+ "types": "./dist/index.d.mts",
11
+ "import": "./dist/index.mjs",
12
12
  "require": "./dist/index.cjs"
13
13
  }
14
14
  },
package/package.json CHANGED
@@ -1,33 +1,33 @@
1
1
  {
2
2
  "name": "@plucky-ai/react",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
- "module": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.mts",
8
8
  "exports": {
9
9
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
10
+ "types": "./dist/index.d.mts",
11
+ "import": "./dist/index.mjs",
12
12
  "require": "./dist/index.cjs"
13
13
  }
14
14
  },
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org/"
18
+ },
15
19
  "dependencies": {
16
20
  "react": "^19.2.3",
17
21
  "zod": "^4.1.11",
18
- "@plucky-ai/chat-sdk": "^0.6.0"
22
+ "@plucky-ai/chat-sdk": "^0.7.0"
19
23
  },
20
24
  "devDependencies": {
21
25
  "@types/react": "19.1.13",
22
- "tsdown": "^0.15.12",
26
+ "tsdown": "^0.21.1",
23
27
  "tsx": "^4.21.0",
24
28
  "typescript": "^5.9.3",
25
29
  "@plucky-ai/loader-types": "^0.4.0"
26
30
  },
27
- "publishConfig": {
28
- "access": "public",
29
- "registry": "https://registry.npmjs.org/"
30
- },
31
31
  "scripts": {
32
32
  "build:watch": "pnpm exec tsdown --watch ./src",
33
33
  "build": "pnpm exec tsdown --config tsdown.config.ts"
package/dist/index.d.ts DELETED
@@ -1,20 +0,0 @@
1
- import { ToolConfig } from "@plucky-ai/chat-sdk";
2
- import { PluckySettingsParams, ToolCallbackResult } from "@plucky-ai/loader-types";
3
-
4
- //#region src/types.d.ts
5
- type UseChatParams = PluckySettingsParams;
6
- type UseToolsParams<TContext = Record<string, unknown>> = {
7
- context?: TContext;
8
- tools: Array<Omit<ToolConfig, 'cb'> & {
9
- cb: (input: Record<string, unknown>, context: TContext) => Promise<ToolCallbackResult> | ToolCallbackResult;
10
- }>;
11
- };
12
- //#endregion
13
- //#region src/hooks/useChat.d.ts
14
- declare function useChat(params: UseChatParams): void;
15
- //#endregion
16
- //#region src/hooks/useTools.d.ts
17
- declare function useTools<TContext = Record<string, unknown>>(params: UseToolsParams<TContext>): void;
18
- //#endregion
19
- export { UseChatParams, UseToolsParams, useChat, useTools };
20
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js DELETED
@@ -1,44 +0,0 @@
1
- import { Plucky, addTools, removeTools } from "@plucky-ai/chat-sdk";
2
- import { useEffect, useMemo, useRef } from "react";
3
-
4
- //#region src/hooks/useChat.ts
5
- function useChat(params) {
6
- useEffect(() => {
7
- Plucky(params);
8
- }, [params]);
9
- }
10
-
11
- //#endregion
12
- //#region src/hooks/useTools.ts
13
- function useLatest(value) {
14
- const ref = useRef(value);
15
- useEffect(() => {
16
- ref.current = value;
17
- }, [value]);
18
- return ref;
19
- }
20
- function useTools(params) {
21
- const contextRef = useLatest(params.context);
22
- const { tools } = params;
23
- const wrappedTools = useMemo(() => tools.map((tool) => {
24
- const originalCb = tool.cb;
25
- return {
26
- ...tool,
27
- cb: async (input) => {
28
- if (!contextRef.current) return "Tool not yet loaded.";
29
- return originalCb(input, contextRef.current);
30
- }
31
- };
32
- }), [tools, contextRef]);
33
- useEffect(() => {
34
- if (!tools || tools.length === 0) return;
35
- addTools(wrappedTools);
36
- return () => {
37
- removeTools(wrappedTools.map((tool) => tool.name));
38
- };
39
- }, [wrappedTools]);
40
- }
41
-
42
- //#endregion
43
- export { useChat, useTools };
44
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/hooks/useChat.ts","../src/hooks/useTools.ts"],"sourcesContent":["import { UseChatParams } from '@/types'\nimport { Plucky } from '@plucky-ai/chat-sdk'\nimport { useEffect } from 'react'\n\nexport function useChat(params: UseChatParams) {\n useEffect(() => {\n Plucky(params)\n }, [params])\n}\n","import { UseToolsParams } from '@/types'\nimport { addTools, removeTools } from '@plucky-ai/chat-sdk'\nimport { useEffect, useMemo, useRef } from 'react'\nfunction useLatest<T>(value: T) {\n const ref = useRef(value)\n useEffect(() => {\n ref.current = value\n }, [value])\n return ref\n}\n\nexport function useTools<TContext = Record<string, unknown>>(\n params: UseToolsParams<TContext>,\n) {\n const contextRef = useLatest(params.context)\n\n const { tools } = params\n const wrappedTools = useMemo(\n () =>\n tools.map((tool) => {\n const originalCb = tool.cb\n return {\n ...tool,\n cb: async (input: Record<string, unknown>) => {\n if (!contextRef.current) return 'Tool not yet loaded.'\n return originalCb(input, contextRef.current)\n },\n }\n }),\n [tools, contextRef],\n )\n\n useEffect(() => {\n if (!tools || tools.length === 0) return\n addTools(wrappedTools)\n return () => {\n removeTools(wrappedTools.map((tool) => tool.name))\n }\n }, [wrappedTools])\n}\n"],"mappings":";;;;AAIA,SAAgB,QAAQ,QAAuB;AAC7C,iBAAgB;AACd,SAAO,OAAO;IACb,CAAC,OAAO,CAAC;;;;;ACJd,SAAS,UAAa,OAAU;CAC9B,MAAM,MAAM,OAAO,MAAM;AACzB,iBAAgB;AACd,MAAI,UAAU;IACb,CAAC,MAAM,CAAC;AACX,QAAO;;AAGT,SAAgB,SACd,QACA;CACA,MAAM,aAAa,UAAU,OAAO,QAAQ;CAE5C,MAAM,EAAE,UAAU;CAClB,MAAM,eAAe,cAEjB,MAAM,KAAK,SAAS;EAClB,MAAM,aAAa,KAAK;AACxB,SAAO;GACL,GAAG;GACH,IAAI,OAAO,UAAmC;AAC5C,QAAI,CAAC,WAAW,QAAS,QAAO;AAChC,WAAO,WAAW,OAAO,WAAW,QAAQ;;GAE/C;GACD,EACJ,CAAC,OAAO,WAAW,CACpB;AAED,iBAAgB;AACd,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAClC,WAAS,aAAa;AACtB,eAAa;AACX,eAAY,aAAa,KAAK,SAAS,KAAK,KAAK,CAAC;;IAEnD,CAAC,aAAa,CAAC"}