chatablex-web-sdk 1.0.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/README.md +199 -0
- package/README.zh-CN.md +199 -0
- package/dist/index.d.mts +280 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.js +366 -0
- package/dist/index.mjs +337 -0
- package/package.json +50 -0
- package/src/bridge.ts +162 -0
- package/src/index.ts +115 -0
- package/src/modules/ai.ts +18 -0
- package/src/modules/events.ts +23 -0
- package/src/modules/skills.ts +14 -0
- package/src/modules/storage.ts +18 -0
- package/src/modules/tool.ts +54 -0
- package/src/modules/tools.ts +18 -0
- package/src/modules/ui.ts +26 -0
- package/src/types.ts +270 -0
package/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# chatablex-web-sdk
|
|
2
|
+
|
|
3
|
+
English | [**简体中文**](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
Runtime SDK for building **ChatableX AI App** WebUI applications.
|
|
6
|
+
|
|
7
|
+
Unlike a type-only package, this SDK contains the actual bridge runtime that connects your web app to the ChatableX Flutter host. You must install it as a dependency — the platform does **not** inject it for you.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install chatablex-web-sdk
|
|
13
|
+
# or link locally during development:
|
|
14
|
+
npm install ../chatablex-web-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { ChatableX } from 'chatablex-web-sdk';
|
|
21
|
+
|
|
22
|
+
// Initialize — connects to the Flutter WebView host
|
|
23
|
+
const sdk = await ChatableX.init({ appId: 'my-app', debug: true });
|
|
24
|
+
|
|
25
|
+
// Register a tool handler (called when the LLM invokes your tool)
|
|
26
|
+
sdk.tool.onExecute(async (params) => {
|
|
27
|
+
const { action, value } = params;
|
|
28
|
+
// ... perform action, update UI ...
|
|
29
|
+
return { success: true, result: 42 };
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What are the SDK namespaces for?
|
|
34
|
+
|
|
35
|
+
The object returned by `ChatableX.init()` is a **set of APIs grouped by responsibility**. Your WebUI runs inside a WebView; many capabilities (native dialogs, file picking, storage aligned with the main chat, AI calls through the host’s stack) are awkward or inconsistent if you only use browser APIs. These modules call into the **Flutter host via the JS bridge**.
|
|
36
|
+
|
|
37
|
+
**You do not need every module** for every app — the smallest integration is usually `sdk.tool` (handle LLM invocations). Add others when you need them.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
| Namespace | Role (why it exists) |
|
|
41
|
+
|-----------|----------------------|
|
|
42
|
+
| **`sdk.tool`** | Register tool execution: when the LLM invokes your tool, the host forwards params into your WebUI and you return a result. This is the **core** hook for an AI App. |
|
|
43
|
+
| **`sdk.events`** | Subscribe to host-side events (e.g. user messages, streaming) so the WebUI stays in sync with the session. |
|
|
44
|
+
| **`sdk.ai`** | Send messages or read session context through the **same host AI pipeline** (`chat`, `getContext`, etc.) instead of wiring your own model only inside the page. |
|
|
45
|
+
| **`sdk.ui`** | Drive **native host UI**: toasts, confirms, file picker, refresh main chrome — same UX and permissions as the desktop client. |
|
|
46
|
+
| **`sdk.storage`** | Key–value storage on the **host** for persistence and sharing with the rest of the app, not only `localStorage` in the WebView. |
|
|
47
|
+
| **`sdk.tools` / `sdk.skills`** | List or invoke other tools and skills on the platform for orchestration. |
|
|
48
|
+
|
|
49
|
+
The **API** sections below each include: a **typical scenario** (when to use it) + **example code** (how to wire it up).
|
|
50
|
+
|
|
51
|
+
## API
|
|
52
|
+
|
|
53
|
+
### `ChatableX.init(config)`
|
|
54
|
+
|
|
55
|
+
| Option | Type | Default | Description |
|
|
56
|
+
|-----------|---------|---------|-------------|
|
|
57
|
+
| `appId` | string | — | **Required.** Must match your `manifest.json` `id`. |
|
|
58
|
+
| `debug` | boolean | false | Print debug logs to console. |
|
|
59
|
+
| `timeout` | number | 10000 | Handshake timeout in ms. |
|
|
60
|
+
|
|
61
|
+
Returns `Promise<ChatableXSDK>`.
|
|
62
|
+
|
|
63
|
+
### `sdk.tool`
|
|
64
|
+
|
|
65
|
+
**When to use**: The user opens your AI App from chat, or the model invokes your tool; the host forwards JSON params into the WebView and you return a result back into the session.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
sdk.tool.onExecute(async (params) => {
|
|
69
|
+
const { action, rowId } = params as { action?: string; rowId?: string };
|
|
70
|
+
if (action === 'delete') {
|
|
71
|
+
await deleteRow(rowId);
|
|
72
|
+
return { success: true, message: 'Deleted' };
|
|
73
|
+
}
|
|
74
|
+
return { success: false, error: 'unknown action' };
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Metadata from manifest (filled in by the host after handshake)
|
|
78
|
+
const info = sdk.tool.getInfo();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `sdk.events`
|
|
82
|
+
|
|
83
|
+
**When to use**: Your side panel should stay in sync with the main window—new user messages, streaming assistant output, or other tool executions should update your UI.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const unsubUser = sdk.events.onUserMessage(({ message }) => {
|
|
87
|
+
appendActivityFeed(`User: ${message}`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const unsubStream = sdk.events.on('streamingContent', ({ content, finished }) => {
|
|
91
|
+
setPartialReply(content);
|
|
92
|
+
if (finished) setLoading(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const unsubAi = sdk.events.onAiResponse((data) => {
|
|
96
|
+
setLastReply(data.content);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Unsubscribe on unmount to avoid leaks
|
|
100
|
+
// unsubUser(); unsubStream(); unsubAi();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
You can also subscribe to `toolExecution`, `close`, etc. (depends on host support).
|
|
104
|
+
|
|
105
|
+
### `sdk.ai`
|
|
106
|
+
|
|
107
|
+
**When to use**: A button in your panel like “ask about this session again” should use the **host’s** model and context, not a separate API key inside the page; or you need session metadata for a summary view.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const reply = await sdk.ai.chat('Summarize the last user message in three bullets', {
|
|
111
|
+
stream: false,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const ctx = await sdk.ai.getContext();
|
|
115
|
+
if (ctx.name) setSessionTitle(ctx.name); // some fields depend on host implementation
|
|
116
|
+
|
|
117
|
+
// Streaming may be pushed by the host; call chatStream when supported
|
|
118
|
+
await sdk.ai.chatStream('Write a short reply', { stream: true });
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `sdk.ui`
|
|
122
|
+
|
|
123
|
+
**When to use**: Destructive actions need a **native confirm**; long jobs end with a **host toast**; picking files should use the **host file picker**; after work you may **refresh the main transcript** or close the WebUI.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
await sdk.ui.showNotification('Export finished', 'success');
|
|
127
|
+
|
|
128
|
+
const ok = await sdk.ui.showConfirm('Delete record', 'This cannot be undone. Continue?');
|
|
129
|
+
if (!ok) return;
|
|
130
|
+
|
|
131
|
+
const path = await sdk.ui.pickFile({ type: 'image' });
|
|
132
|
+
if (path) await uploadPreview(path);
|
|
133
|
+
|
|
134
|
+
await sdk.ui.updateState({ refreshMessages: true });
|
|
135
|
+
// await sdk.ui.openTab({ title: 'Details', type: 'custom', data: { id: 'x' } });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `sdk.storage`
|
|
139
|
+
|
|
140
|
+
**When to use**: Persist filters, layout, or drafts for your panel on the **host** so it behaves like the rest of the desktop app—not only `localStorage` inside the WebView.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const KEY = 'my-app:filters';
|
|
144
|
+
|
|
145
|
+
await sdk.storage.set(KEY, { projectId: 'p1', sort: 'date' });
|
|
146
|
+
const filters = await sdk.storage.get<{ projectId: string; sort: string }>(KEY);
|
|
147
|
+
await sdk.storage.delete(KEY);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `sdk.tools` / `sdk.skills`
|
|
151
|
+
|
|
152
|
+
**When to use**: A one-click flow in your panel chains **other installed tools** in order; or you show a form so the user fills variables and runs a **skill** (a skill may orchestrate several tools). Use `executeWithConfirm` for risky steps so the host shows a confirm dialog first.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const tools = await sdk.tools.list();
|
|
156
|
+
setToolPicker(tools.filter((t) => t.id !== sdk.tool.getInfo().id));
|
|
157
|
+
|
|
158
|
+
const step1 = await sdk.tools.execute('fetch-doc', { url });
|
|
159
|
+
if (!step1.success) throw new Error(step1.error);
|
|
160
|
+
const step2 = await sdk.tools.execute('summarize', { text: step1.data });
|
|
161
|
+
|
|
162
|
+
// High-risk actions: confirm in the host first
|
|
163
|
+
await sdk.tools.executeWithConfirm('delete-backup', { id: backupId });
|
|
164
|
+
|
|
165
|
+
const skills = await sdk.skills.list();
|
|
166
|
+
const skillResult = await sdk.skills.execute('weekly-report-skill', {
|
|
167
|
+
week: '2026-W13',
|
|
168
|
+
department: 'sales',
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Architecture
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
Your App (React/Vue/Vanilla)
|
|
176
|
+
│ import { ChatableX } from 'chatablex-web-sdk'
|
|
177
|
+
│
|
|
178
|
+
▼
|
|
179
|
+
┌─────────────────────────────────────┐
|
|
180
|
+
│ chatablex-web-sdk (this package) │
|
|
181
|
+
│ │
|
|
182
|
+
│ Bridge layer: │
|
|
183
|
+
│ JS → Flutter: ChatableXBridge │
|
|
184
|
+
│ Flutter → JS: ChatableXReceive │
|
|
185
|
+
│ │
|
|
186
|
+
│ Modules: tool, events, ai, ui, │
|
|
187
|
+
│ storage, tools, skills │
|
|
188
|
+
└──────────────┬──────────────────────┘
|
|
189
|
+
│ WebView Bridge
|
|
190
|
+
▼
|
|
191
|
+
┌─────────────────────────────────────┐
|
|
192
|
+
│ ChatableX Flutter Client │
|
|
193
|
+
│ (owns chat UI, SSE stream, agent) │
|
|
194
|
+
└─────────────────────────────────────┘
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# chatablex-web-sdk
|
|
2
|
+
|
|
3
|
+
**[English](README.md)** | 简体中文
|
|
4
|
+
|
|
5
|
+
用于构建 **ChatableX AI App** WebUI 应用的运行时 SDK。
|
|
6
|
+
|
|
7
|
+
与仅提供类型的包不同,本 SDK 包含将 Web 应用连接到 ChatableX Flutter 宿主的真实桥接运行时。你必须将其作为依赖安装.
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install chatablex-web-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 快速开始
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { ChatableX } from 'chatablex-web-sdk';
|
|
19
|
+
|
|
20
|
+
// 初始化 —— 连接 Flutter WebView 宿主
|
|
21
|
+
const sdk = await ChatableX.init({ appId: 'my-app', debug: true });
|
|
22
|
+
|
|
23
|
+
// 注册工具处理器(当 LLM 调用你的工具时触发)
|
|
24
|
+
sdk.tool.onExecute(async (params) => {
|
|
25
|
+
const { action, value } = params;
|
|
26
|
+
// ... 执行操作、更新 UI ...
|
|
27
|
+
return { success: true, result: 42 };
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## SDK 模块是做什么的?
|
|
32
|
+
|
|
33
|
+
`ChatableX.init()` 返回的 `sdk` 是一个**按职责划分的 API 集合**。WebUI 跑在 WebView 里,很多能力(系统对话框、文件选择、与主聊天同步的存储、走宿主模型的对话等)在浏览器里要么不好做、要么和 Flutter 主应用割裂。这些模块都通过 **JS ↔ Flutter 桥** 调用宿主已实现的能力。
|
|
34
|
+
|
|
35
|
+
**你不一定要用到每一个模块**:最小集成往往只需要 `sdk.tool`(响应 LLM 调用);其余按需选用。
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
| 命名空间 | 用途(为什么要单独拆出来) |
|
|
39
|
+
|----------|---------------------------|
|
|
40
|
+
| **`sdk.tool`** | 注册工具执行逻辑:LLM 调用你的工具时由宿主把参数传进来,你在 WebUI 里算完再返回结果。这是 AI App 的**核心**入口。 |
|
|
41
|
+
| **`sdk.events`** | 订阅宿主侧事件(如用户消息、流式内容),让 WebUI 与当前会话状态对齐。 |
|
|
42
|
+
| **`sdk.ai`** | 在 WebUI 内向**宿主同一条 AI 管线**发消息或拉取会话上下文(`chat` / `getContext` 等),避免你在页面里自己再接一套模型。 |
|
|
43
|
+
| **`sdk.ui`** | 用**宿主原生 UI** 做提示、确认框、选文件、通知主界面刷新等,体验和权限与桌面客户端一致。 |
|
|
44
|
+
| **`sdk.storage`** | 键值存储走**宿主侧**,便于与 App 其它部分共享状态、持久化,而不只存在页面的 `localStorage` 里。 |
|
|
45
|
+
| **`sdk.tools` / `sdk.skills`** | 列举或调用平台上其它工具、技能,做编排或联动。 |
|
|
46
|
+
|
|
47
|
+
下面「API」各节包含:**典型场景**(什么时候用)+ **示例代码**(怎么接)。
|
|
48
|
+
|
|
49
|
+
## API
|
|
50
|
+
|
|
51
|
+
### `ChatableX.init(config)`
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
| 选项 | 类型 | 默认值 | 说明 |
|
|
55
|
+
| --------- | ------- | ----- | ------------------------------------- |
|
|
56
|
+
| `appId` | string | — | **必填。**须与 `manifest.json` 中的 `id` 一致。 |
|
|
57
|
+
| `debug` | boolean | false | 是否在控制台打印调试日志。 |
|
|
58
|
+
| `timeout` | number | 10000 | 握手超时时间(毫秒)。 |
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
返回 `Promise<ChatableXSDK>`。
|
|
62
|
+
|
|
63
|
+
### `sdk.tool`
|
|
64
|
+
|
|
65
|
+
**典型场景**:用户在聊天里触发你的 AI App,或模型根据上下文调用你的工具;宿主把 JSON 参数推进 WebView,你要执行逻辑并把结果返回给会话。
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
sdk.tool.onExecute(async (params) => {
|
|
69
|
+
const { action, rowId } = params as { action?: string; rowId?: string };
|
|
70
|
+
if (action === 'delete') {
|
|
71
|
+
await deleteRow(rowId);
|
|
72
|
+
return { success: true, message: '已删除' };
|
|
73
|
+
}
|
|
74
|
+
return { success: false, error: 'unknown action' };
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 展示 manifest 里的名称、版本等(握手后由宿主填充)
|
|
78
|
+
const info = sdk.tool.getInfo();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `sdk.events`
|
|
82
|
+
|
|
83
|
+
**典型场景**:侧边 WebUI 要做「实时仪表盘」——主窗口里用户发了新消息、AI 流式输出、或其它工具执行完成时,你的面板要同步高亮或刷新。
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const unsubUser = sdk.events.onUserMessage(({ message }) => {
|
|
87
|
+
appendActivityFeed(`用户:${message}`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const unsubStream = sdk.events.on('streamingContent', ({ content, finished }) => {
|
|
91
|
+
setPartialReply(content);
|
|
92
|
+
if (finished) setLoading(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const unsubAi = sdk.events.onAiResponse((data) => {
|
|
96
|
+
setLastReply(data.content);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// 组件卸载时取消订阅,避免泄漏
|
|
100
|
+
// unsubUser(); unsubStream(); unsubAi();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
事件名还可选:`toolExecution`、`close` 等(与宿主实现一致)。
|
|
104
|
+
|
|
105
|
+
### `sdk.ai`
|
|
106
|
+
|
|
107
|
+
**典型场景**:在工具面板里提供「针对当前会话再问一句」按钮——走宿主已配置的模型与上下文,而不是在页面里单独接第三方 API;或拉取会话上下文做摘要展示。
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const reply = await sdk.ai.chat('把上一条用户消息总结成三点', {
|
|
111
|
+
stream: false,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const ctx = await sdk.ai.getContext();
|
|
115
|
+
if (ctx.name) setSessionTitle(ctx.name); // 部分字段视宿主实现而定
|
|
116
|
+
|
|
117
|
+
// 流式由宿主推送;也可按需调用 chatStream(视宿主支持而定)
|
|
118
|
+
await sdk.ai.chatStream('写一段简短回复', { stream: true });
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `sdk.ui`
|
|
122
|
+
|
|
123
|
+
**典型场景**:危险操作要用**系统级确认框**;完成长任务后用**原生通知**;需要访问用户文件时用**宿主文件选择器**;操作结束后让主窗口**刷新消息列表或关闭 WebUI**。
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
await sdk.ui.showNotification('导出完成', 'success');
|
|
127
|
+
|
|
128
|
+
const ok = await sdk.ui.showConfirm('删除记录', '此操作不可撤销,是否继续?');
|
|
129
|
+
if (!ok) return;
|
|
130
|
+
|
|
131
|
+
const path = await sdk.ui.pickFile({ type: 'image' });
|
|
132
|
+
if (path) await uploadPreview(path);
|
|
133
|
+
|
|
134
|
+
await sdk.ui.updateState({ refreshMessages: true });
|
|
135
|
+
// await sdk.ui.openTab({ title: '详情', type: 'custom', data: { id: 'x' } });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `sdk.storage`
|
|
139
|
+
|
|
140
|
+
**典型场景**:记住用户在面板里的筛选条件、布局或草稿;数据存在**宿主侧**,可和 App 其它部分一致、也比仅 `localStorage` 更符合桌面端预期。
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const KEY = 'my-app:filters';
|
|
144
|
+
|
|
145
|
+
await sdk.storage.set(KEY, { projectId: 'p1', sort: 'date' });
|
|
146
|
+
const filters = await sdk.storage.get<{ projectId: string; sort: string }>(KEY);
|
|
147
|
+
await sdk.storage.delete(KEY);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `sdk.tools` / `sdk.skills`
|
|
151
|
+
|
|
152
|
+
**典型场景**:面板上的「一键流程」——按固定顺序调用**其它已安装工具**;或展示表单让用户填变量后执行**技能**(技能内部可编排多个工具)。敏感步骤可用 `executeWithConfirm` 让宿主先弹确认。
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const tools = await sdk.tools.list();
|
|
156
|
+
setToolPicker(tools.filter((t) => t.id !== sdk.tool.getInfo().id));
|
|
157
|
+
|
|
158
|
+
const step1 = await sdk.tools.execute('fetch-doc', { url });
|
|
159
|
+
if (!step1.success) throw new Error(step1.error);
|
|
160
|
+
const step2 = await sdk.tools.execute('summarize', { text: step1.data });
|
|
161
|
+
|
|
162
|
+
// 删除类等高风险:走宿主确认
|
|
163
|
+
await sdk.tools.executeWithConfirm('delete-backup', { id: backupId });
|
|
164
|
+
|
|
165
|
+
const skills = await sdk.skills.list();
|
|
166
|
+
const skillResult = await sdk.skills.execute('weekly-report-skill', {
|
|
167
|
+
week: '2026-W13',
|
|
168
|
+
department: 'sales',
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## 架构
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
Your App (React/Vue/Vanilla)
|
|
176
|
+
│ import { ChatableX } from 'chatablex-web-sdk'
|
|
177
|
+
│
|
|
178
|
+
▼
|
|
179
|
+
┌─────────────────────────────────────┐
|
|
180
|
+
│ chatablex-web-sdk(本包) │
|
|
181
|
+
│ │
|
|
182
|
+
│ 桥接层: │
|
|
183
|
+
│ JS → Flutter: ChatableXBridge │
|
|
184
|
+
│ Flutter → JS: ChatableXReceive │
|
|
185
|
+
│ │
|
|
186
|
+
│ 模块:tool, events, ai, ui, │
|
|
187
|
+
│ storage, tools, skills │
|
|
188
|
+
└──────────────┬──────────────────────┘
|
|
189
|
+
│ WebView Bridge
|
|
190
|
+
▼
|
|
191
|
+
┌─────────────────────────────────────┐
|
|
192
|
+
│ ChatableX Flutter 客户端 │
|
|
193
|
+
│ (承载聊天 UI、SSE 流、Agent) │
|
|
194
|
+
└─────────────────────────────────────┘
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## 许可证
|
|
198
|
+
|
|
199
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatableX Web SDK — Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
interface ChatOptions {
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
context?: Record<string, unknown>;
|
|
7
|
+
tools?: string[];
|
|
8
|
+
skills?: string[];
|
|
9
|
+
stream?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface ChatResponse {
|
|
12
|
+
content: string;
|
|
13
|
+
sessionId: string;
|
|
14
|
+
messageId: string;
|
|
15
|
+
toolResults?: ToolResult[];
|
|
16
|
+
finished: boolean;
|
|
17
|
+
model?: string;
|
|
18
|
+
usage?: {
|
|
19
|
+
promptTokens: number;
|
|
20
|
+
completionTokens: number;
|
|
21
|
+
totalTokens: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface SessionContext {
|
|
25
|
+
sessionId: string;
|
|
26
|
+
name: string;
|
|
27
|
+
messages: Message[];
|
|
28
|
+
activeTools: string[];
|
|
29
|
+
activeSkills: string[];
|
|
30
|
+
createdAt: string;
|
|
31
|
+
updatedAt: string;
|
|
32
|
+
}
|
|
33
|
+
interface Message {
|
|
34
|
+
id: string;
|
|
35
|
+
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
36
|
+
content: string;
|
|
37
|
+
timestamp: string;
|
|
38
|
+
toolCalls?: ToolCall[];
|
|
39
|
+
}
|
|
40
|
+
interface ToolInfo {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
version: string;
|
|
44
|
+
description: string;
|
|
45
|
+
}
|
|
46
|
+
interface ToolParameter {
|
|
47
|
+
name: string;
|
|
48
|
+
type: string;
|
|
49
|
+
description: string;
|
|
50
|
+
required: boolean;
|
|
51
|
+
default?: unknown;
|
|
52
|
+
enum?: string[];
|
|
53
|
+
}
|
|
54
|
+
interface ToolCall {
|
|
55
|
+
id: string;
|
|
56
|
+
toolId: string;
|
|
57
|
+
name: string;
|
|
58
|
+
params: Record<string, unknown>;
|
|
59
|
+
status: 'pending' | 'running' | 'success' | 'error' | 'cancelled';
|
|
60
|
+
}
|
|
61
|
+
interface ToolResult {
|
|
62
|
+
success: boolean;
|
|
63
|
+
data?: unknown;
|
|
64
|
+
error?: string;
|
|
65
|
+
toolId: string;
|
|
66
|
+
duration?: number;
|
|
67
|
+
}
|
|
68
|
+
type ToolExecuteHandler = (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
69
|
+
interface Skill {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
version: string;
|
|
74
|
+
author?: string;
|
|
75
|
+
category?: string;
|
|
76
|
+
toolIds: string[];
|
|
77
|
+
variables: SkillVariable[];
|
|
78
|
+
installed: boolean;
|
|
79
|
+
}
|
|
80
|
+
interface SkillVariable {
|
|
81
|
+
name: string;
|
|
82
|
+
type: string;
|
|
83
|
+
description: string;
|
|
84
|
+
required: boolean;
|
|
85
|
+
default?: unknown;
|
|
86
|
+
}
|
|
87
|
+
interface SkillResult {
|
|
88
|
+
success: boolean;
|
|
89
|
+
data?: unknown;
|
|
90
|
+
error?: string;
|
|
91
|
+
skillId: string;
|
|
92
|
+
toolResults?: ToolResult[];
|
|
93
|
+
}
|
|
94
|
+
type NotificationType = 'info' | 'success' | 'warning' | 'error';
|
|
95
|
+
interface FilePickerOptions {
|
|
96
|
+
type?: 'any' | 'image' | 'video' | 'audio' | 'custom';
|
|
97
|
+
multiple?: boolean;
|
|
98
|
+
allowedExtensions?: string[];
|
|
99
|
+
}
|
|
100
|
+
interface TabConfig {
|
|
101
|
+
id: string;
|
|
102
|
+
title: string;
|
|
103
|
+
icon?: string;
|
|
104
|
+
type: 'chat' | 'tool' | 'skill' | 'custom';
|
|
105
|
+
data?: Record<string, unknown>;
|
|
106
|
+
}
|
|
107
|
+
interface StateUpdate {
|
|
108
|
+
refreshMessages?: boolean;
|
|
109
|
+
closeWebUI?: boolean;
|
|
110
|
+
[key: string]: unknown;
|
|
111
|
+
}
|
|
112
|
+
type EventType = 'aiResponse' | 'toolExecution' | 'userMessage' | 'streamingContent' | 'close';
|
|
113
|
+
interface AiResponseEventData extends ChatResponse {
|
|
114
|
+
}
|
|
115
|
+
interface ToolExecutionEventData {
|
|
116
|
+
toolCall: ToolCall;
|
|
117
|
+
result?: ToolResult;
|
|
118
|
+
}
|
|
119
|
+
interface UserMessageEventData {
|
|
120
|
+
message: string;
|
|
121
|
+
timestamp: string;
|
|
122
|
+
}
|
|
123
|
+
interface StreamingContentEventData {
|
|
124
|
+
content: string;
|
|
125
|
+
finished?: boolean;
|
|
126
|
+
}
|
|
127
|
+
interface CloseEventData {
|
|
128
|
+
toolId: string;
|
|
129
|
+
}
|
|
130
|
+
interface EventCallbackMap {
|
|
131
|
+
aiResponse: (data: AiResponseEventData) => void;
|
|
132
|
+
toolExecution: (data: ToolExecutionEventData) => void;
|
|
133
|
+
userMessage: (data: UserMessageEventData) => void;
|
|
134
|
+
streamingContent: (data: StreamingContentEventData) => void;
|
|
135
|
+
close: (data: CloseEventData) => void;
|
|
136
|
+
}
|
|
137
|
+
type Unsubscribe = () => void;
|
|
138
|
+
interface ChatableXInitConfig {
|
|
139
|
+
/** Your app / tool id (must match manifest.json id) */
|
|
140
|
+
appId: string;
|
|
141
|
+
/** SDK version override (default: SDK built-in version) */
|
|
142
|
+
version?: string;
|
|
143
|
+
/** Enable debug logging (default: false) */
|
|
144
|
+
debug?: boolean;
|
|
145
|
+
/** Timeout in ms for the handshake with Flutter (default: 10000) */
|
|
146
|
+
timeout?: number;
|
|
147
|
+
}
|
|
148
|
+
interface ChatableXAI {
|
|
149
|
+
chat(message: string, options?: ChatOptions): Promise<ChatResponse>;
|
|
150
|
+
chatStream(message: string, options?: ChatOptions): Promise<unknown>;
|
|
151
|
+
getContext(): Promise<SessionContext>;
|
|
152
|
+
}
|
|
153
|
+
interface ChatableXTools {
|
|
154
|
+
list(): Promise<ToolInfo[]>;
|
|
155
|
+
execute(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
156
|
+
executeWithConfirm(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
|
|
157
|
+
}
|
|
158
|
+
interface ChatableXSkills {
|
|
159
|
+
list(): Promise<Skill[]>;
|
|
160
|
+
execute(skillId: string, variables: Record<string, unknown>): Promise<SkillResult>;
|
|
161
|
+
}
|
|
162
|
+
interface ChatableXUI {
|
|
163
|
+
showNotification(message: string, type?: NotificationType): Promise<void>;
|
|
164
|
+
showConfirm(title: string, message: string): Promise<boolean>;
|
|
165
|
+
pickFile(options?: FilePickerOptions): Promise<string | null>;
|
|
166
|
+
openTab(config: TabConfig): Promise<void>;
|
|
167
|
+
updateState(state: StateUpdate): Promise<void>;
|
|
168
|
+
}
|
|
169
|
+
interface ChatableXEvents {
|
|
170
|
+
on<T extends EventType>(eventType: T, callback: EventCallbackMap[T]): Unsubscribe;
|
|
171
|
+
onAiResponse(callback: EventCallbackMap['aiResponse']): Unsubscribe;
|
|
172
|
+
onToolExecution(callback: EventCallbackMap['toolExecution']): Unsubscribe;
|
|
173
|
+
onUserMessage(callback: EventCallbackMap['userMessage']): Unsubscribe;
|
|
174
|
+
}
|
|
175
|
+
interface ChatableXStorage {
|
|
176
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
177
|
+
set<T = unknown>(key: string, value: T): Promise<void>;
|
|
178
|
+
delete(key: string): Promise<void>;
|
|
179
|
+
}
|
|
180
|
+
interface ChatableXToolModule {
|
|
181
|
+
getInfo(): ToolInfo;
|
|
182
|
+
onExecute(handler: ToolExecuteHandler): void;
|
|
183
|
+
}
|
|
184
|
+
interface ChatableXSDK {
|
|
185
|
+
ai: ChatableXAI;
|
|
186
|
+
tools: ChatableXTools;
|
|
187
|
+
skills: ChatableXSkills;
|
|
188
|
+
ui: ChatableXUI;
|
|
189
|
+
events: ChatableXEvents;
|
|
190
|
+
storage: ChatableXStorage;
|
|
191
|
+
tool: ChatableXToolModule;
|
|
192
|
+
}
|
|
193
|
+
declare global {
|
|
194
|
+
interface Window {
|
|
195
|
+
/** SDK instance — set after ChatableX.init() */
|
|
196
|
+
ChatableX?: ChatableXSDK;
|
|
197
|
+
/** Flutter → JS message receiver — set by SDK */
|
|
198
|
+
ChatableXReceive?: (jsonStr: string) => void;
|
|
199
|
+
/** Flutter's JavaScriptChannel (set by Flutter WebView) */
|
|
200
|
+
ChatableXBridge?: {
|
|
201
|
+
postMessage: (msg: string) => void;
|
|
202
|
+
};
|
|
203
|
+
/** Direct dispatch function for Flutter's executeInWebUI */
|
|
204
|
+
__CHATABLEX_DISPATCH__?: (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Low-level WebView bridge between the Web SDK and the Flutter host.
|
|
210
|
+
*
|
|
211
|
+
* Communication:
|
|
212
|
+
* JS → Flutter : window.ChatableXBridge.postMessage(JSON.stringify(msg))
|
|
213
|
+
* Flutter → JS : controller.runJavaScript("window.ChatableXReceive('...')")
|
|
214
|
+
*/
|
|
215
|
+
type EventHandler = (data: unknown) => void;
|
|
216
|
+
declare class Bridge {
|
|
217
|
+
private _msgId;
|
|
218
|
+
private _pending;
|
|
219
|
+
private _listeners;
|
|
220
|
+
private _debug;
|
|
221
|
+
constructor(debug?: boolean);
|
|
222
|
+
/** Install the global ChatableXReceive handler so Flutter can push data in. */
|
|
223
|
+
install(): void;
|
|
224
|
+
/** Wait for ChatableXBridge (set by Flutter) to become available. */
|
|
225
|
+
waitForBridge(timeoutMs: number): Promise<void>;
|
|
226
|
+
/** Send a request to Flutter and wait for a response. */
|
|
227
|
+
sendMessage(method: string, params?: Record<string, unknown>, requestTimeoutMs?: number): Promise<unknown>;
|
|
228
|
+
private _handleResponse;
|
|
229
|
+
private _handleEvent;
|
|
230
|
+
addEventListener(eventType: string, handler: EventHandler): () => void;
|
|
231
|
+
/** Dispatch a synthetic event (used internally). */
|
|
232
|
+
dispatchEvent(eventType: string, data: unknown): void;
|
|
233
|
+
private _nextId;
|
|
234
|
+
private _log;
|
|
235
|
+
destroy(): void;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* chatablex-web-sdk
|
|
240
|
+
*
|
|
241
|
+
* Runtime SDK for ChatableX AI App (WebUI) development.
|
|
242
|
+
* Developers install this package and call `ChatableX.init()` to connect
|
|
243
|
+
* their web app to the ChatableX Flutter host.
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```ts
|
|
247
|
+
* import { ChatableX } from 'chatablex-web-sdk';
|
|
248
|
+
*
|
|
249
|
+
* const sdk = await ChatableX.init({ appId: 'counter-app' });
|
|
250
|
+
*
|
|
251
|
+
* sdk.tool.onExecute(async (params) => {
|
|
252
|
+
* // handle LLM-driven tool calls
|
|
253
|
+
* return { success: true, data: 'done' };
|
|
254
|
+
* });
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
|
|
258
|
+
declare const SDK_VERSION = "1.0.0";
|
|
259
|
+
/**
|
|
260
|
+
* Main entry point. Provides `ChatableX.init()` to bootstrap the SDK.
|
|
261
|
+
*/
|
|
262
|
+
declare const ChatableX: {
|
|
263
|
+
/**
|
|
264
|
+
* Initialize the SDK and establish the bridge with the Flutter host.
|
|
265
|
+
*
|
|
266
|
+
* 1. Sets up `window.ChatableXReceive` (Flutter → JS message handler).
|
|
267
|
+
* 2. Waits for `window.ChatableXBridge` (Flutter's JavaScriptChannel).
|
|
268
|
+
* 3. Sends `sdk_init` handshake and receives tool config from Flutter.
|
|
269
|
+
* 4. Returns the fully-initialised SDK instance.
|
|
270
|
+
*/
|
|
271
|
+
init(config: ChatableXInitConfig): Promise<ChatableXSDK>;
|
|
272
|
+
/** Get the current SDK instance (throws if not initialised). */
|
|
273
|
+
getInstance(): ChatableXSDK;
|
|
274
|
+
/** Check whether the SDK has been initialised. */
|
|
275
|
+
isReady(): boolean;
|
|
276
|
+
/** SDK version */
|
|
277
|
+
version: string;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export { type AiResponseEventData, Bridge, type ChatOptions, type ChatResponse, ChatableX, type ChatableXAI, type ChatableXEvents, type ChatableXInitConfig, type ChatableXSDK, type ChatableXSkills, type ChatableXStorage, type ChatableXToolModule, type ChatableXTools, type ChatableXUI, type CloseEventData, type EventCallbackMap, type EventType, type FilePickerOptions, type Message, type NotificationType, SDK_VERSION, type SessionContext, type Skill, type SkillResult, type SkillVariable, type StateUpdate, type StreamingContentEventData, type TabConfig, type ToolCall, type ToolExecuteHandler, type ToolExecutionEventData, type ToolInfo, type ToolParameter, type ToolResult, type Unsubscribe, type UserMessageEventData };
|