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/dist/index.mjs ADDED
@@ -0,0 +1,337 @@
1
+ // src/bridge.ts
2
+ var Bridge = class {
3
+ constructor(debug = false) {
4
+ this._msgId = 0;
5
+ this._pending = /* @__PURE__ */ new Map();
6
+ this._listeners = /* @__PURE__ */ new Map();
7
+ this._debug = debug;
8
+ }
9
+ // -------------------------------------------------------------------------
10
+ // Lifecycle
11
+ // -------------------------------------------------------------------------
12
+ /** Install the global ChatableXReceive handler so Flutter can push data in. */
13
+ install() {
14
+ window.ChatableXReceive = (jsonStr) => {
15
+ try {
16
+ const data = JSON.parse(jsonStr);
17
+ if (data.type === "response") {
18
+ this._handleResponse(data);
19
+ } else if (data.type === "event") {
20
+ this._handleEvent(data);
21
+ }
22
+ } catch (e) {
23
+ console.error("[ChatableX Bridge] receive parse error:", e);
24
+ }
25
+ };
26
+ this._log("ChatableXReceive installed");
27
+ }
28
+ /** Wait for ChatableXBridge (set by Flutter) to become available. */
29
+ waitForBridge(timeoutMs) {
30
+ return new Promise((resolve, reject) => {
31
+ if (window.ChatableXBridge) {
32
+ resolve();
33
+ return;
34
+ }
35
+ const start = Date.now();
36
+ const check = setInterval(() => {
37
+ if (window.ChatableXBridge) {
38
+ clearInterval(check);
39
+ resolve();
40
+ } else if (Date.now() - start > timeoutMs) {
41
+ clearInterval(check);
42
+ reject(new Error(`ChatableXBridge not available after ${timeoutMs}ms`));
43
+ }
44
+ }, 50);
45
+ });
46
+ }
47
+ // -------------------------------------------------------------------------
48
+ // Request / Response
49
+ // -------------------------------------------------------------------------
50
+ /** Send a request to Flutter and wait for a response. */
51
+ sendMessage(method, params = {}, requestTimeoutMs = 3e4) {
52
+ return new Promise((resolve, reject) => {
53
+ const id = this._nextId();
54
+ const message = { id, method, params, timestamp: Date.now() };
55
+ const timer = setTimeout(() => {
56
+ if (this._pending.has(id)) {
57
+ this._pending.delete(id);
58
+ reject(new Error(`Request timeout: ${method}`));
59
+ }
60
+ }, requestTimeoutMs);
61
+ this._pending.set(id, { resolve, reject, timer });
62
+ if (window.ChatableXBridge) {
63
+ window.ChatableXBridge.postMessage(JSON.stringify(message));
64
+ } else {
65
+ clearTimeout(timer);
66
+ this._pending.delete(id);
67
+ reject(new Error("ChatableXBridge not available"));
68
+ }
69
+ });
70
+ }
71
+ _handleResponse(data) {
72
+ const pending = this._pending.get(data.id);
73
+ if (!pending) return;
74
+ this._pending.delete(data.id);
75
+ clearTimeout(pending.timer);
76
+ if (data.success) {
77
+ pending.resolve(data.data);
78
+ } else {
79
+ pending.reject(new Error(data.error ?? "Unknown error"));
80
+ }
81
+ }
82
+ // -------------------------------------------------------------------------
83
+ // Events
84
+ // -------------------------------------------------------------------------
85
+ _handleEvent(data) {
86
+ const handlers = this._listeners.get(data.eventType);
87
+ if (handlers) {
88
+ for (const fn of handlers) {
89
+ try {
90
+ fn(data.data);
91
+ } catch (e) {
92
+ console.error("[ChatableX] event handler error:", e);
93
+ }
94
+ }
95
+ }
96
+ }
97
+ addEventListener(eventType, handler) {
98
+ if (!this._listeners.has(eventType)) {
99
+ this._listeners.set(eventType, /* @__PURE__ */ new Set());
100
+ }
101
+ this._listeners.get(eventType).add(handler);
102
+ return () => {
103
+ const set = this._listeners.get(eventType);
104
+ if (set) {
105
+ set.delete(handler);
106
+ if (set.size === 0) this._listeners.delete(eventType);
107
+ }
108
+ };
109
+ }
110
+ /** Dispatch a synthetic event (used internally). */
111
+ dispatchEvent(eventType, data) {
112
+ this._handleEvent({ eventType, data });
113
+ }
114
+ // -------------------------------------------------------------------------
115
+ // Internals
116
+ // -------------------------------------------------------------------------
117
+ _nextId() {
118
+ return `ctx_${++this._msgId}_${Date.now()}`;
119
+ }
120
+ _log(...args) {
121
+ if (this._debug) console.log("[ChatableX Bridge]", ...args);
122
+ }
123
+ destroy() {
124
+ for (const [, p] of this._pending) {
125
+ clearTimeout(p.timer);
126
+ p.reject(new Error("Bridge destroyed"));
127
+ }
128
+ this._pending.clear();
129
+ this._listeners.clear();
130
+ window.ChatableXReceive = void 0;
131
+ }
132
+ };
133
+
134
+ // src/modules/tool.ts
135
+ function createToolModule(bridge, appId) {
136
+ let _info = { id: appId, name: appId, version: "1.0.0", description: "" };
137
+ let _handler = null;
138
+ const dispatch = async (params) => {
139
+ if (!_handler) {
140
+ return { success: false, error: "No execute handler registered" };
141
+ }
142
+ try {
143
+ return await _handler(params);
144
+ } catch (e) {
145
+ const msg = e instanceof Error ? e.message : String(e);
146
+ return { success: false, error: msg };
147
+ }
148
+ };
149
+ window.__CHATABLEX_DISPATCH__ = dispatch;
150
+ bridge.addEventListener("toolExecution", async (data) => {
151
+ const params = data;
152
+ const requestId = params._requestId;
153
+ const result = await dispatch(params);
154
+ if (requestId && window.ChatableXBridge) {
155
+ window.ChatableXBridge.postMessage(JSON.stringify({
156
+ method: "tool.executeResult",
157
+ params: { _requestId: requestId, ...result }
158
+ }));
159
+ }
160
+ });
161
+ return {
162
+ getInfo() {
163
+ return { ..._info };
164
+ },
165
+ onExecute(handler) {
166
+ _handler = handler;
167
+ },
168
+ /** @internal — called by SDK after handshake to fill in tool metadata */
169
+ _setInfo(info) {
170
+ _info = { ..._info, ...info };
171
+ }
172
+ };
173
+ }
174
+
175
+ // src/modules/events.ts
176
+ function createEventsModule(bridge) {
177
+ return {
178
+ on(eventType, callback) {
179
+ bridge.sendMessage("events.subscribe", { eventType }).catch(() => {
180
+ });
181
+ return bridge.addEventListener(eventType, callback);
182
+ },
183
+ onAiResponse(callback) {
184
+ return this.on("aiResponse", callback);
185
+ },
186
+ onToolExecution(callback) {
187
+ return this.on("toolExecution", callback);
188
+ },
189
+ onUserMessage(callback) {
190
+ return this.on("userMessage", callback);
191
+ }
192
+ };
193
+ }
194
+
195
+ // src/modules/ai.ts
196
+ function createAIModule(bridge) {
197
+ return {
198
+ chat(message, options) {
199
+ return bridge.sendMessage("ai.chat", { message, ...options });
200
+ },
201
+ chatStream(message, options) {
202
+ return bridge.sendMessage("ai.chatStream", { message, ...options });
203
+ },
204
+ getContext() {
205
+ return bridge.sendMessage("ai.getContext", {});
206
+ }
207
+ };
208
+ }
209
+
210
+ // src/modules/ui.ts
211
+ function createUIModule(bridge) {
212
+ return {
213
+ showNotification(message, type = "info") {
214
+ return bridge.sendMessage("ui.showNotification", { message, type });
215
+ },
216
+ showConfirm(title, message) {
217
+ return bridge.sendMessage("ui.showConfirm", { title, message });
218
+ },
219
+ pickFile(options) {
220
+ return bridge.sendMessage("ui.pickFile", options ?? {});
221
+ },
222
+ openTab(config) {
223
+ return bridge.sendMessage("ui.openTab", config);
224
+ },
225
+ updateState(state) {
226
+ return bridge.sendMessage("ui.updateState", state);
227
+ }
228
+ };
229
+ }
230
+
231
+ // src/modules/storage.ts
232
+ function createStorageModule(bridge) {
233
+ return {
234
+ get(key) {
235
+ return bridge.sendMessage("storage.get", { key });
236
+ },
237
+ set(key, value) {
238
+ return bridge.sendMessage("storage.set", { key, value });
239
+ },
240
+ delete(key) {
241
+ return bridge.sendMessage("storage.delete", { key });
242
+ }
243
+ };
244
+ }
245
+
246
+ // src/modules/tools.ts
247
+ function createToolsModule(bridge) {
248
+ return {
249
+ list() {
250
+ return bridge.sendMessage("tools.list", {});
251
+ },
252
+ execute(toolId, params) {
253
+ return bridge.sendMessage("tools.execute", { toolId, params });
254
+ },
255
+ executeWithConfirm(toolId, params) {
256
+ return bridge.sendMessage("tools.executeWithConfirm", { toolId, params });
257
+ }
258
+ };
259
+ }
260
+
261
+ // src/modules/skills.ts
262
+ function createSkillsModule(bridge) {
263
+ return {
264
+ list() {
265
+ return bridge.sendMessage("skills.list", {});
266
+ },
267
+ execute(skillId, variables) {
268
+ return bridge.sendMessage("skills.execute", { skillId, variables });
269
+ }
270
+ };
271
+ }
272
+
273
+ // src/index.ts
274
+ var SDK_VERSION = "1.0.0";
275
+ var _instance = null;
276
+ var ChatableX = {
277
+ /**
278
+ * Initialize the SDK and establish the bridge with the Flutter host.
279
+ *
280
+ * 1. Sets up `window.ChatableXReceive` (Flutter → JS message handler).
281
+ * 2. Waits for `window.ChatableXBridge` (Flutter's JavaScriptChannel).
282
+ * 3. Sends `sdk_init` handshake and receives tool config from Flutter.
283
+ * 4. Returns the fully-initialised SDK instance.
284
+ */
285
+ async init(config) {
286
+ if (_instance) return _instance;
287
+ const debug = config.debug ?? false;
288
+ const timeout = config.timeout ?? 1e4;
289
+ const bridge = new Bridge(debug);
290
+ bridge.install();
291
+ await bridge.waitForBridge(timeout);
292
+ if (debug) console.log("[ChatableX] Bridge connected, sending sdk_init");
293
+ let toolConfig = {};
294
+ try {
295
+ const resp = await bridge.sendMessage("sdk_init", {
296
+ appId: config.appId,
297
+ sdkVersion: SDK_VERSION
298
+ });
299
+ if (resp && typeof resp === "object") {
300
+ toolConfig = resp;
301
+ }
302
+ } catch {
303
+ if (debug) console.warn("[ChatableX] sdk_init handshake failed, continuing with defaults");
304
+ }
305
+ const toolModule = createToolModule(bridge, config.appId);
306
+ if (toolConfig) toolModule._setInfo(toolConfig);
307
+ const sdk = {
308
+ ai: createAIModule(bridge),
309
+ tools: createToolsModule(bridge),
310
+ skills: createSkillsModule(bridge),
311
+ ui: createUIModule(bridge),
312
+ events: createEventsModule(bridge),
313
+ storage: createStorageModule(bridge),
314
+ tool: toolModule
315
+ };
316
+ window.ChatableX = sdk;
317
+ _instance = sdk;
318
+ if (debug) console.log(`[ChatableX] SDK v${SDK_VERSION} ready for: ${config.appId}`);
319
+ return sdk;
320
+ },
321
+ /** Get the current SDK instance (throws if not initialised). */
322
+ getInstance() {
323
+ if (!_instance) throw new Error("ChatableX SDK not initialised. Call ChatableX.init() first.");
324
+ return _instance;
325
+ },
326
+ /** Check whether the SDK has been initialised. */
327
+ isReady() {
328
+ return _instance !== null;
329
+ },
330
+ /** SDK version */
331
+ version: SDK_VERSION
332
+ };
333
+ export {
334
+ Bridge,
335
+ ChatableX,
336
+ SDK_VERSION
337
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "chatablex-web-sdk",
3
+ "version": "1.0.0",
4
+ "description": "ChatableX Web SDK for AI App WebUI development. Provides bridge communication with the ChatableX Flutter client.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "src",
18
+ "README.md",
19
+ "README.zh-CN.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
23
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
24
+ "typecheck": "tsc --noEmit",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": [
28
+ "chatablex",
29
+ "sdk",
30
+ "webui",
31
+ "ai",
32
+ "flutter",
33
+ "webview",
34
+ "bridge"
35
+ ],
36
+ "author": "ChatableX Team",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/ersa-org/co-work.git",
41
+ "directory": "chatablex-web-sdk"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^8.0.1",
45
+ "typescript": "^5.3.0"
46
+ },
47
+ "engines": {
48
+ "node": ">=16.0.0"
49
+ }
50
+ }
package/src/bridge.ts ADDED
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Low-level WebView bridge between the Web SDK and the Flutter host.
3
+ *
4
+ * Communication:
5
+ * JS → Flutter : window.ChatableXBridge.postMessage(JSON.stringify(msg))
6
+ * Flutter → JS : controller.runJavaScript("window.ChatableXReceive('...')")
7
+ */
8
+
9
+ type PendingRequest = {
10
+ resolve: (value: unknown) => void;
11
+ reject: (reason: Error) => void;
12
+ timer: ReturnType<typeof setTimeout>;
13
+ };
14
+
15
+ type EventHandler = (data: unknown) => void;
16
+
17
+ export class Bridge {
18
+ private _msgId = 0;
19
+ private _pending = new Map<string, PendingRequest>();
20
+ private _listeners = new Map<string, Set<EventHandler>>();
21
+ private _debug: boolean;
22
+
23
+ constructor(debug = false) {
24
+ this._debug = debug;
25
+ }
26
+
27
+ // -------------------------------------------------------------------------
28
+ // Lifecycle
29
+ // -------------------------------------------------------------------------
30
+
31
+ /** Install the global ChatableXReceive handler so Flutter can push data in. */
32
+ install(): void {
33
+ window.ChatableXReceive = (jsonStr: string) => {
34
+ try {
35
+ const data = JSON.parse(jsonStr);
36
+ if (data.type === 'response') {
37
+ this._handleResponse(data);
38
+ } else if (data.type === 'event') {
39
+ this._handleEvent(data);
40
+ }
41
+ } catch (e) {
42
+ console.error('[ChatableX Bridge] receive parse error:', e);
43
+ }
44
+ };
45
+ this._log('ChatableXReceive installed');
46
+ }
47
+
48
+ /** Wait for ChatableXBridge (set by Flutter) to become available. */
49
+ waitForBridge(timeoutMs: number): Promise<void> {
50
+ return new Promise((resolve, reject) => {
51
+ if (window.ChatableXBridge) {
52
+ resolve();
53
+ return;
54
+ }
55
+ const start = Date.now();
56
+ const check = setInterval(() => {
57
+ if (window.ChatableXBridge) {
58
+ clearInterval(check);
59
+ resolve();
60
+ } else if (Date.now() - start > timeoutMs) {
61
+ clearInterval(check);
62
+ reject(new Error(`ChatableXBridge not available after ${timeoutMs}ms`));
63
+ }
64
+ }, 50);
65
+ });
66
+ }
67
+
68
+ // -------------------------------------------------------------------------
69
+ // Request / Response
70
+ // -------------------------------------------------------------------------
71
+
72
+ /** Send a request to Flutter and wait for a response. */
73
+ sendMessage(method: string, params: Record<string, unknown> = {}, requestTimeoutMs = 30_000): Promise<unknown> {
74
+ return new Promise((resolve, reject) => {
75
+ const id = this._nextId();
76
+ const message = { id, method, params, timestamp: Date.now() };
77
+
78
+ const timer = setTimeout(() => {
79
+ if (this._pending.has(id)) {
80
+ this._pending.delete(id);
81
+ reject(new Error(`Request timeout: ${method}`));
82
+ }
83
+ }, requestTimeoutMs);
84
+
85
+ this._pending.set(id, { resolve, reject, timer });
86
+
87
+ if (window.ChatableXBridge) {
88
+ window.ChatableXBridge.postMessage(JSON.stringify(message));
89
+ } else {
90
+ clearTimeout(timer);
91
+ this._pending.delete(id);
92
+ reject(new Error('ChatableXBridge not available'));
93
+ }
94
+ });
95
+ }
96
+
97
+ private _handleResponse(data: { id: string; success: boolean; data?: unknown; error?: string }): void {
98
+ const pending = this._pending.get(data.id);
99
+ if (!pending) return;
100
+ this._pending.delete(data.id);
101
+ clearTimeout(pending.timer);
102
+ if (data.success) {
103
+ pending.resolve(data.data);
104
+ } else {
105
+ pending.reject(new Error(data.error ?? 'Unknown error'));
106
+ }
107
+ }
108
+
109
+ // -------------------------------------------------------------------------
110
+ // Events
111
+ // -------------------------------------------------------------------------
112
+
113
+ private _handleEvent(data: { eventType: string; data: unknown }): void {
114
+ const handlers = this._listeners.get(data.eventType);
115
+ if (handlers) {
116
+ for (const fn of handlers) {
117
+ try { fn(data.data); } catch (e) { console.error('[ChatableX] event handler error:', e); }
118
+ }
119
+ }
120
+ }
121
+
122
+ addEventListener(eventType: string, handler: EventHandler): () => void {
123
+ if (!this._listeners.has(eventType)) {
124
+ this._listeners.set(eventType, new Set());
125
+ }
126
+ this._listeners.get(eventType)!.add(handler);
127
+ return () => {
128
+ const set = this._listeners.get(eventType);
129
+ if (set) {
130
+ set.delete(handler);
131
+ if (set.size === 0) this._listeners.delete(eventType);
132
+ }
133
+ };
134
+ }
135
+
136
+ /** Dispatch a synthetic event (used internally). */
137
+ dispatchEvent(eventType: string, data: unknown): void {
138
+ this._handleEvent({ eventType, data });
139
+ }
140
+
141
+ // -------------------------------------------------------------------------
142
+ // Internals
143
+ // -------------------------------------------------------------------------
144
+
145
+ private _nextId(): string {
146
+ return `ctx_${++this._msgId}_${Date.now()}`;
147
+ }
148
+
149
+ private _log(...args: unknown[]): void {
150
+ if (this._debug) console.log('[ChatableX Bridge]', ...args);
151
+ }
152
+
153
+ destroy(): void {
154
+ for (const [, p] of this._pending) {
155
+ clearTimeout(p.timer);
156
+ p.reject(new Error('Bridge destroyed'));
157
+ }
158
+ this._pending.clear();
159
+ this._listeners.clear();
160
+ window.ChatableXReceive = undefined;
161
+ }
162
+ }
package/src/index.ts ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * chatablex-web-sdk
3
+ *
4
+ * Runtime SDK for ChatableX AI App (WebUI) development.
5
+ * Developers install this package and call `ChatableX.init()` to connect
6
+ * their web app to the ChatableX Flutter host.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { ChatableX } from 'chatablex-web-sdk';
11
+ *
12
+ * const sdk = await ChatableX.init({ appId: 'counter-app' });
13
+ *
14
+ * sdk.tool.onExecute(async (params) => {
15
+ * // handle LLM-driven tool calls
16
+ * return { success: true, data: 'done' };
17
+ * });
18
+ * ```
19
+ */
20
+
21
+ import { Bridge } from './bridge';
22
+ import { createToolModule } from './modules/tool';
23
+ import { createEventsModule } from './modules/events';
24
+ import { createAIModule } from './modules/ai';
25
+ import { createUIModule } from './modules/ui';
26
+ import { createStorageModule } from './modules/storage';
27
+ import { createToolsModule } from './modules/tools';
28
+ import { createSkillsModule } from './modules/skills';
29
+ import type { ChatableXSDK, ChatableXInitConfig, ToolInfo } from './types';
30
+
31
+ export const SDK_VERSION = '1.0.0';
32
+
33
+ let _instance: ChatableXSDK | null = null;
34
+
35
+ /**
36
+ * Main entry point. Provides `ChatableX.init()` to bootstrap the SDK.
37
+ */
38
+ export const ChatableX = {
39
+ /**
40
+ * Initialize the SDK and establish the bridge with the Flutter host.
41
+ *
42
+ * 1. Sets up `window.ChatableXReceive` (Flutter → JS message handler).
43
+ * 2. Waits for `window.ChatableXBridge` (Flutter's JavaScriptChannel).
44
+ * 3. Sends `sdk_init` handshake and receives tool config from Flutter.
45
+ * 4. Returns the fully-initialised SDK instance.
46
+ */
47
+ async init(config: ChatableXInitConfig): Promise<ChatableXSDK> {
48
+ if (_instance) return _instance;
49
+
50
+ const debug = config.debug ?? false;
51
+ const timeout = config.timeout ?? 10_000;
52
+ const bridge = new Bridge(debug);
53
+
54
+ // 1. Install the global receiver first
55
+ bridge.install();
56
+
57
+ // 2. Wait for Flutter to set up the channel
58
+ await bridge.waitForBridge(timeout);
59
+
60
+ if (debug) console.log('[ChatableX] Bridge connected, sending sdk_init');
61
+
62
+ // 3. Handshake — tell Flutter we're ready and get tool config back
63
+ let toolConfig: Partial<ToolInfo> = {};
64
+ try {
65
+ const resp = await bridge.sendMessage('sdk_init', {
66
+ appId: config.appId,
67
+ sdkVersion: SDK_VERSION,
68
+ });
69
+ if (resp && typeof resp === 'object') {
70
+ toolConfig = resp as Partial<ToolInfo>;
71
+ }
72
+ } catch {
73
+ if (debug) console.warn('[ChatableX] sdk_init handshake failed, continuing with defaults');
74
+ }
75
+
76
+ // 4. Create modules
77
+ const toolModule = createToolModule(bridge, config.appId);
78
+ if (toolConfig) toolModule._setInfo(toolConfig);
79
+
80
+ const sdk: ChatableXSDK = {
81
+ ai: createAIModule(bridge),
82
+ tools: createToolsModule(bridge),
83
+ skills: createSkillsModule(bridge),
84
+ ui: createUIModule(bridge),
85
+ events: createEventsModule(bridge),
86
+ storage: createStorageModule(bridge),
87
+ tool: toolModule,
88
+ };
89
+
90
+ // Expose on window for debugging / Flutter interop
91
+ window.ChatableX = sdk;
92
+
93
+ _instance = sdk;
94
+ if (debug) console.log(`[ChatableX] SDK v${SDK_VERSION} ready for: ${config.appId}`);
95
+ return sdk;
96
+ },
97
+
98
+ /** Get the current SDK instance (throws if not initialised). */
99
+ getInstance(): ChatableXSDK {
100
+ if (!_instance) throw new Error('ChatableX SDK not initialised. Call ChatableX.init() first.');
101
+ return _instance;
102
+ },
103
+
104
+ /** Check whether the SDK has been initialised. */
105
+ isReady(): boolean {
106
+ return _instance !== null;
107
+ },
108
+
109
+ /** SDK version */
110
+ version: SDK_VERSION,
111
+ };
112
+
113
+ // Re-export all types
114
+ export * from './types';
115
+ export { Bridge } from './bridge';
@@ -0,0 +1,18 @@
1
+ import type { Bridge } from '../bridge';
2
+ import type { ChatOptions, ChatResponse, SessionContext, ChatableXAI } from '../types';
3
+
4
+ export function createAIModule(bridge: Bridge): ChatableXAI {
5
+ return {
6
+ chat(message: string, options?: ChatOptions): Promise<ChatResponse> {
7
+ return bridge.sendMessage('ai.chat', { message, ...options }) as Promise<ChatResponse>;
8
+ },
9
+
10
+ chatStream(message: string, options?: ChatOptions): Promise<unknown> {
11
+ return bridge.sendMessage('ai.chatStream', { message, ...options });
12
+ },
13
+
14
+ getContext(): Promise<SessionContext> {
15
+ return bridge.sendMessage('ai.getContext', {}) as Promise<SessionContext>;
16
+ },
17
+ };
18
+ }
@@ -0,0 +1,23 @@
1
+ import type { Bridge } from '../bridge';
2
+ import type { EventType, EventCallbackMap, Unsubscribe, ChatableXEvents } from '../types';
3
+
4
+ export function createEventsModule(bridge: Bridge): ChatableXEvents {
5
+ return {
6
+ on<T extends EventType>(eventType: T, callback: EventCallbackMap[T]): Unsubscribe {
7
+ bridge.sendMessage('events.subscribe', { eventType }).catch(() => {});
8
+ return bridge.addEventListener(eventType, callback as (data: unknown) => void);
9
+ },
10
+
11
+ onAiResponse(callback) {
12
+ return this.on('aiResponse', callback);
13
+ },
14
+
15
+ onToolExecution(callback) {
16
+ return this.on('toolExecution', callback);
17
+ },
18
+
19
+ onUserMessage(callback) {
20
+ return this.on('userMessage', callback);
21
+ },
22
+ };
23
+ }