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