@bpmsoftwaresolutions/ai-engine-client 1.1.57 → 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 +421 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bpmsoftwaresolutions/ai-engine-client",
3
- "version": "1.1.57",
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.57';
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',
@@ -454,6 +454,11 @@ export class AIEngineClient {
454
454
  verifyMessageSent: (request) => this.verifyMessageSent(request),
455
455
  verifyMessageReceived: (request) => this.verifyMessageReceived(request),
456
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),
457
462
  connectToTransferChannel: (request) => this.connectToTransferChannel(request),
458
463
  respondToMessageWatch: (request) => this.respondToMessageWatch(request),
459
464
  };
@@ -482,6 +487,11 @@ export class AIEngineClient {
482
487
  verifyMessageSent: (request) => this.verifyMessageSent(request),
483
488
  verifyMessageReceived: (request) => this.verifyMessageReceived(request),
484
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),
485
495
  };
486
496
  }
487
497
 
@@ -771,6 +781,108 @@ export class AIEngineClient {
771
781
  });
772
782
  }
773
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
+
774
886
  async markParticipantOnline({
775
887
  transferChannelId,
776
888
  transfer_channel_id,
@@ -802,7 +914,7 @@ export class AIEngineClient {
802
914
  method: 'POST',
803
915
  body: {
804
916
  transfer_channel_id: normalizedTransferChannelId,
805
- 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,
806
918
  workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
807
919
  participant_role: cleanText(participant_role) || cleanText(participantRole),
808
920
  current_phase: cleanText(current_phase) || cleanText(currentPhase),
@@ -848,7 +960,7 @@ export class AIEngineClient {
848
960
  method: 'POST',
849
961
  body: {
850
962
  transfer_channel_id: normalizedTransferChannelId,
851
- 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,
852
964
  workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
853
965
  participant_role: cleanText(participant_role) || cleanText(participantRole),
854
966
  current_phase: cleanText(current_phase) || cleanText(currentPhase),
@@ -967,7 +1079,7 @@ export class AIEngineClient {
967
1079
  return this._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/connect`, {
968
1080
  method: 'POST',
969
1081
  body: {
970
- 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,
971
1083
  workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
972
1084
  participant_role: cleanText(participant_role) || cleanText(participantRole),
973
1085
  expected_peer_role: cleanText(expected_peer_role) || cleanText(expectedPeerRole),
@@ -1676,6 +1788,299 @@ export class AIEngineClient {
1676
1788
  });
1677
1789
  }
1678
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
+
1679
2084
  async verifyMessageSent({ messageId, message_id } = {}) {
1680
2085
  const normalizedMessageId = cleanText(message_id) || cleanText(messageId);
1681
2086
  if (!normalizedMessageId) throw new Error('message_id is required.');
@@ -4954,17 +5359,27 @@ export class AIEngineClient {
4954
5359
  });
4955
5360
  const contentType = response.headers.get('content-type') || '';
4956
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
+ };
4957
5372
  if (!response.ok) {
4958
5373
  const payload = contentType.includes('application/json')
4959
5374
  ? await response.json()
4960
- : { message: await response.text() };
5375
+ : { message: await readResponseText() };
4961
5376
  const error = new Error(payload?.message || payload?.error || `Request failed with status ${response.status}.`);
4962
5377
  error.status = response.status;
4963
5378
  error.payload = payload;
4964
5379
  throw error;
4965
5380
  }
4966
5381
  return {
4967
- text: await response.text(),
5382
+ text: await readResponseText(),
4968
5383
  contentType,
4969
5384
  fileName: parseContentDispositionFilename(contentDisposition),
4970
5385
  headers: Object.fromEntries(response.headers.entries()),