@aikaara/chat-sdk 0.1.4 → 0.3.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/headless.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./headless-CrgIWcf7.cjs");exports.ActionCableClient=e.ActionCableClient;exports.AikaaraChatClient=e.AikaaraChatClient;exports.ApiClient=e.ApiClient;exports.ChannelSubscription=e.ChannelSubscription;exports.ConnectionManager=e.ConnectionManager;exports.ConversationManager=e.ConversationManager;exports.EventEmitter=e.EventEmitter;exports.MessageStore=e.MessageStore;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./AikaaraChatClient-kAu65hX-.cjs");class g extends s.EventEmitter{registration=null;pendingEdits=[];constructor(t){super(),this.setupListeners(t)}registerForm(t){this.registration=t;const e=this.pendingEdits.filter(i=>i.entity_type===t.entityType&&String(i.entity_id)===String(t.entityId));if(e.length>0){for(const i of e)t.onFieldUpdate(i.fields),this.emit("edit:applied",{entityType:i.entity_type,entityId:i.entity_id,fields:i.fields});this.pendingEdits=this.pendingEdits.filter(i=>!(i.entity_type===t.entityType&&String(i.entity_id)===String(t.entityId)))}}unregisterForm(t,e){this.registration?.entityType===t&&String(this.registration?.entityId)===String(e)&&(this.registration=null)}get currentForm(){return this.registration}pushFieldUpdates(t,e,i){this.registration&&this.registration.entityType===t&&String(this.registration.entityId)===String(e)?(this.registration.onFieldUpdate(i),this.emit("edit:applied",{entityType:t,entityId:e,fields:i})):(this.pendingEdits.push({action:"edit_entity",entity_type:t,entity_id:e,fields:i}),this.emit("edit:pending",{entityType:t,entityId:e,fields:i}))}async requestSave(){if(!this.registration)return{success:!1,error:"No form registered"};try{return await this.registration.onSave(),this.emit("save:success",{entityType:this.registration.entityType,entityId:this.registration.entityId}),{success:!0}}catch(t){const e=t instanceof Error?t.message:"Save failed";return this.emit("save:error",{entityType:this.registration.entityType,entityId:this.registration.entityId,error:e}),{success:!1,error:e}}}async requestTest(t){if(!this.registration?.onTest)return{success:!1,error:"Current form does not support testing"};try{return await this.registration.onTest(t),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Test failed"}}}setupListeners(t){t.on("action:edit_entity",e=>{this.pushFieldUpdates(e.entity_type,e.entity_id,e.fields)}),t.on("action:save_entity",e=>{this.requestSave()}),t.on("action:test_tool",e=>{this.emit("test:triggered",{toolId:e.tool_id,parameters:e.parameters}),this.requestTest(e.parameters)})}}function m(n){return{async upload(t,e){const i=new FormData,p=n.fieldName??"file";i.append(p,t,t.name);const o=typeof n.extraFields=="function"?n.extraFields(e):n.extraFields;if(o)for(const[u,y]of Object.entries(o))i.append(u,y);i.append("conversationId",e.conversationId),i.append("userId",e.userId),e.projectId&&i.append("projectId",e.projectId);const c=typeof n.headers=="function"?await n.headers():n.headers??{},a=await fetch(n.endpoint,{method:n.method??"POST",body:i,headers:c,credentials:n.credentials});if(!a.ok)throw new Error(`Upload failed: ${a.status} ${a.statusText}`);const d=await a.json().catch(()=>({}));if(n.parseResponse)return n.parseResponse(d,e);const r=d,l=r.url??r.fileUrl??r.publicUrl,h=r.fileName??r.name??t.name;if(!l)throw new Error('Upload response missing "url" / "fileUrl" / "publicUrl"');return{url:l,fileName:h,cloudFileId:typeof r.cloudFileId=="string"?r.cloudFileId:void 0,relativePath:typeof r.path=="string"?r.path:void 0,contentType:typeof r.contentType=="string"?r.contentType:void 0,byteSize:typeof r.byteSize=="number"?r.byteSize:void 0,meta:r}}}}exports.ActionCableClient=s.ActionCableClient;exports.AikaaraChatClient=s.AikaaraChatClient;exports.ApiClient=s.ApiClient;exports.ChannelSubscription=s.ChannelSubscription;exports.ConnectionManager=s.ConnectionManager;exports.ConversationManager=s.ConversationManager;exports.EventEmitter=s.EventEmitter;exports.MessageStore=s.MessageStore;exports.TiledeskTransport=s.TiledeskTransport;exports.extractTiledeskFileEnvelope=s.extractTiledeskFileEnvelope;exports.inferTiledeskRole=s.inferTiledeskRole;exports.isTiledeskSelfEcho=s.isTiledeskSelfEcho;exports.parseTiledeskTemplate=s.parseTiledeskTemplate;exports.FormBridge=g;exports.createFetchUploadAdapter=m;
@@ -22,6 +22,8 @@ export declare interface ActionCableMessage {
22
22
  message?: unknown;
23
23
  }
24
24
 
25
+ export declare type AgentAction = EditEntityAction | SaveEntityAction | TestToolAction | NavigateAction;
26
+
25
27
  export declare interface AgentEvent {
26
28
  type: AgentEventType;
27
29
  [key: string]: unknown;
@@ -31,39 +33,108 @@ export declare type AgentEventType = 'status' | 'error' | 'agent_start' | 'agent
31
33
 
32
34
  export declare class AikaaraChatClient extends EventEmitter<ChatEvents> {
33
35
  private connection;
36
+ private tiledesk;
34
37
  private api;
35
38
  private messageStore;
36
39
  private conversationManager;
37
40
  private subscription;
38
41
  private config;
39
- constructor(config: ChatClientConfig);
42
+ private mode;
43
+ private uploadAdapter;
44
+ private tiledeskUnsubs;
45
+ constructor(config: ChatClientConfig, opts?: {
46
+ uploadAdapter?: UploadAdapter;
47
+ });
48
+ private usesAikaara;
49
+ private usesTiledesk;
50
+ private initTiledeskTransport;
40
51
  connect(): Promise<void>;
41
52
  sendMessage(content: string): Promise<void>;
53
+ /**
54
+ * Upload a file via the configured UploadAdapter (client-side: file goes
55
+ * to the tenant's own backend, never through Aikaara). Then publish the
56
+ * Tiledesk file-message envelope so hooks_controller picks it up.
57
+ */
58
+ sendFile(file: File | Blob, opts?: {
59
+ caption?: string;
60
+ }): Promise<void>;
61
+ /**
62
+ * Trigger Tiledesk's CHAT_INITIATED event — required to kick off a bot flow
63
+ * for newly-created Tiledesk request groups.
64
+ */
65
+ initiateTiledeskChat(extraAttributes?: Record<string, unknown>): void;
66
+ /** Mark a Tiledesk message as read (publishes status=300 update). */
67
+ markTiledeskRead(messageId: string): void;
68
+ setUploadAdapter(adapter: UploadAdapter): void;
42
69
  sendUserEvent(eventKey: string, value?: object, source?: string): Promise<void>;
43
70
  loadHistory(): Promise<Message[]>;
44
71
  get messages(): Message[];
45
72
  get conversationId(): string | null;
46
73
  get isConnected(): boolean;
74
+ /**
75
+ * Update the agent's context with information about the host app's current state.
76
+ * Call this on route changes so the agent knows what page/entity the user is viewing.
77
+ *
78
+ * The context is stored in conversation metadata and interpolated into the system prompt.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * // On route change
83
+ * client.setContext({
84
+ * currentPage: '/products/42',
85
+ * entityType: 'product',
86
+ * entityId: '42',
87
+ * availableRoutes: { products: '/products', orders: '/orders' },
88
+ * });
89
+ * ```
90
+ */
91
+ setContext(context: AppContext): Promise<void>;
47
92
  disconnect(): Promise<void>;
93
+ private handleTiledeskMessage;
94
+ private handleTiledeskStatusUpdate;
95
+ /**
96
+ * Parse structured action results from tool execution output.
97
+ * When the agent calls tools like `edit_current_entity`, `save_current_entity`,
98
+ * `navigate_to`, or `test_tool_by_id`, the result contains an action payload
99
+ * that the SDK emits as a typed event for the host app to handle.
100
+ */
101
+ private parseActionResult;
48
102
  private handleBroadcast;
49
103
  }
50
104
 
51
105
  export declare class ApiClient {
52
106
  private baseUrl;
53
107
  private apiKey?;
108
+ private authToken?;
54
109
  private userToken;
55
- constructor(baseUrl: string, userToken: string, apiKey?: string);
110
+ constructor(baseUrl: string, userToken: string, apiKey?: string, authToken?: string);
56
111
  createConversation(params: {
57
112
  systemPromptId?: number;
58
113
  channel?: string;
59
114
  title?: string;
60
115
  extUid?: string;
61
116
  }): Promise<CreateConversationResponse>;
117
+ updateContext(conversationId: string, context: Record<string, unknown>): Promise<void>;
62
118
  getMessages(conversationId: string): Promise<Message[]>;
63
119
  private mapMessage;
64
120
  private request;
65
121
  }
66
122
 
123
+ export declare interface AppContext {
124
+ /** Current page/route path in the host app (e.g., '/products/42') */
125
+ currentPage: string;
126
+ /** Entity type on the current page (e.g., 'product', 'agent') */
127
+ entityType?: string;
128
+ /** Entity ID on the current page */
129
+ entityId?: string | number;
130
+ /** Project/workspace ID if applicable */
131
+ projectId?: string | number;
132
+ /** Routes the agent can navigate to — map of label → path */
133
+ availableRoutes?: Record<string, string>;
134
+ /** Additional context for the agent (e.g., form field names, entity schema) */
135
+ custom?: Record<string, unknown>;
136
+ }
137
+
67
138
  export declare class ChannelSubscription {
68
139
  readonly identifier: string;
69
140
  private callbacks;
@@ -82,15 +153,35 @@ export declare class ChannelSubscription {
82
153
 
83
154
  export declare interface ChatClientConfig extends ConnectionConfig {
84
155
  apiKey?: string;
156
+ authToken?: string;
85
157
  extUid?: string;
86
158
  conversationId?: string;
87
159
  systemPromptId?: number;
88
- channel?: 'widget' | 'api';
160
+ channel?: 'widget' | 'api' | 'sidekick';
161
+ /**
162
+ * Transport selection.
163
+ * - `aikaara` (default): ActionCable to Aikaara Rails (AI streaming).
164
+ * - `tiledesk`: MQTT direct to a self-hosted Tiledesk + chat21 stack.
165
+ * - `dual`: both — Aikaara cable for AI, Tiledesk MQTT for live-agent + file events.
166
+ */
167
+ transport?: TransportMode;
168
+ /**
169
+ * Tiledesk-side identity. Required when `transport` is `tiledesk` or `dual`.
170
+ * `userId` here is the Tiledesk user `_id` and is also used as the SDK conversation
171
+ * subject — Aikaara conversations bound to this user via ext_uid mapping.
172
+ */
173
+ tiledeskIdentity?: {
174
+ userId: string;
175
+ userName?: string;
176
+ departmentId?: string;
177
+ senderFullname?: string;
178
+ };
89
179
  onMessage?: (message: Message) => void;
90
180
  onStatusChange?: (status: string) => void;
91
181
  onError?: (error: Error) => void;
92
182
  onStreamUpdate?: (delta: string, fullContent: string) => void;
93
183
  onConnectionStateChange?: (state: ConnectionState) => void;
184
+ onTemplateMessage?: (template: TemplateMessageEvent) => void;
94
185
  }
95
186
 
96
187
  export declare interface ChatEvents {
@@ -116,12 +207,26 @@ export declare interface ChatEvents {
116
207
  'typing:stop': void;
117
208
  'error': Error;
118
209
  'status': string;
210
+ 'action:edit_entity': EditEntityAction;
211
+ 'action:save_entity': SaveEntityAction;
212
+ 'action:test_tool': TestToolAction;
213
+ 'action:navigate': NavigateAction;
214
+ 'tool:start': {
215
+ toolName: string;
216
+ args: Record<string, unknown>;
217
+ };
218
+ 'tool:end': {
219
+ toolName: string;
220
+ result: unknown;
221
+ isError: boolean;
222
+ };
119
223
  }
120
224
 
121
225
  export declare interface ConnectionConfig {
122
226
  baseUrl: string;
123
227
  wsUrl?: string;
124
228
  userToken: string;
229
+ tiledesk?: TiledeskTransportConfig;
125
230
  reconnect?: boolean;
126
231
  maxReconnectAttempts?: number;
127
232
  reconnectInterval?: number;
@@ -164,6 +269,15 @@ declare interface CreateConversationResponse {
164
269
  status: string;
165
270
  }
166
271
 
272
+ export declare function createFetchUploadAdapter(config: FetchUploadAdapterConfig): UploadAdapter;
273
+
274
+ export declare interface EditEntityAction {
275
+ action: 'edit_entity';
276
+ entity_type: string;
277
+ entity_id: string | number;
278
+ fields: FieldUpdate[];
279
+ }
280
+
167
281
  export declare class EventEmitter<Events extends Record<string, any>> {
168
282
  private handlers;
169
283
  on<K extends keyof Events & string>(event: K, handler: (data: Events[K]) => void): () => void;
@@ -172,10 +286,153 @@ export declare class EventEmitter<Events extends Record<string, any>> {
172
286
  removeAllListeners(): void;
173
287
  }
174
288
 
289
+ export declare function extractTiledeskFileEnvelope(message: TiledeskMessage): TiledeskFileEnvelope | null;
290
+
291
+ export declare interface FetchUploadAdapterConfig {
292
+ endpoint: string;
293
+ method?: 'POST' | 'PUT';
294
+ fieldName?: string;
295
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
296
+ credentials?: RequestCredentials;
297
+ extraFields?: Record<string, string> | ((ctx: UploadAdapterContext) => Record<string, string>);
298
+ parseResponse?: (raw: unknown, ctx: UploadAdapterContext) => UploadAdapterResult;
299
+ }
300
+
301
+ export declare interface FieldUpdate {
302
+ field: string;
303
+ value: unknown;
304
+ previousValue?: unknown;
305
+ }
306
+
307
+ export declare class FormBridge extends EventEmitter<FormBridgeEvents> {
308
+ private registration;
309
+ private pendingEdits;
310
+ constructor(client: AikaaraChatClient);
311
+ /**
312
+ * Register a form to receive AI-driven edits.
313
+ * Only one form can be registered at a time (the active page).
314
+ */
315
+ registerForm(reg: FormRegistration): void;
316
+ /**
317
+ * Unregister the form (call on unmount).
318
+ */
319
+ unregisterForm(entityType: string, entityId: string | number): void;
320
+ /**
321
+ * Get the current form registration (if any).
322
+ */
323
+ get currentForm(): FormRegistration | null;
324
+ /**
325
+ * Manually push field updates (for custom tool handling).
326
+ */
327
+ pushFieldUpdates(entityType: string, entityId: string | number, fields: FieldUpdate[]): void;
328
+ /**
329
+ * Request the current form to save.
330
+ */
331
+ requestSave(): Promise<{
332
+ success: boolean;
333
+ error?: string;
334
+ }>;
335
+ /**
336
+ * Request the current form to run a test.
337
+ */
338
+ requestTest(params?: Record<string, unknown>): Promise<{
339
+ success: boolean;
340
+ error?: string;
341
+ }>;
342
+ private setupListeners;
343
+ }
344
+
345
+ /**
346
+ * FormBridge — Enables AI agents to visually edit forms in the host application.
347
+ *
348
+ * This bridges the gap between AI tool results and UI form state. When the agent
349
+ * calls tools like `edit_current_entity`, the FormBridge receives the action and
350
+ * pushes field updates to the registered form.
351
+ *
352
+ * ## Usage (any framework)
353
+ *
354
+ * ```typescript
355
+ * import { AikaaraChatClient, FormBridge } from '@aikaara/chat-sdk/headless';
356
+ *
357
+ * const client = new AikaaraChatClient({ baseUrl, userToken, authToken });
358
+ * const bridge = new FormBridge(client);
359
+ *
360
+ * // Register a form (call when your form mounts)
361
+ * bridge.registerForm({
362
+ * entityType: 'product',
363
+ * entityId: 42,
364
+ * onFieldUpdate: (fields) => {
365
+ * for (const { field, value } of fields) {
366
+ * formState[field] = value; // update your form framework
367
+ * }
368
+ * },
369
+ * onSave: async () => await api.saveProduct(42, formState),
370
+ * getCurrentValues: () => ({ ...formState }),
371
+ * });
372
+ *
373
+ * // Unregister when form unmounts
374
+ * bridge.unregisterForm('product', 42);
375
+ * ```
376
+ *
377
+ * ## React hook (provided by dashboard, but easy to replicate)
378
+ *
379
+ * ```tsx
380
+ * function useFormBridge(bridge, { entityType, entityId, onFieldUpdate, onSave }) {
381
+ * useEffect(() => {
382
+ * bridge.registerForm({ entityType, entityId, onFieldUpdate, onSave, getCurrentValues });
383
+ * return () => bridge.unregisterForm(entityType, entityId);
384
+ * }, [entityType, entityId]);
385
+ * }
386
+ * ```
387
+ */
388
+ export declare interface FormBridgeEvents {
389
+ 'edit:applied': {
390
+ entityType: string;
391
+ entityId: string | number;
392
+ fields: FieldUpdate[];
393
+ };
394
+ 'edit:pending': {
395
+ entityType: string;
396
+ entityId: string | number;
397
+ fields: FieldUpdate[];
398
+ };
399
+ 'save:success': {
400
+ entityType: string;
401
+ entityId: string | number;
402
+ };
403
+ 'save:error': {
404
+ entityType: string;
405
+ entityId: string | number;
406
+ error: string;
407
+ };
408
+ 'test:triggered': {
409
+ toolId: number;
410
+ parameters: Record<string, unknown>;
411
+ };
412
+ }
413
+
414
+ export declare interface FormRegistration {
415
+ entityType: string;
416
+ entityId: string | number;
417
+ onFieldUpdate: (fields: FieldUpdate[]) => void;
418
+ onSave: () => Promise<void>;
419
+ onTest?: (params?: Record<string, unknown>) => Promise<void>;
420
+ getCurrentValues: () => Record<string, unknown>;
421
+ }
422
+
423
+ export declare function inferTiledeskRole(message: TiledeskMessage, cfg: TiledeskRoleConfig): TiledeskRole;
424
+
425
+ /**
426
+ * Self-echo detector — Tiledesk fans the user's outgoing publish back
427
+ * as a `clientadded` event on the same connection. UI must dedupe against
428
+ * the optimistic local message rather than rendering twice.
429
+ */
430
+ export declare function isTiledeskSelfEcho(message: TiledeskMessage, userId: string): boolean;
431
+
175
432
  export declare interface Message {
176
433
  id: string;
177
434
  conversationId: string;
178
- role: 'user' | 'assistant' | 'system' | 'tool';
435
+ role: 'user' | 'assistant' | 'system' | 'tool' | 'agent';
179
436
  content: string;
180
437
  toolCalls?: ToolCall[];
181
438
  toolCallResults?: ToolCallResult;
@@ -183,7 +440,19 @@ export declare interface Message {
183
440
  tokensOutput?: number;
184
441
  metadata?: Record<string, unknown>;
185
442
  createdAt: string;
186
- status?: 'sending' | 'sent' | 'streaming' | 'complete' | 'error';
443
+ status?: 'sending' | 'sent' | 'delivered' | 'read' | 'streaming' | 'complete' | 'error';
444
+ externalId?: string;
445
+ template?: {
446
+ contentType?: string;
447
+ templateId?: string;
448
+ payload?: unknown;
449
+ };
450
+ attachments?: Array<{
451
+ fileName: string;
452
+ fileUrl: string;
453
+ cloudFileId?: string;
454
+ contentType?: string;
455
+ }>;
187
456
  }
188
457
 
189
458
  export declare class MessageStore {
@@ -191,6 +460,22 @@ export declare class MessageStore {
191
460
  private optimisticCounter;
192
461
  get messages(): Message[];
193
462
  addOptimistic(role: 'user', content: string, conversationId: string): Message;
463
+ /**
464
+ * Reconcile a remote message against an outstanding optimistic message.
465
+ * Tiledesk fans the user's outgoing publish back as an inbound clientadded —
466
+ * dedupe by exact content + recency window so the optimistic bubble keeps
467
+ * its position and we don't render duplicates.
468
+ */
469
+ reconcileOptimistic(remote: Message, recencyMs?: number): Message | null;
470
+ /**
471
+ * Append a remote-originated message (e.g. from Tiledesk MQTT). If a matching
472
+ * optimistic message exists it is reconciled in place; otherwise appended.
473
+ */
474
+ upsertRemoteMessage(remote: Message): {
475
+ message: Message;
476
+ deduped: boolean;
477
+ };
478
+ updateMessageStatus(externalId: string, status: Message['status']): Message | undefined;
194
479
  confirmOptimistic(tempId: string): void;
195
480
  addStreamingMessage(conversationId: string): Message;
196
481
  updateStreaming(content: string): void;
@@ -205,8 +490,211 @@ export declare class MessageStore {
205
490
  clear(): void;
206
491
  }
207
492
 
493
+ export declare interface NavigateAction {
494
+ navigate_to: string;
495
+ }
496
+
497
+ export declare function parseTiledeskTemplate(message: TiledeskMessage): TiledeskParsedTemplate;
498
+
499
+ export declare interface SaveEntityAction {
500
+ action: 'save_entity';
501
+ }
502
+
208
503
  declare type SubscriptionCallback = (data: unknown) => void;
209
504
 
505
+ declare interface TemplateMessageEvent {
506
+ messageId: string;
507
+ conversationId: string;
508
+ role: 'user' | 'assistant' | 'system' | 'agent';
509
+ contentType?: string;
510
+ templateId?: string;
511
+ payload?: unknown;
512
+ innerMessage?: string;
513
+ raw: unknown;
514
+ }
515
+
516
+ export declare interface TestToolAction {
517
+ action: 'test_tool';
518
+ tool_id: number;
519
+ parameters: Record<string, unknown>;
520
+ }
521
+
522
+ export declare interface TiledeskFileEnvelope {
523
+ fileName?: string;
524
+ fileUrl?: string;
525
+ cloudFileId?: string;
526
+ templateId?: string;
527
+ }
528
+
529
+ export declare interface TiledeskFileMessageInput {
530
+ fileName: string;
531
+ fileUrl: string;
532
+ cloudFileId?: string;
533
+ templateId?: string;
534
+ headerImgSrc?: string;
535
+ type?: 'link' | 'image';
536
+ isDeepLink?: boolean;
537
+ description?: string;
538
+ attributes?: Record<string, unknown>;
539
+ metadata?: Record<string, unknown>;
540
+ }
541
+
542
+ export declare interface TiledeskFileTemplateConfig {
543
+ templateId: string;
544
+ headerImgSrc?: string;
545
+ type?: 'link' | 'image';
546
+ isDeepLink?: boolean;
547
+ }
548
+
549
+ export declare interface TiledeskMessage {
550
+ text?: string;
551
+ type?: string;
552
+ sender?: string;
553
+ senderFullname?: string;
554
+ sender_fullname?: string;
555
+ recipient?: string;
556
+ recipient_fullname?: string;
557
+ channel_type?: string;
558
+ timestamp?: number;
559
+ app_id?: string;
560
+ message_id?: string;
561
+ status?: number;
562
+ attributes?: Record<string, unknown>;
563
+ metadata?: Record<string, unknown>;
564
+ [key: string]: unknown;
565
+ }
566
+
567
+ export declare interface TiledeskMessageContext {
568
+ topic: string;
569
+ conversationId?: string;
570
+ messageId?: string;
571
+ kind: 'clientadded' | 'update' | 'unknown';
572
+ }
573
+
574
+ export declare interface TiledeskMessageDefaults {
575
+ channelType?: string;
576
+ channel?: string;
577
+ requestChannel?: string;
578
+ platform?: string;
579
+ medium?: string;
580
+ departmentId?: string;
581
+ attributes?: Record<string, unknown>;
582
+ }
583
+
584
+ export declare interface TiledeskParsedTemplate {
585
+ contentType?: string;
586
+ templateId?: string;
587
+ payload?: unknown;
588
+ innerMessage?: string;
589
+ raw: TiledeskMessage;
590
+ }
591
+
592
+ export declare type TiledeskRole = 'user' | 'assistant' | 'system' | 'agent';
593
+
594
+ export declare interface TiledeskRoleConfig {
595
+ userId: string;
596
+ systemSenders?: string[];
597
+ botSenderPrefix?: string;
598
+ }
599
+
600
+ export declare interface TiledeskStatusUpdate {
601
+ conversationId: string;
602
+ messageId: string;
603
+ status: number;
604
+ raw: Record<string, unknown>;
605
+ }
606
+
607
+ export declare interface TiledeskTopicTemplates {
608
+ inbound?: string;
609
+ inboundUpdate?: string;
610
+ outbound?: string;
611
+ presence?: string;
612
+ wildcardSubscribe?: string;
613
+ }
614
+
615
+ export declare class TiledeskTransport {
616
+ private client;
617
+ private config;
618
+ private currentToken;
619
+ private clientId;
620
+ private appId;
621
+ private topics;
622
+ private messageHandlers;
623
+ private stateHandlers;
624
+ private statusUpdateHandlers;
625
+ private subscribedTopics;
626
+ private reconnectAttempt;
627
+ private maxReconnectAttempts;
628
+ private reconnectMaxDelayMs;
629
+ private disposed;
630
+ private reconnectTimer;
631
+ private inboundRegex;
632
+ private inboundUpdateRegex;
633
+ constructor(config: TiledeskTransportConfig);
634
+ connect(): Promise<void>;
635
+ subscribeWildcard(): void;
636
+ subscribeToConversation(conversationId: string): void;
637
+ unsubscribeFromConversation(conversationId: string): void;
638
+ publishMessage(conversationId: string, text: string, overrides?: Partial<TiledeskMessage>): void;
639
+ publishFileMessage(conversationId: string, file: TiledeskFileMessageInput): void;
640
+ publishRaw(conversationId: string, message: TiledeskMessage): void;
641
+ /**
642
+ * Send a read receipt for a message. Tiledesk widgets publish
643
+ * `{"status":300}` to apps/{appId}/users/{userId}/messages/{convId}/{msgId}/update.
644
+ */
645
+ publishReadReceipt(conversationId: string, messageId: string, status?: number): void;
646
+ /**
647
+ * Trigger conversation kickoff. Tiledesk bot routing waits for the
648
+ * widget to publish a CHAT_INITIATED event before the bot replies.
649
+ */
650
+ publishChatInitiated(conversationId: string, extraAttributes?: Record<string, unknown>): void;
651
+ onMessage(handler: TransportMessageHandler): () => void;
652
+ onStateChange(handler: TransportStateHandler): () => void;
653
+ onStatusUpdate(handler: TransportStatusUpdateHandler): () => void;
654
+ disconnect(): void;
655
+ get isConnected(): boolean;
656
+ private scheduleReconnect;
657
+ private notifyStateChange;
658
+ private dispatchInbound;
659
+ private buildOutgoingEnvelope;
660
+ private publishEnvelope;
661
+ private renderInboundTopic;
662
+ private renderOutboundTopic;
663
+ private renderPresenceTopic;
664
+ private renderTemplate;
665
+ private buildTopicRegex;
666
+ }
667
+
668
+ export declare interface TiledeskTransportConfig {
669
+ mqttEndpoint: string;
670
+ jwtToken: string;
671
+ userId: string;
672
+ userName?: string;
673
+ projectId: string;
674
+ appId?: string;
675
+ clientId?: string;
676
+ protocolVersion?: 3 | 4 | 5;
677
+ protocolId?: 'MQIsdp' | 'MQTT';
678
+ mqttUsername?: string;
679
+ connectTimeoutMs?: number;
680
+ keepAliveSec?: number;
681
+ maxReconnectAttempts?: number;
682
+ reconnectMaxDelayMs?: number;
683
+ tokenProvider?: () => Promise<string>;
684
+ wildcardSubscribe?: boolean;
685
+ subscribeQos?: 0 | 1 | 2;
686
+ publishQos?: 0 | 1 | 2;
687
+ publishRetain?: boolean;
688
+ enablePresence?: boolean;
689
+ presencePayloadConnected?: Record<string, unknown>;
690
+ presencePayloadDisconnected?: Record<string, unknown>;
691
+ topicTemplates?: TiledeskTopicTemplates;
692
+ messageDefaults?: TiledeskMessageDefaults;
693
+ fileTemplate?: TiledeskFileTemplateConfig;
694
+ recipientFullnameResolver?: (conversationId: string) => string | undefined;
695
+ senderFullname?: string;
696
+ }
697
+
210
698
  export declare interface ToolCall {
211
699
  id: string;
212
700
  type: 'function';
@@ -221,6 +709,35 @@ export declare interface ToolCallResult {
221
709
  content: string;
222
710
  }
223
711
 
712
+ export declare type TransportMessageHandler = (message: TiledeskMessage, ctx: TiledeskMessageContext) => void;
713
+
714
+ declare type TransportMode = 'aikaara' | 'tiledesk' | 'dual';
715
+
716
+ export declare type TransportStateHandler = (connected: boolean) => void;
717
+
718
+ export declare type TransportStatusUpdateHandler = (update: TiledeskStatusUpdate) => void;
719
+
720
+ export declare interface UploadAdapter {
721
+ upload(file: File | Blob, ctx: UploadAdapterContext): Promise<UploadAdapterResult>;
722
+ }
723
+
724
+ export declare interface UploadAdapterContext {
725
+ conversationId: string;
726
+ userId: string;
727
+ projectId?: string;
728
+ appId?: string;
729
+ }
730
+
731
+ export declare interface UploadAdapterResult {
732
+ url: string;
733
+ fileName: string;
734
+ cloudFileId?: string;
735
+ relativePath?: string;
736
+ contentType?: string;
737
+ byteSize?: number;
738
+ meta?: Record<string, unknown>;
739
+ }
740
+
224
741
  export declare interface WidgetConfig extends ChatClientConfig {
225
742
  position?: 'bottom-right' | 'bottom-left';
226
743
  offset?: {
@@ -243,6 +760,7 @@ export declare interface WidgetConfig extends ChatClientConfig {
243
760
  showBubble?: boolean;
244
761
  bubbleText?: string;
245
762
  bubbleIcon?: string;
763
+ uploadAdapter?: UploadAdapter;
246
764
  }
247
765
 
248
766
  export { }