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.
@@ -0,0 +1,14 @@
1
+ import type { Bridge } from '../bridge';
2
+ import type { Skill, SkillResult, ChatableXSkills } from '../types';
3
+
4
+ export function createSkillsModule(bridge: Bridge): ChatableXSkills {
5
+ return {
6
+ list(): Promise<Skill[]> {
7
+ return bridge.sendMessage('skills.list', {}) as Promise<Skill[]>;
8
+ },
9
+
10
+ execute(skillId: string, variables: Record<string, unknown>): Promise<SkillResult> {
11
+ return bridge.sendMessage('skills.execute', { skillId, variables }) as Promise<SkillResult>;
12
+ },
13
+ };
14
+ }
@@ -0,0 +1,18 @@
1
+ import type { Bridge } from '../bridge';
2
+ import type { ChatableXStorage } from '../types';
3
+
4
+ export function createStorageModule(bridge: Bridge): ChatableXStorage {
5
+ return {
6
+ get<T = unknown>(key: string): Promise<T | null> {
7
+ return bridge.sendMessage('storage.get', { key }) as Promise<T | null>;
8
+ },
9
+
10
+ set<T = unknown>(key: string, value: T): Promise<void> {
11
+ return bridge.sendMessage('storage.set', { key, value: value as unknown }) as Promise<void>;
12
+ },
13
+
14
+ delete(key: string): Promise<void> {
15
+ return bridge.sendMessage('storage.delete', { key }) as Promise<void>;
16
+ },
17
+ };
18
+ }
@@ -0,0 +1,54 @@
1
+ import type { Bridge } from '../bridge';
2
+ import type { ToolInfo, ToolExecuteHandler, ChatableXToolModule } from '../types';
3
+
4
+ /**
5
+ * Creates the `sdk.tool` module — the primary interface for LLM-driven
6
+ * tool execution in a ChatableX WebUI app.
7
+ */
8
+ export function createToolModule(bridge: Bridge, appId: string): ChatableXToolModule & { _setInfo(info: Partial<ToolInfo>): void } {
9
+ let _info: ToolInfo = { id: appId, name: appId, version: '1.0.0', description: '' };
10
+ let _handler: ToolExecuteHandler | null = null;
11
+
12
+ const dispatch = async (params: Record<string, unknown>): Promise<Record<string, unknown>> => {
13
+ if (!_handler) {
14
+ return { success: false, error: 'No execute handler registered' };
15
+ }
16
+ try {
17
+ return await _handler(params);
18
+ } catch (e: unknown) {
19
+ const msg = e instanceof Error ? e.message : String(e);
20
+ return { success: false, error: msg };
21
+ }
22
+ };
23
+
24
+ // Expose globally so Flutter can call it via runJavaScriptReturningResult
25
+ window.__CHATABLEX_DISPATCH__ = dispatch;
26
+
27
+ // Listen for toolExecution events pushed from Flutter.
28
+ // If the event carries a _requestId, send the result back via the bridge
29
+ // so Flutter can resolve its pending Completer.
30
+ bridge.addEventListener('toolExecution', async (data) => {
31
+ const params = data as Record<string, unknown>;
32
+ const requestId = params._requestId as string | undefined;
33
+ const result = await dispatch(params);
34
+ if (requestId && window.ChatableXBridge) {
35
+ window.ChatableXBridge.postMessage(JSON.stringify({
36
+ method: 'tool.executeResult',
37
+ params: { _requestId: requestId, ...result },
38
+ }));
39
+ }
40
+ });
41
+
42
+ return {
43
+ getInfo(): ToolInfo {
44
+ return { ..._info };
45
+ },
46
+ onExecute(handler: ToolExecuteHandler): void {
47
+ _handler = handler;
48
+ },
49
+ /** @internal — called by SDK after handshake to fill in tool metadata */
50
+ _setInfo(info: Partial<ToolInfo>): void {
51
+ _info = { ..._info, ...info };
52
+ },
53
+ };
54
+ }
@@ -0,0 +1,18 @@
1
+ import type { Bridge } from '../bridge';
2
+ import type { ToolInfo, ToolResult, ChatableXTools } from '../types';
3
+
4
+ export function createToolsModule(bridge: Bridge): ChatableXTools {
5
+ return {
6
+ list(): Promise<ToolInfo[]> {
7
+ return bridge.sendMessage('tools.list', {}) as Promise<ToolInfo[]>;
8
+ },
9
+
10
+ execute(toolId: string, params: Record<string, unknown>): Promise<ToolResult> {
11
+ return bridge.sendMessage('tools.execute', { toolId, params }) as Promise<ToolResult>;
12
+ },
13
+
14
+ executeWithConfirm(toolId: string, params: Record<string, unknown>): Promise<ToolResult> {
15
+ return bridge.sendMessage('tools.executeWithConfirm', { toolId, params }) as Promise<ToolResult>;
16
+ },
17
+ };
18
+ }
@@ -0,0 +1,26 @@
1
+ import type { Bridge } from '../bridge';
2
+ import type { NotificationType, FilePickerOptions, TabConfig, StateUpdate, ChatableXUI } from '../types';
3
+
4
+ export function createUIModule(bridge: Bridge): ChatableXUI {
5
+ return {
6
+ showNotification(message: string, type: NotificationType = 'info'): Promise<void> {
7
+ return bridge.sendMessage('ui.showNotification', { message, type }) as Promise<void>;
8
+ },
9
+
10
+ showConfirm(title: string, message: string): Promise<boolean> {
11
+ return bridge.sendMessage('ui.showConfirm', { title, message }) as Promise<boolean>;
12
+ },
13
+
14
+ pickFile(options?: FilePickerOptions): Promise<string | null> {
15
+ return bridge.sendMessage('ui.pickFile', options ?? {}) as Promise<string | null>;
16
+ },
17
+
18
+ openTab(config: TabConfig): Promise<void> {
19
+ return bridge.sendMessage('ui.openTab', config as unknown as Record<string, unknown>) as Promise<void>;
20
+ },
21
+
22
+ updateState(state: StateUpdate): Promise<void> {
23
+ return bridge.sendMessage('ui.updateState', state as Record<string, unknown>) as Promise<void>;
24
+ },
25
+ };
26
+ }
package/src/types.ts ADDED
@@ -0,0 +1,270 @@
1
+ /**
2
+ * ChatableX Web SDK — Type Definitions
3
+ */
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Chat / AI
7
+ // ---------------------------------------------------------------------------
8
+
9
+ export interface ChatOptions {
10
+ sessionId?: string;
11
+ context?: Record<string, unknown>;
12
+ tools?: string[];
13
+ skills?: string[];
14
+ stream?: boolean;
15
+ }
16
+
17
+ export interface ChatResponse {
18
+ content: string;
19
+ sessionId: string;
20
+ messageId: string;
21
+ toolResults?: ToolResult[];
22
+ finished: boolean;
23
+ model?: string;
24
+ usage?: { promptTokens: number; completionTokens: number; totalTokens: number };
25
+ }
26
+
27
+ export interface SessionContext {
28
+ sessionId: string;
29
+ name: string;
30
+ messages: Message[];
31
+ activeTools: string[];
32
+ activeSkills: string[];
33
+ createdAt: string;
34
+ updatedAt: string;
35
+ }
36
+
37
+ export interface Message {
38
+ id: string;
39
+ role: 'user' | 'assistant' | 'system' | 'tool';
40
+ content: string;
41
+ timestamp: string;
42
+ toolCalls?: ToolCall[];
43
+ }
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Tool
47
+ // ---------------------------------------------------------------------------
48
+
49
+ export interface ToolInfo {
50
+ id: string;
51
+ name: string;
52
+ version: string;
53
+ description: string;
54
+ }
55
+
56
+ export interface ToolParameter {
57
+ name: string;
58
+ type: string;
59
+ description: string;
60
+ required: boolean;
61
+ default?: unknown;
62
+ enum?: string[];
63
+ }
64
+
65
+ export interface ToolCall {
66
+ id: string;
67
+ toolId: string;
68
+ name: string;
69
+ params: Record<string, unknown>;
70
+ status: 'pending' | 'running' | 'success' | 'error' | 'cancelled';
71
+ }
72
+
73
+ export interface ToolResult {
74
+ success: boolean;
75
+ data?: unknown;
76
+ error?: string;
77
+ toolId: string;
78
+ duration?: number;
79
+ }
80
+
81
+ export type ToolExecuteHandler = (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
82
+
83
+ // ---------------------------------------------------------------------------
84
+ // Skill
85
+ // ---------------------------------------------------------------------------
86
+
87
+ export interface Skill {
88
+ id: string;
89
+ name: string;
90
+ description: string;
91
+ version: string;
92
+ author?: string;
93
+ category?: string;
94
+ toolIds: string[];
95
+ variables: SkillVariable[];
96
+ installed: boolean;
97
+ }
98
+
99
+ export interface SkillVariable {
100
+ name: string;
101
+ type: string;
102
+ description: string;
103
+ required: boolean;
104
+ default?: unknown;
105
+ }
106
+
107
+ export interface SkillResult {
108
+ success: boolean;
109
+ data?: unknown;
110
+ error?: string;
111
+ skillId: string;
112
+ toolResults?: ToolResult[];
113
+ }
114
+
115
+ // ---------------------------------------------------------------------------
116
+ // UI
117
+ // ---------------------------------------------------------------------------
118
+
119
+ export type NotificationType = 'info' | 'success' | 'warning' | 'error';
120
+
121
+ export interface FilePickerOptions {
122
+ type?: 'any' | 'image' | 'video' | 'audio' | 'custom';
123
+ multiple?: boolean;
124
+ allowedExtensions?: string[];
125
+ }
126
+
127
+ export interface TabConfig {
128
+ id: string;
129
+ title: string;
130
+ icon?: string;
131
+ type: 'chat' | 'tool' | 'skill' | 'custom';
132
+ data?: Record<string, unknown>;
133
+ }
134
+
135
+ export interface StateUpdate {
136
+ refreshMessages?: boolean;
137
+ closeWebUI?: boolean;
138
+ [key: string]: unknown;
139
+ }
140
+
141
+ // ---------------------------------------------------------------------------
142
+ // Events
143
+ // ---------------------------------------------------------------------------
144
+
145
+ export type EventType =
146
+ | 'aiResponse'
147
+ | 'toolExecution'
148
+ | 'userMessage'
149
+ | 'streamingContent'
150
+ | 'close';
151
+
152
+ export interface AiResponseEventData extends ChatResponse {}
153
+
154
+ export interface ToolExecutionEventData {
155
+ toolCall: ToolCall;
156
+ result?: ToolResult;
157
+ }
158
+
159
+ export interface UserMessageEventData {
160
+ message: string;
161
+ timestamp: string;
162
+ }
163
+
164
+ export interface StreamingContentEventData {
165
+ content: string;
166
+ finished?: boolean;
167
+ }
168
+
169
+ export interface CloseEventData {
170
+ toolId: string;
171
+ }
172
+
173
+ export interface EventCallbackMap {
174
+ aiResponse: (data: AiResponseEventData) => void;
175
+ toolExecution: (data: ToolExecutionEventData) => void;
176
+ userMessage: (data: UserMessageEventData) => void;
177
+ streamingContent: (data: StreamingContentEventData) => void;
178
+ close: (data: CloseEventData) => void;
179
+ }
180
+
181
+ export type Unsubscribe = () => void;
182
+
183
+ // ---------------------------------------------------------------------------
184
+ // Init Config
185
+ // ---------------------------------------------------------------------------
186
+
187
+ export interface ChatableXInitConfig {
188
+ /** Your app / tool id (must match manifest.json id) */
189
+ appId: string;
190
+ /** SDK version override (default: SDK built-in version) */
191
+ version?: string;
192
+ /** Enable debug logging (default: false) */
193
+ debug?: boolean;
194
+ /** Timeout in ms for the handshake with Flutter (default: 10000) */
195
+ timeout?: number;
196
+ }
197
+
198
+ // ---------------------------------------------------------------------------
199
+ // SDK Module Interfaces
200
+ // ---------------------------------------------------------------------------
201
+
202
+ export interface ChatableXAI {
203
+ chat(message: string, options?: ChatOptions): Promise<ChatResponse>;
204
+ chatStream(message: string, options?: ChatOptions): Promise<unknown>;
205
+ getContext(): Promise<SessionContext>;
206
+ }
207
+
208
+ export interface ChatableXTools {
209
+ list(): Promise<ToolInfo[]>;
210
+ execute(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
211
+ executeWithConfirm(toolId: string, params: Record<string, unknown>): Promise<ToolResult>;
212
+ }
213
+
214
+ export interface ChatableXSkills {
215
+ list(): Promise<Skill[]>;
216
+ execute(skillId: string, variables: Record<string, unknown>): Promise<SkillResult>;
217
+ }
218
+
219
+ export interface ChatableXUI {
220
+ showNotification(message: string, type?: NotificationType): Promise<void>;
221
+ showConfirm(title: string, message: string): Promise<boolean>;
222
+ pickFile(options?: FilePickerOptions): Promise<string | null>;
223
+ openTab(config: TabConfig): Promise<void>;
224
+ updateState(state: StateUpdate): Promise<void>;
225
+ }
226
+
227
+ export interface ChatableXEvents {
228
+ on<T extends EventType>(eventType: T, callback: EventCallbackMap[T]): Unsubscribe;
229
+ onAiResponse(callback: EventCallbackMap['aiResponse']): Unsubscribe;
230
+ onToolExecution(callback: EventCallbackMap['toolExecution']): Unsubscribe;
231
+ onUserMessage(callback: EventCallbackMap['userMessage']): Unsubscribe;
232
+ }
233
+
234
+ export interface ChatableXStorage {
235
+ get<T = unknown>(key: string): Promise<T | null>;
236
+ set<T = unknown>(key: string, value: T): Promise<void>;
237
+ delete(key: string): Promise<void>;
238
+ }
239
+
240
+ export interface ChatableXToolModule {
241
+ getInfo(): ToolInfo;
242
+ onExecute(handler: ToolExecuteHandler): void;
243
+ }
244
+
245
+ export interface ChatableXSDK {
246
+ ai: ChatableXAI;
247
+ tools: ChatableXTools;
248
+ skills: ChatableXSkills;
249
+ ui: ChatableXUI;
250
+ events: ChatableXEvents;
251
+ storage: ChatableXStorage;
252
+ tool: ChatableXToolModule;
253
+ }
254
+
255
+ // ---------------------------------------------------------------------------
256
+ // Global Window Augmentation
257
+ // ---------------------------------------------------------------------------
258
+
259
+ declare global {
260
+ interface Window {
261
+ /** SDK instance — set after ChatableX.init() */
262
+ ChatableX?: ChatableXSDK;
263
+ /** Flutter → JS message receiver — set by SDK */
264
+ ChatableXReceive?: (jsonStr: string) => void;
265
+ /** Flutter's JavaScriptChannel (set by Flutter WebView) */
266
+ ChatableXBridge?: { postMessage: (msg: string) => void };
267
+ /** Direct dispatch function for Flutter's executeInWebUI */
268
+ __CHATABLEX_DISPATCH__?: (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
269
+ }
270
+ }