@bpmsoftwaresolutions/ai-engine-client 1.1.56 → 1.1.58

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +564 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bpmsoftwaresolutions/ai-engine-client",
3
- "version": "1.1.56",
3
+ "version": "1.1.58",
4
4
  "description": "Thin npm client for the AI Engine operator and retrieval APIs",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const DEFAULT_TIMEOUT_MS = 30000;
2
- export const AI_ENGINE_CLIENT_VERSION = '1.1.56';
2
+ export const AI_ENGINE_CLIENT_VERSION = '1.1.58';
3
3
  export const GOVERNED_MUTATION_REQUIRED_CAPABILITIES = [
4
4
  'executeVerifiedMutation',
5
5
  'post_mutation_verification',
@@ -409,7 +409,7 @@ export class AIEngineClient {
409
409
  openThread: (request) => this.openCommunicationThread(request),
410
410
  getThread: (threadId) => this.getCommunicationThread(threadId),
411
411
  listInbox: (request) => this.listCommunicationInbox(request),
412
- sendMessage: (request) => this.sendCommunicationMessage(request),
412
+ sendMessage: (request) => this._sendAgentCommsMessage(request),
413
413
  getCommunicationCapabilities: (request) => this.getCommunicationCapabilities(request),
414
414
  getCollaborationCapabilities: (request) => this.getCollaborationCapabilities(request),
415
415
  getDeploymentCapabilities: (request) => this.getDeploymentCapabilities(request),
@@ -440,6 +440,10 @@ export class AIEngineClient {
440
440
  acceptHandoff: (request) => this.acceptCommunicationHandoff(request),
441
441
  whoIsOnline: (request) => this.whoIsOnline(request),
442
442
  findOnlineParticipant: (request) => this.findOnlineParticipant(request),
443
+ listCommunicationChannels: (request) => this.listCommunicationChannels(request),
444
+ listOpenCommunicationChannels: (request) => this.listOpenCommunicationChannels(request),
445
+ getCommunicationChannelStatus: (request) => this.getCommunicationChannelStatus(request),
446
+ getCommunicationChannelParticipants: (request) => this.getCommunicationChannelParticipants(request),
443
447
  getPresenceBoard: (request) => this.getPresenceBoard(request),
444
448
  getChannelPresence: (request) => this.getChannelPresence(request),
445
449
  markParticipantOnline: (request) => this.markParticipantOnline(request),
@@ -447,6 +451,14 @@ export class AIEngineClient {
447
451
  sendToParticipant: (request) => this.sendToParticipant(request),
448
452
  sendToRole: (request) => this.sendToRole(request),
449
453
  getMyInbox: (request) => this.getMyInbox(request),
454
+ verifyMessageSent: (request) => this.verifyMessageSent(request),
455
+ verifyMessageReceived: (request) => this.verifyMessageReceived(request),
456
+ getMessageDeliveryReceipt: (request) => this.getMessageDeliveryReceipt(request),
457
+ startCoordinationPingPong: (request) => this.startCoordinationPingPong(request),
458
+ sendCoordinationPing: (request) => this.sendCoordinationPing(request),
459
+ sendCoordinationPong: (request) => this.sendCoordinationPong(request),
460
+ getCoordinationPingPongStatus: (request) => this.getCoordinationPingPongStatus(request),
461
+ stopCoordinationPingPong: (request) => this.stopCoordinationPingPong(request),
450
462
  connectToTransferChannel: (request) => this.connectToTransferChannel(request),
451
463
  respondToMessageWatch: (request) => this.respondToMessageWatch(request),
452
464
  };
@@ -460,6 +472,10 @@ export class AIEngineClient {
460
472
  requestClosure: (request) => this.requestCollaborationClosure(request),
461
473
  whoIsOnline: (request) => this.whoIsOnline(request),
462
474
  findOnlineParticipant: (request) => this.findOnlineParticipant(request),
475
+ listCommunicationChannels: (request) => this.listCommunicationChannels(request),
476
+ listOpenCommunicationChannels: (request) => this.listOpenCommunicationChannels(request),
477
+ getCommunicationChannelStatus: (request) => this.getCommunicationChannelStatus(request),
478
+ getCommunicationChannelParticipants: (request) => this.getCommunicationChannelParticipants(request),
463
479
  getPresenceBoard: (request) => this.getPresenceBoard(request),
464
480
  getChannelPresence: (request) => this.getChannelPresence(request),
465
481
  markParticipantOnline: (request) => this.markParticipantOnline(request),
@@ -467,6 +483,15 @@ export class AIEngineClient {
467
483
  sendToParticipant: (request) => this.sendToParticipant(request),
468
484
  sendToRole: (request) => this.sendToRole(request),
469
485
  getMyInbox: (request) => this.getMyInbox(request),
486
+ sendMessage: (request) => this._sendAgentCommsMessage(request),
487
+ verifyMessageSent: (request) => this.verifyMessageSent(request),
488
+ verifyMessageReceived: (request) => this.verifyMessageReceived(request),
489
+ getMessageDeliveryReceipt: (request) => this.getMessageDeliveryReceipt(request),
490
+ startCoordinationPingPong: (request) => this.startCoordinationPingPong(request),
491
+ sendCoordinationPing: (request) => this.sendCoordinationPing(request),
492
+ sendCoordinationPong: (request) => this.sendCoordinationPong(request),
493
+ getCoordinationPingPongStatus: (request) => this.getCoordinationPingPongStatus(request),
494
+ stopCoordinationPingPong: (request) => this.stopCoordinationPingPong(request),
470
495
  };
471
496
  }
472
497
 
@@ -657,6 +682,50 @@ export class AIEngineClient {
657
682
  return this._request('/api/agent-communications/deployment-capabilities');
658
683
  }
659
684
 
685
+ async listCommunicationChannels({
686
+ workflowRunId,
687
+ workflow_run_id,
688
+ workTransferPacketId,
689
+ work_transfer_packet_id,
690
+ status,
691
+ channelStatus,
692
+ channel_status,
693
+ } = {}) {
694
+ return this._request('/api/agent-communications/transfer-channels', {
695
+ query: {
696
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
697
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId),
698
+ status: cleanText(status) || cleanText(channel_status) || cleanText(channelStatus),
699
+ },
700
+ });
701
+ }
702
+
703
+ async listOpenCommunicationChannels(request = {}) {
704
+ return this.listCommunicationChannels({ ...request, status: 'open' });
705
+ }
706
+
707
+ async getCommunicationChannelStatus({
708
+ transferChannelId,
709
+ transfer_channel_id,
710
+ channelId,
711
+ channel_id,
712
+ } = {}) {
713
+ const normalizedTransferChannelId = cleanText(transfer_channel_id) || cleanText(transferChannelId) || cleanText(channel_id) || cleanText(channelId);
714
+ if (!normalizedTransferChannelId) throw new Error('transferChannelId is required.');
715
+ return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/status`);
716
+ }
717
+
718
+ async getCommunicationChannelParticipants({
719
+ transferChannelId,
720
+ transfer_channel_id,
721
+ channelId,
722
+ channel_id,
723
+ } = {}) {
724
+ const normalizedTransferChannelId = cleanText(transfer_channel_id) || cleanText(transferChannelId) || cleanText(channel_id) || cleanText(channelId);
725
+ if (!normalizedTransferChannelId) throw new Error('transferChannelId is required.');
726
+ return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/participants`);
727
+ }
728
+
660
729
  async getPresenceBoard({
661
730
  workflowRunId,
662
731
  workflow_run_id,
@@ -712,6 +781,108 @@ export class AIEngineClient {
712
781
  });
713
782
  }
714
783
 
784
+ async _resolveCoordinationChannelContext({
785
+ transferChannelId,
786
+ transfer_channel_id,
787
+ channelId,
788
+ channel_id,
789
+ workTransferPacketId,
790
+ work_transfer_packet_id,
791
+ packetId,
792
+ packet_id,
793
+ workflowRunId,
794
+ workflow_run_id,
795
+ participantRole,
796
+ participant_role,
797
+ role,
798
+ } = {}) {
799
+ const normalizedTransferChannelId = cleanText(transfer_channel_id) || cleanText(transferChannelId) || cleanText(channel_id) || cleanText(channelId);
800
+ const normalizedParticipantRole = cleanText(participant_role) || cleanText(participantRole) || cleanText(role);
801
+ const normalizedWorkflowRunId = cleanText(workflow_run_id) || cleanText(workflowRunId);
802
+ if (normalizedTransferChannelId) {
803
+ let packetId = cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId);
804
+ if (!packetId) {
805
+ try {
806
+ const status = await this.getCommunicationChannelStatus({ transferChannelId: normalizedTransferChannelId });
807
+ packetId = cleanText(status?.packet_id || status?.packetId || status?.work_transfer_packet_id);
808
+ } catch (error) {
809
+ void error;
810
+ }
811
+ }
812
+ return {
813
+ channel_id: normalizedTransferChannelId,
814
+ packet_id: packetId,
815
+ workflow_run_id: normalizedWorkflowRunId,
816
+ stop_reason: null,
817
+ };
818
+ }
819
+ const presence = await this.whoIsOnline({
820
+ workflowRunId: normalizedWorkflowRunId,
821
+ participantRole: normalizedParticipantRole,
822
+ includeStale: true,
823
+ });
824
+ const directoryRows = Array.isArray(presence?.presence)
825
+ ? presence.presence.filter((row) => row && typeof row === 'object')
826
+ : Array.isArray(presence?.online_participants)
827
+ ? presence.online_participants.filter((row) => row && typeof row === 'object')
828
+ : Array.isArray(presence?.participants)
829
+ ? presence.participants.filter((row) => row && typeof row === 'object')
830
+ : [];
831
+ const filteredRows = normalizedParticipantRole
832
+ ? directoryRows.filter((row) => cleanText(row.participant_role) === normalizedParticipantRole)
833
+ : [];
834
+ const onlineRows = filteredRows.filter((row) => Boolean(row.is_online));
835
+ const chooseRows = onlineRows.length > 0 ? onlineRows : filteredRows;
836
+ if (chooseRows.length === 1) {
837
+ return {
838
+ channel_id: cleanText(chooseRows[0].transfer_channel_id),
839
+ packet_id: cleanText(chooseRows[0].work_transfer_packet_id) || cleanText(chooseRows[0].packet_id),
840
+ workflow_run_id: cleanText(chooseRows[0].workflow_run_id) || normalizedWorkflowRunId,
841
+ stop_reason: null,
842
+ };
843
+ }
844
+ const openChannels = await this.listOpenCommunicationChannels({ workflowRunId: normalizedWorkflowRunId });
845
+ const openChannelRows = Array.isArray(openChannels) ? openChannels.filter((row) => row && typeof row === 'object') : [];
846
+ if (openChannelRows.length === 1) {
847
+ return {
848
+ channel_id: cleanText(openChannelRows[0].channel_id || openChannelRows[0].transfer_channel_id),
849
+ packet_id: cleanText(openChannelRows[0].packet_id || openChannelRows[0].work_transfer_packet_id),
850
+ workflow_run_id: cleanText(openChannelRows[0].workflow_run_id) || normalizedWorkflowRunId,
851
+ stop_reason: null,
852
+ };
853
+ }
854
+ if (openChannelRows.length > 1) {
855
+ return {
856
+ channel_id: null,
857
+ packet_id: null,
858
+ workflow_run_id: normalizedWorkflowRunId,
859
+ stop_reason: {
860
+ code: 'multiple_open_channels_need_disambiguation',
861
+ message: 'Multiple open channels matched the requested coordination context.',
862
+ details: {
863
+ workflow_run_id: normalizedWorkflowRunId,
864
+ participant_role: normalizedParticipantRole,
865
+ candidate_count: openChannelRows.length,
866
+ candidate_channel_ids: openChannelRows.map((row) => cleanText(row.channel_id || row.transfer_channel_id)).filter(Boolean),
867
+ },
868
+ },
869
+ };
870
+ }
871
+ return {
872
+ channel_id: null,
873
+ packet_id: null,
874
+ workflow_run_id: normalizedWorkflowRunId,
875
+ stop_reason: {
876
+ code: 'active_channel_not_found',
877
+ message: 'Active transfer channel not found.',
878
+ details: {
879
+ workflow_run_id: normalizedWorkflowRunId,
880
+ participant_role: normalizedParticipantRole,
881
+ },
882
+ },
883
+ };
884
+ }
885
+
715
886
  async markParticipantOnline({
716
887
  transferChannelId,
717
888
  transfer_channel_id,
@@ -743,7 +914,7 @@ export class AIEngineClient {
743
914
  method: 'POST',
744
915
  body: {
745
916
  transfer_channel_id: normalizedTransferChannelId,
746
- work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId),
917
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId) || resolved.packet_id,
747
918
  workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
748
919
  participant_role: cleanText(participant_role) || cleanText(participantRole),
749
920
  current_phase: cleanText(current_phase) || cleanText(currentPhase),
@@ -789,7 +960,7 @@ export class AIEngineClient {
789
960
  method: 'POST',
790
961
  body: {
791
962
  transfer_channel_id: normalizedTransferChannelId,
792
- work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId),
963
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId) || resolved.packet_id,
793
964
  workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
794
965
  participant_role: cleanText(participant_role) || cleanText(participantRole),
795
966
  current_phase: cleanText(current_phase) || cleanText(currentPhase),
@@ -908,7 +1079,7 @@ export class AIEngineClient {
908
1079
  return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/connect`, {
909
1080
  method: 'POST',
910
1081
  body: {
911
- work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId),
1082
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId) || resolved.packet_id,
912
1083
  workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
913
1084
  participant_role: cleanText(participant_role) || cleanText(participantRole),
914
1085
  expected_peer_role: cleanText(expected_peer_role) || cleanText(expectedPeerRole),
@@ -1617,6 +1788,382 @@ export class AIEngineClient {
1617
1788
  });
1618
1789
  }
1619
1790
 
1791
+ async startCoordinationPingPong({
1792
+ transferChannelId,
1793
+ transfer_channel_id,
1794
+ channelId,
1795
+ channel_id,
1796
+ participantRole,
1797
+ participant_role,
1798
+ role,
1799
+ expectedPeerRole,
1800
+ expected_peer_role,
1801
+ expectedMessageKind,
1802
+ expected_message_kind,
1803
+ workTransferPacketId,
1804
+ work_transfer_packet_id,
1805
+ packetId,
1806
+ packet_id,
1807
+ workflowRunId,
1808
+ workflow_run_id,
1809
+ proposalId,
1810
+ proposal_id,
1811
+ mode,
1812
+ bodyMarkdown,
1813
+ body_markdown,
1814
+ payload = {},
1815
+ scope = {},
1816
+ metadata = {},
1817
+ staleAfterSeconds,
1818
+ stale_after_seconds,
1819
+ } = {}) {
1820
+ const resolved = await this._resolveCoordinationChannelContext({
1821
+ transferChannelId,
1822
+ transfer_channel_id,
1823
+ channelId,
1824
+ channel_id,
1825
+ workTransferPacketId,
1826
+ work_transfer_packet_id,
1827
+ packetId,
1828
+ packet_id,
1829
+ workflowRunId,
1830
+ workflow_run_id,
1831
+ participantRole,
1832
+ participant_role,
1833
+ role,
1834
+ });
1835
+ if (resolved.stop_reason) {
1836
+ return {
1837
+ started: false,
1838
+ sent: false,
1839
+ stop_reason: resolved.stop_reason,
1840
+ };
1841
+ }
1842
+ return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(resolved.channel_id)}/coordination/ping-pong/start`, {
1843
+ method: 'POST',
1844
+ body: {
1845
+ transfer_channel_id: resolved.channel_id,
1846
+ participant_role: cleanText(participant_role) || cleanText(participantRole) || cleanText(role),
1847
+ expected_peer_role: cleanText(expected_peer_role) || cleanText(expectedPeerRole),
1848
+ expected_message_kind: cleanText(expected_message_kind) || cleanText(expectedMessageKind),
1849
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId),
1850
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId) || resolved.workflow_run_id,
1851
+ proposal_id: cleanText(proposal_id) || cleanText(proposalId),
1852
+ mode: cleanText(mode) || 'communication_participant',
1853
+ body_markdown: cleanText(body_markdown) || cleanText(bodyMarkdown),
1854
+ payload: isPlainObject(payload) ? payload : {},
1855
+ scope: isPlainObject(scope) ? scope : {},
1856
+ metadata: isPlainObject(metadata) ? metadata : {},
1857
+ stale_after_seconds: stale_after_seconds ?? staleAfterSeconds,
1858
+ },
1859
+ });
1860
+ }
1861
+
1862
+ async sendCoordinationPing({
1863
+ transferChannelId,
1864
+ transfer_channel_id,
1865
+ channelId,
1866
+ channel_id,
1867
+ participantRole,
1868
+ participant_role,
1869
+ role,
1870
+ expectedPeerRole,
1871
+ expected_peer_role,
1872
+ bodyMarkdown,
1873
+ body_markdown,
1874
+ payload = {},
1875
+ scope = {},
1876
+ metadata = {},
1877
+ workflowRunId,
1878
+ workflow_run_id,
1879
+ workTransferPacketId,
1880
+ work_transfer_packet_id,
1881
+ packetId,
1882
+ packet_id,
1883
+ proposalId,
1884
+ proposal_id,
1885
+ expectedMessageKind,
1886
+ expected_message_kind,
1887
+ } = {}) {
1888
+ const resolved = await this._resolveCoordinationChannelContext({
1889
+ transferChannelId,
1890
+ transfer_channel_id,
1891
+ channelId,
1892
+ channel_id,
1893
+ workTransferPacketId,
1894
+ work_transfer_packet_id,
1895
+ packetId,
1896
+ packet_id,
1897
+ workflowRunId,
1898
+ workflow_run_id,
1899
+ participantRole,
1900
+ participant_role,
1901
+ role,
1902
+ });
1903
+ if (resolved.stop_reason) {
1904
+ return {
1905
+ sent: false,
1906
+ stop_reason: resolved.stop_reason,
1907
+ };
1908
+ }
1909
+ return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(resolved.channel_id)}/coordination/ping-pong/ping`, {
1910
+ method: 'POST',
1911
+ body: {
1912
+ transfer_channel_id: resolved.channel_id,
1913
+ participant_role: cleanText(participant_role) || cleanText(participantRole) || cleanText(role),
1914
+ expected_peer_role: cleanText(expected_peer_role) || cleanText(expectedPeerRole),
1915
+ body_markdown: cleanText(body_markdown) || cleanText(bodyMarkdown),
1916
+ payload: isPlainObject(payload) ? payload : {},
1917
+ scope: isPlainObject(scope) ? scope : {},
1918
+ metadata: isPlainObject(metadata) ? metadata : {},
1919
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId) || resolved.workflow_run_id,
1920
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId),
1921
+ proposal_id: cleanText(proposal_id) || cleanText(proposalId),
1922
+ expected_message_kind: cleanText(expected_message_kind) || cleanText(expectedMessageKind),
1923
+ },
1924
+ });
1925
+ }
1926
+
1927
+ async sendCoordinationPong({
1928
+ transferChannelId,
1929
+ transfer_channel_id,
1930
+ channelId,
1931
+ channel_id,
1932
+ participantRole,
1933
+ participant_role,
1934
+ role,
1935
+ expectedPeerRole,
1936
+ expected_peer_role,
1937
+ bodyMarkdown,
1938
+ body_markdown,
1939
+ payload = {},
1940
+ scope = {},
1941
+ metadata = {},
1942
+ workflowRunId,
1943
+ workflow_run_id,
1944
+ workTransferPacketId,
1945
+ work_transfer_packet_id,
1946
+ packetId,
1947
+ packet_id,
1948
+ proposalId,
1949
+ proposal_id,
1950
+ expectedMessageKind,
1951
+ expected_message_kind,
1952
+ } = {}) {
1953
+ const resolved = await this._resolveCoordinationChannelContext({
1954
+ transferChannelId,
1955
+ transfer_channel_id,
1956
+ channelId,
1957
+ channel_id,
1958
+ workTransferPacketId,
1959
+ work_transfer_packet_id,
1960
+ packetId,
1961
+ packet_id,
1962
+ workflowRunId,
1963
+ workflow_run_id,
1964
+ participantRole,
1965
+ participant_role,
1966
+ role,
1967
+ });
1968
+ if (resolved.stop_reason) {
1969
+ return {
1970
+ sent: false,
1971
+ stop_reason: resolved.stop_reason,
1972
+ };
1973
+ }
1974
+ return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(resolved.channel_id)}/coordination/ping-pong/pong`, {
1975
+ method: 'POST',
1976
+ body: {
1977
+ transfer_channel_id: resolved.channel_id,
1978
+ participant_role: cleanText(participant_role) || cleanText(participantRole) || cleanText(role),
1979
+ expected_peer_role: cleanText(expected_peer_role) || cleanText(expectedPeerRole),
1980
+ body_markdown: cleanText(body_markdown) || cleanText(bodyMarkdown),
1981
+ payload: isPlainObject(payload) ? payload : {},
1982
+ scope: isPlainObject(scope) ? scope : {},
1983
+ metadata: isPlainObject(metadata) ? metadata : {},
1984
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId) || resolved.workflow_run_id,
1985
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId),
1986
+ proposal_id: cleanText(proposal_id) || cleanText(proposalId),
1987
+ expected_message_kind: cleanText(expected_message_kind) || cleanText(expectedMessageKind),
1988
+ },
1989
+ });
1990
+ }
1991
+
1992
+ async getCoordinationPingPongStatus({
1993
+ transferChannelId,
1994
+ transfer_channel_id,
1995
+ channelId,
1996
+ channel_id,
1997
+ workTransferPacketId,
1998
+ work_transfer_packet_id,
1999
+ packetId,
2000
+ packet_id,
2001
+ participantRole,
2002
+ participant_role,
2003
+ role,
2004
+ workflowRunId,
2005
+ workflow_run_id,
2006
+ } = {}) {
2007
+ const resolved = await this._resolveCoordinationChannelContext({
2008
+ transferChannelId,
2009
+ transfer_channel_id,
2010
+ channelId,
2011
+ channel_id,
2012
+ workTransferPacketId,
2013
+ work_transfer_packet_id,
2014
+ packetId,
2015
+ packet_id,
2016
+ workflowRunId,
2017
+ workflow_run_id,
2018
+ participantRole,
2019
+ participant_role,
2020
+ role,
2021
+ });
2022
+ if (resolved.stop_reason) {
2023
+ return {
2024
+ verified: false,
2025
+ stop_reason: resolved.stop_reason,
2026
+ };
2027
+ }
2028
+ return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(resolved.channel_id)}/coordination/ping-pong/status`, {
2029
+ query: {
2030
+ participant_role: cleanText(participant_role) || cleanText(participantRole) || cleanText(role),
2031
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId) || resolved.workflow_run_id,
2032
+ },
2033
+ });
2034
+ }
2035
+
2036
+ async stopCoordinationPingPong({
2037
+ transferChannelId,
2038
+ transfer_channel_id,
2039
+ channelId,
2040
+ channel_id,
2041
+ workTransferPacketId,
2042
+ work_transfer_packet_id,
2043
+ packetId,
2044
+ packet_id,
2045
+ participantRole,
2046
+ participant_role,
2047
+ role,
2048
+ workflowRunId,
2049
+ workflow_run_id,
2050
+ metadata = {},
2051
+ } = {}) {
2052
+ const resolved = await this._resolveCoordinationChannelContext({
2053
+ transferChannelId,
2054
+ transfer_channel_id,
2055
+ channelId,
2056
+ channel_id,
2057
+ workTransferPacketId,
2058
+ work_transfer_packet_id,
2059
+ packetId,
2060
+ packet_id,
2061
+ workflowRunId,
2062
+ workflow_run_id,
2063
+ participantRole,
2064
+ participant_role,
2065
+ role,
2066
+ });
2067
+ if (resolved.stop_reason) {
2068
+ return {
2069
+ stopped: false,
2070
+ stop_reason: resolved.stop_reason,
2071
+ };
2072
+ }
2073
+ return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(resolved.channel_id)}/coordination/ping-pong/stop`, {
2074
+ method: 'POST',
2075
+ body: {
2076
+ transfer_channel_id: resolved.channel_id,
2077
+ participant_role: cleanText(participant_role) || cleanText(participantRole) || cleanText(role),
2078
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId) || resolved.workflow_run_id,
2079
+ metadata: isPlainObject(metadata) ? metadata : {},
2080
+ },
2081
+ });
2082
+ }
2083
+
2084
+ async verifyMessageSent({ messageId, message_id } = {}) {
2085
+ const normalizedMessageId = cleanText(message_id) || cleanText(messageId);
2086
+ if (!normalizedMessageId) throw new Error('message_id is required.');
2087
+ return this._request(`/api/agent-communications/messages/${encodeURIComponent(normalizedMessageId)}/verify-sent`, {
2088
+ method: 'POST',
2089
+ body: { message_id: normalizedMessageId },
2090
+ });
2091
+ }
2092
+
2093
+ async verifyMessageReceived({
2094
+ messageId,
2095
+ message_id,
2096
+ recipientAgentSessionId,
2097
+ recipient_agent_session_id,
2098
+ recipientRole,
2099
+ recipient_role,
2100
+ role,
2101
+ participantId,
2102
+ participant_id,
2103
+ } = {}) {
2104
+ const normalizedMessageId = cleanText(message_id) || cleanText(messageId);
2105
+ if (!normalizedMessageId) throw new Error('message_id is required.');
2106
+ return this._request(`/api/agent-communications/messages/${encodeURIComponent(normalizedMessageId)}/verify-received`, {
2107
+ method: 'POST',
2108
+ body: {
2109
+ message_id: normalizedMessageId,
2110
+ recipient_agent_session_id: cleanText(recipient_agent_session_id) || cleanText(recipientAgentSessionId),
2111
+ recipient_role: cleanText(recipient_role) || cleanText(recipientRole) || cleanText(role),
2112
+ participant_id: cleanText(participant_id) || cleanText(participantId),
2113
+ },
2114
+ });
2115
+ }
2116
+
2117
+ async getMessageDeliveryReceipt({ messageId, message_id } = {}) {
2118
+ const normalizedMessageId = cleanText(message_id) || cleanText(messageId);
2119
+ if (!normalizedMessageId) throw new Error('message_id is required.');
2120
+ return this._request(`/api/agent-communications/messages/${encodeURIComponent(normalizedMessageId)}/delivery-receipt`, {
2121
+ method: 'GET',
2122
+ });
2123
+ }
2124
+
2125
+ async _sendAgentCommsMessage(request = {}) {
2126
+ const hasThreadContext = Boolean(
2127
+ cleanText(request.communication_thread_id)
2128
+ || cleanText(request.communicationThreadId)
2129
+ || cleanText(request.thread_id)
2130
+ || cleanText(request.threadId)
2131
+ || cleanText(request.recipient_role_key)
2132
+ || cleanText(request.recipientRoleKey)
2133
+ );
2134
+ const hasTransferChannelContext = Boolean(
2135
+ cleanText(request.transfer_channel_id)
2136
+ || cleanText(request.transferChannelId)
2137
+ || cleanText(request.channel_id)
2138
+ || cleanText(request.channelId)
2139
+ || cleanText(request.sender_role)
2140
+ || cleanText(request.senderRole)
2141
+ || cleanText(request.recipient_role)
2142
+ || cleanText(request.recipientRole)
2143
+ || cleanText(request.role)
2144
+ || cleanText(request.participant_role)
2145
+ || cleanText(request.participantRole)
2146
+ || cleanText(request.participant_id)
2147
+ || cleanText(request.participantId)
2148
+ || cleanText(request.recipient_participant_id)
2149
+ || cleanText(request.recipientParticipantId)
2150
+ );
2151
+ if (hasTransferChannelContext && !hasThreadContext) {
2152
+ if (
2153
+ cleanText(request.participant_id)
2154
+ || cleanText(request.participantId)
2155
+ || cleanText(request.recipient_participant_id)
2156
+ || cleanText(request.recipientParticipantId)
2157
+ || cleanText(request.recipient_agent_session_id)
2158
+ || cleanText(request.recipientAgentSessionId)
2159
+ ) {
2160
+ return this.sendToParticipant(request);
2161
+ }
2162
+ return this.sendToRole(request);
2163
+ }
2164
+ return this.sendCommunicationMessage(request);
2165
+ }
2166
+
1620
2167
  async sendCommunicationMessage({
1621
2168
  communicationThreadId,
1622
2169
  communication_thread_id,
@@ -4812,17 +5359,27 @@ export class AIEngineClient {
4812
5359
  });
4813
5360
  const contentType = response.headers.get('content-type') || '';
4814
5361
  const contentDisposition = response.headers.get('content-disposition') || '';
5362
+ const readResponseText = async () => {
5363
+ if (typeof response.text === 'function') {
5364
+ return response.text();
5365
+ }
5366
+ if (typeof response.json === 'function') {
5367
+ const payload = await response.json();
5368
+ return typeof payload === 'string' ? payload : JSON.stringify(payload);
5369
+ }
5370
+ return '';
5371
+ };
4815
5372
  if (!response.ok) {
4816
5373
  const payload = contentType.includes('application/json')
4817
5374
  ? await response.json()
4818
- : { message: await response.text() };
5375
+ : { message: await readResponseText() };
4819
5376
  const error = new Error(payload?.message || payload?.error || `Request failed with status ${response.status}.`);
4820
5377
  error.status = response.status;
4821
5378
  error.payload = payload;
4822
5379
  throw error;
4823
5380
  }
4824
5381
  return {
4825
- text: await response.text(),
5382
+ text: await readResponseText(),
4826
5383
  contentType,
4827
5384
  fileName: parseContentDispositionFilename(contentDisposition),
4828
5385
  headers: Object.fromEntries(response.headers.entries()),