@aikaara/chat-sdk 0.2.0 → 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.
@@ -33,14 +33,39 @@ export declare type AgentEventType = 'status' | 'error' | 'agent_start' | 'agent
33
33
 
34
34
  export declare class AikaaraChatClient extends EventEmitter<ChatEvents> {
35
35
  private connection;
36
+ private tiledesk;
36
37
  private api;
37
38
  private messageStore;
38
39
  private conversationManager;
39
40
  private subscription;
40
41
  private config;
41
- 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;
42
51
  connect(): Promise<void>;
43
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;
44
69
  sendUserEvent(eventKey: string, value?: object, source?: string): Promise<void>;
45
70
  loadHistory(): Promise<Message[]>;
46
71
  get messages(): Message[];
@@ -65,6 +90,8 @@ export declare class AikaaraChatClient extends EventEmitter<ChatEvents> {
65
90
  */
66
91
  setContext(context: AppContext): Promise<void>;
67
92
  disconnect(): Promise<void>;
93
+ private handleTiledeskMessage;
94
+ private handleTiledeskStatusUpdate;
68
95
  /**
69
96
  * Parse structured action results from tool execution output.
70
97
  * When the agent calls tools like `edit_current_entity`, `save_current_entity`,
@@ -131,11 +158,30 @@ export declare interface ChatClientConfig extends ConnectionConfig {
131
158
  conversationId?: string;
132
159
  systemPromptId?: number;
133
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
+ };
134
179
  onMessage?: (message: Message) => void;
135
180
  onStatusChange?: (status: string) => void;
136
181
  onError?: (error: Error) => void;
137
182
  onStreamUpdate?: (delta: string, fullContent: string) => void;
138
183
  onConnectionStateChange?: (state: ConnectionState) => void;
184
+ onTemplateMessage?: (template: TemplateMessageEvent) => void;
139
185
  }
140
186
 
141
187
  export declare interface ChatEvents {
@@ -223,6 +269,8 @@ declare interface CreateConversationResponse {
223
269
  status: string;
224
270
  }
225
271
 
272
+ export declare function createFetchUploadAdapter(config: FetchUploadAdapterConfig): UploadAdapter;
273
+
226
274
  export declare interface EditEntityAction {
227
275
  action: 'edit_entity';
228
276
  entity_type: string;
@@ -238,6 +286,18 @@ export declare class EventEmitter<Events extends Record<string, any>> {
238
286
  removeAllListeners(): void;
239
287
  }
240
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
+
241
301
  export declare interface FieldUpdate {
242
302
  field: string;
243
303
  value: unknown;
@@ -360,10 +420,19 @@ export declare interface FormRegistration {
360
420
  getCurrentValues: () => Record<string, unknown>;
361
421
  }
362
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
+
363
432
  export declare interface Message {
364
433
  id: string;
365
434
  conversationId: string;
366
- role: 'user' | 'assistant' | 'system' | 'tool';
435
+ role: 'user' | 'assistant' | 'system' | 'tool' | 'agent';
367
436
  content: string;
368
437
  toolCalls?: ToolCall[];
369
438
  toolCallResults?: ToolCallResult;
@@ -371,7 +440,19 @@ export declare interface Message {
371
440
  tokensOutput?: number;
372
441
  metadata?: Record<string, unknown>;
373
442
  createdAt: string;
374
- 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
+ }>;
375
456
  }
376
457
 
377
458
  export declare class MessageStore {
@@ -379,6 +460,22 @@ export declare class MessageStore {
379
460
  private optimisticCounter;
380
461
  get messages(): Message[];
381
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;
382
479
  confirmOptimistic(tempId: string): void;
383
480
  addStreamingMessage(conversationId: string): Message;
384
481
  updateStreaming(content: string): void;
@@ -397,50 +494,175 @@ export declare interface NavigateAction {
397
494
  navigate_to: string;
398
495
  }
399
496
 
497
+ export declare function parseTiledeskTemplate(message: TiledeskMessage): TiledeskParsedTemplate;
498
+
400
499
  export declare interface SaveEntityAction {
401
500
  action: 'save_entity';
402
501
  }
403
502
 
404
503
  declare type SubscriptionCallback = (data: unknown) => void;
405
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
+
406
516
  export declare interface TestToolAction {
407
517
  action: 'test_tool';
408
518
  tool_id: number;
409
519
  parameters: Record<string, unknown>;
410
520
  }
411
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
+
412
549
  export declare interface TiledeskMessage {
413
550
  text?: string;
414
551
  type?: string;
415
552
  sender?: string;
416
553
  senderFullname?: string;
554
+ sender_fullname?: string;
417
555
  recipient?: string;
556
+ recipient_fullname?: string;
557
+ channel_type?: string;
418
558
  timestamp?: number;
559
+ app_id?: string;
560
+ message_id?: string;
561
+ status?: number;
419
562
  attributes?: Record<string, unknown>;
420
563
  metadata?: Record<string, unknown>;
421
564
  [key: string]: unknown;
422
565
  }
423
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
+
424
615
  export declare class TiledeskTransport {
425
616
  private client;
426
617
  private config;
618
+ private currentToken;
619
+ private clientId;
620
+ private appId;
621
+ private topics;
427
622
  private messageHandlers;
428
623
  private stateHandlers;
624
+ private statusUpdateHandlers;
429
625
  private subscribedTopics;
430
626
  private reconnectAttempt;
431
627
  private maxReconnectAttempts;
628
+ private reconnectMaxDelayMs;
432
629
  private disposed;
630
+ private reconnectTimer;
631
+ private inboundRegex;
632
+ private inboundUpdateRegex;
433
633
  constructor(config: TiledeskTransportConfig);
434
634
  connect(): Promise<void>;
635
+ subscribeWildcard(): void;
435
636
  subscribeToConversation(conversationId: string): void;
436
637
  unsubscribeFromConversation(conversationId: string): void;
437
- publishMessage(conversationId: string, text: 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;
438
651
  onMessage(handler: TransportMessageHandler): () => void;
439
652
  onStateChange(handler: TransportStateHandler): () => void;
653
+ onStatusUpdate(handler: TransportStatusUpdateHandler): () => void;
440
654
  disconnect(): void;
441
655
  get isConnected(): boolean;
442
656
  private scheduleReconnect;
443
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;
444
666
  }
445
667
 
446
668
  export declare interface TiledeskTransportConfig {
@@ -449,6 +671,28 @@ export declare interface TiledeskTransportConfig {
449
671
  userId: string;
450
672
  userName?: string;
451
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;
452
696
  }
453
697
 
454
698
  export declare interface ToolCall {
@@ -465,10 +709,35 @@ export declare interface ToolCallResult {
465
709
  content: string;
466
710
  }
467
711
 
468
- export declare type TransportMessageHandler = (message: TiledeskMessage) => void;
712
+ export declare type TransportMessageHandler = (message: TiledeskMessage, ctx: TiledeskMessageContext) => void;
713
+
714
+ declare type TransportMode = 'aikaara' | 'tiledesk' | 'dual';
469
715
 
470
716
  export declare type TransportStateHandler = (connected: boolean) => void;
471
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
+
472
741
  export declare interface WidgetConfig extends ChatClientConfig {
473
742
  position?: 'bottom-right' | 'bottom-left';
474
743
  offset?: {
@@ -491,6 +760,7 @@ export declare interface WidgetConfig extends ChatClientConfig {
491
760
  showBubble?: boolean;
492
761
  bubbleText?: string;
493
762
  bubbleIcon?: string;
763
+ uploadAdapter?: UploadAdapter;
494
764
  }
495
765
 
496
766
  export { }