@rizal_ncc/agent-client 1.4.2 → 1.4.3
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/README.md +225 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
|
+
[](https://github.com/rizalNCC/agent-client/actions/workflows/npm-publish.yml)
|
|
2
|
+
|
|
1
3
|
# @rizal_ncc/agent-client
|
|
2
4
|
|
|
3
5
|
Frontend UI wrapper + typed helpers for `nems/ai_agent`.
|
|
4
6
|
|
|
5
7
|
`backend-documentation.md` is the source-of-truth contract for backend payload and `tool_results` schema.
|
|
6
8
|
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Install](#install)
|
|
12
|
+
- [Quick Start (React)](#quick-start-react)
|
|
13
|
+
- [Layouts](#layouts)
|
|
14
|
+
- [AiAgentChat Props](#aiagentchat-props)
|
|
15
|
+
- [Built-in Transport Contract](#built-in-transport-contract)
|
|
16
|
+
- [Headless Core Usage](#headless-core-usage)
|
|
17
|
+
- [Tool Result Helpers](#tool-result-helpers)
|
|
18
|
+
- [Theme and Styling](#theme-and-styling)
|
|
19
|
+
- [Architecture](#architecture)
|
|
20
|
+
- [Testing](#testing)
|
|
21
|
+
- [Development](#development)
|
|
22
|
+
- [Release and Publish](#release-and-publish)
|
|
23
|
+
- [File Map](#file-map)
|
|
24
|
+
- [Known Tradeoffs](#known-tradeoffs)
|
|
25
|
+
|
|
7
26
|
## Install
|
|
8
27
|
|
|
9
28
|
```bash
|
|
10
29
|
npm install @rizal_ncc/agent-client
|
|
11
30
|
```
|
|
12
31
|
|
|
13
|
-
## React
|
|
32
|
+
## Quick Start (React)
|
|
14
33
|
|
|
15
34
|
```tsx
|
|
16
35
|
import { AiAgentChat } from "@rizal_ncc/agent-client/react";
|
|
@@ -20,7 +39,7 @@ export function App() {
|
|
|
20
39
|
return (
|
|
21
40
|
<AiAgentChat
|
|
22
41
|
baseURL="https://example.com/api"
|
|
23
|
-
accessToken="your-access-token
|
|
42
|
+
accessToken="your-access-token"
|
|
24
43
|
agent="home-assistant"
|
|
25
44
|
primaryColor="#0f766e"
|
|
26
45
|
primaryForeground="#ffffff"
|
|
@@ -33,60 +52,102 @@ export function App() {
|
|
|
33
52
|
}
|
|
34
53
|
```
|
|
35
54
|
|
|
36
|
-
|
|
55
|
+
## Layouts
|
|
56
|
+
|
|
57
|
+
The component supports three layouts:
|
|
58
|
+
|
|
59
|
+
- `inline`: always open in page flow.
|
|
60
|
+
- `floating`: fixed toggle button + popover panel.
|
|
61
|
+
- `dropdown`: inline toggle bar + expandable panel.
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
37
64
|
|
|
38
65
|
```tsx
|
|
66
|
+
<AiAgentChat layout="inline" />
|
|
39
67
|
<AiAgentChat layout="floating" defaultOpen={false} />
|
|
40
68
|
<AiAgentChat layout="dropdown" defaultOpen={false} panelHeight="560px" />
|
|
41
69
|
```
|
|
42
70
|
|
|
43
|
-
|
|
71
|
+
Open state control:
|
|
72
|
+
|
|
73
|
+
- Controlled: pass `open` + `onOpenChange`.
|
|
74
|
+
- Uncontrolled: pass `defaultOpen`.
|
|
44
75
|
|
|
45
|
-
|
|
76
|
+
## AiAgentChat Props
|
|
46
77
|
|
|
47
|
-
|
|
48
|
-
|
|
78
|
+
### Core
|
|
79
|
+
|
|
80
|
+
- `baseURL?: string` backend base URL (required for built-in transport)
|
|
81
|
+
- `accessToken?: string | () => string | undefined | Promise<string | undefined>` bearer token provider (required for built-in transport)
|
|
49
82
|
- `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
83
|
- `metadata?: { course_id?: number }`
|
|
59
84
|
- `requestHeaders?: HeadersInit`
|
|
60
|
-
- `
|
|
61
|
-
- `
|
|
62
|
-
|
|
85
|
+
- `respondPath?: string` endpoint override
|
|
86
|
+
- `generateResponse?: (request) => Promise<{ content: string }>` custom transport override
|
|
87
|
+
|
|
88
|
+
### UI
|
|
89
|
+
|
|
90
|
+
- `headerTitle?: string`
|
|
91
|
+
- `headerDescription?: string`
|
|
92
|
+
- `suggestedMessages?: string[]`
|
|
93
|
+
- `assistantAvatar?: ReactNode`
|
|
94
|
+
- `assistantAvatarUrl?: string` default `/ai-img.svg`
|
|
95
|
+
- `assistantInitials?: string` default `AI`
|
|
96
|
+
- `userInitials?: string` default `YOU`
|
|
97
|
+
- `initials?: boolean` default `true`
|
|
98
|
+
- `placeholder?: string` default `Ask the assistant...`
|
|
99
|
+
- `sendLabel?: string` default `Send`
|
|
100
|
+
- `stopLabel?: string` default `Stop`
|
|
101
|
+
- `className?: string`
|
|
102
|
+
|
|
103
|
+
### Theme
|
|
104
|
+
|
|
105
|
+
- `primaryColor?: string` default `#1168bb`
|
|
106
|
+
- `primaryForeground?: string` default `#ffffff`
|
|
107
|
+
- `panelHeight?: string` optional CSS height override (uses CSS variable fallback if omitted)
|
|
108
|
+
- `zIndex?: number` default `60`
|
|
109
|
+
|
|
110
|
+
### Layout control
|
|
111
|
+
|
|
112
|
+
- `layout?: "inline" | "floating" | "dropdown"` default `inline`
|
|
113
|
+
- `open?: boolean`
|
|
114
|
+
- `defaultOpen?: boolean`
|
|
63
115
|
- `onOpenChange?: (open: boolean) => void`
|
|
64
|
-
- `
|
|
65
|
-
- `
|
|
66
|
-
- `
|
|
116
|
+
- `floatingPosition?: "bottom-right" | "bottom-left"` default `bottom-right`
|
|
117
|
+
- `openLabel?: string` default `Open chat`
|
|
118
|
+
- `closeLabel?: string` default `Close chat`
|
|
67
119
|
|
|
68
|
-
|
|
120
|
+
### Events
|
|
69
121
|
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
- loading state: stop icon
|
|
122
|
+
- `onMessage?: (message, messages) => void`
|
|
123
|
+
- `onError?: (error, messages) => void`
|
|
73
124
|
|
|
74
|
-
|
|
125
|
+
## Built-in Transport Contract
|
|
75
126
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
127
|
+
If `generateResponse` is not provided, `AiAgentChat` performs backend requests.
|
|
128
|
+
|
|
129
|
+
Path resolution:
|
|
79
130
|
|
|
80
|
-
|
|
131
|
+
- if `baseURL` ends with `/api` -> `POST /v2/ai-agent/respond/`
|
|
132
|
+
- otherwise -> `POST /api/v2/ai-agent/respond/`
|
|
81
133
|
|
|
82
|
-
|
|
83
|
-
- Otherwise -> uses `/api/v2/ai-agent/respond/`
|
|
134
|
+
Request body:
|
|
84
135
|
|
|
85
|
-
|
|
136
|
+
- `agent`
|
|
137
|
+
- `message` (latest user message)
|
|
138
|
+
- `metadata`
|
|
86
139
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
140
|
+
Expected response shape (minimum):
|
|
141
|
+
|
|
142
|
+
- `message: string`
|
|
143
|
+
- `tool_results?: ToolResult[]`
|
|
144
|
+
|
|
145
|
+
Recommendation behavior:
|
|
146
|
+
|
|
147
|
+
- Renders `get_course_recommendation` results as horizontal cards.
|
|
148
|
+
- Uses `next` for pagination when available.
|
|
149
|
+
- `Load more` appends validated incoming items.
|
|
150
|
+
- Duplicate items are currently allowed by design.
|
|
90
151
|
|
|
91
152
|
## Headless Core Usage
|
|
92
153
|
|
|
@@ -101,26 +162,87 @@ await bot.sendMessage("Hi");
|
|
|
101
162
|
console.log(bot.getState().messages);
|
|
102
163
|
```
|
|
103
164
|
|
|
104
|
-
|
|
165
|
+
`ChatbotCore` notes:
|
|
166
|
+
|
|
167
|
+
- Ignores empty messages.
|
|
168
|
+
- Aborts previous in-flight request on new send.
|
|
169
|
+
- Throws if `generateResponse` returns empty `content`.
|
|
170
|
+
- Exposes `stop()` for manual cancellation.
|
|
105
171
|
|
|
106
|
-
|
|
172
|
+
## Tool Result Helpers
|
|
173
|
+
|
|
174
|
+
Helpers exported from core entry:
|
|
107
175
|
|
|
108
176
|
- `getToolResultsByName(response, toolName)`
|
|
177
|
+
- `getToolErrors(response)`
|
|
178
|
+
- `extractCourseDetail(response)`
|
|
109
179
|
- `extractRecommendationOutput(response)`
|
|
110
180
|
- `extractRecommendationItems(response)`
|
|
111
|
-
- `extractCourseDetail(response)`
|
|
112
|
-
- `getToolErrors(response)`
|
|
113
181
|
|
|
114
|
-
|
|
182
|
+
Known backend tool names:
|
|
115
183
|
|
|
116
184
|
- `get_course_recommendation`
|
|
117
185
|
- `get_course_detail`
|
|
118
186
|
|
|
119
|
-
##
|
|
187
|
+
## Theme and Styling
|
|
188
|
+
|
|
189
|
+
Import styles once:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
import "@rizal_ncc/agent-client/style.css";
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Runtime CSS variables used by component shell:
|
|
196
|
+
|
|
197
|
+
- `--chat-primary`
|
|
198
|
+
- `--chat-primary-rgb`
|
|
199
|
+
- `--chat-primary-foreground`
|
|
200
|
+
- `--chat-panel-height`
|
|
201
|
+
- `--chat-shell-z-index`
|
|
120
202
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
-
|
|
203
|
+
Important:
|
|
204
|
+
|
|
205
|
+
- Do not redeclare `--chat-primary*` inside `.ai-agent-chat` if you want prop colors to apply.
|
|
206
|
+
|
|
207
|
+
## Architecture
|
|
208
|
+
|
|
209
|
+
Primary layers:
|
|
210
|
+
|
|
211
|
+
1. `ChatbotCore` state engine (`src/core/chatbot.ts`)
|
|
212
|
+
2. React adapter + transport + layout shell (`src/adapters/react.tsx`)
|
|
213
|
+
3. Tool parsing and pagination helpers (`src/lib/tool-results.ts`, `src/lib/recommendation-pagination.ts`)
|
|
214
|
+
4. UI styles and layout animations (`src/style.css`)
|
|
215
|
+
|
|
216
|
+
Message lifecycle:
|
|
217
|
+
|
|
218
|
+
1. User input -> user message append (`isLoading = true`)
|
|
219
|
+
2. Transport call (custom or built-in)
|
|
220
|
+
3. Assistant message normalize + append
|
|
221
|
+
4. Optional recommendation pagination update
|
|
222
|
+
5. `isLoading = false`
|
|
223
|
+
|
|
224
|
+
## Testing
|
|
225
|
+
|
|
226
|
+
Stack:
|
|
227
|
+
|
|
228
|
+
- Vitest
|
|
229
|
+
- React Testing Library
|
|
230
|
+
- jsdom
|
|
231
|
+
|
|
232
|
+
Current coverage includes:
|
|
233
|
+
|
|
234
|
+
- core behavior/error flow
|
|
235
|
+
- tool helper parsing
|
|
236
|
+
- recommendation merge behavior
|
|
237
|
+
- dropdown/floating open state
|
|
238
|
+
- typing/stop/error UI states
|
|
239
|
+
- load-more append flow
|
|
240
|
+
|
|
241
|
+
Run tests:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
npm test
|
|
245
|
+
```
|
|
124
246
|
|
|
125
247
|
## Development
|
|
126
248
|
|
|
@@ -131,12 +253,68 @@ npm test
|
|
|
131
253
|
npm run build
|
|
132
254
|
```
|
|
133
255
|
|
|
134
|
-
`npm run dev` starts
|
|
256
|
+
`npm run dev` starts Vite playground (`index.html` + `demo/*`).
|
|
135
257
|
|
|
136
|
-
Demo env:
|
|
258
|
+
Demo env (`.env`):
|
|
137
259
|
|
|
138
260
|
```bash
|
|
139
261
|
VITE_API_BASE_URL=http://example.com/
|
|
140
262
|
VITE_AI_AGENT_TOKEN=<access_token>
|
|
141
263
|
VITE_AI_AGENT_AGENT=home-assistant
|
|
142
264
|
```
|
|
265
|
+
|
|
266
|
+
## Release and Publish
|
|
267
|
+
|
|
268
|
+
Pre-release validation:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
npm run release:check
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Manual publish:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
npm publish --access public
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Automated publish (GitHub Actions):
|
|
281
|
+
|
|
282
|
+
- Workflow: `.github/workflows/npm-publish.yml`
|
|
283
|
+
- Trigger: push tag matching `v*.*.*`
|
|
284
|
+
- Required secret: `NPM_TOKEN` (npm automation token)
|
|
285
|
+
|
|
286
|
+
Tag-based release flow:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
npm version patch
|
|
290
|
+
git push --follow-tags
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Use `minor` or `major` instead of `patch` when needed.
|
|
294
|
+
|
|
295
|
+
## File Map
|
|
296
|
+
|
|
297
|
+
- Core
|
|
298
|
+
- `src/core/chatbot.ts`
|
|
299
|
+
- `src/core/types.ts`
|
|
300
|
+
- `src/core/errors.ts`
|
|
301
|
+
- React
|
|
302
|
+
- `src/adapters/react.tsx`
|
|
303
|
+
- `src/react.ts`
|
|
304
|
+
- Helpers
|
|
305
|
+
- `src/lib/tool-results.ts`
|
|
306
|
+
- `src/lib/recommendation-pagination.ts`
|
|
307
|
+
- Styles
|
|
308
|
+
- `src/style.css`
|
|
309
|
+
- Tests
|
|
310
|
+
- `tests/chatbot-core.test.ts`
|
|
311
|
+
- `tests/tool-results.test.ts`
|
|
312
|
+
- `tests/recommendation-pagination.test.ts`
|
|
313
|
+
- `tests/ai-agent-chat-ui.test.tsx`
|
|
314
|
+
|
|
315
|
+
## Known Tradeoffs
|
|
316
|
+
|
|
317
|
+
1. Recommendation dedupe is intentionally disabled.
|
|
318
|
+
2. Built-in transport assumes JSON response (`response.json()`).
|
|
319
|
+
3. Some layout behavior depends on CSS class contracts.
|
|
320
|
+
4. Token refresh strategy is caller-managed when using function token provider.
|