@bpmsoftwaresolutions/ai-engine-client 1.1.85 → 1.1.86

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.
@@ -0,0 +1,664 @@
1
+ import {
2
+ cleanText,
3
+ isPlainObject,
4
+ normalizeConnectionFirstMessageKind,
5
+ normalizeTransferKind,
6
+ } from '../utils/communication.js';
7
+
8
+ function normalizeTransferChannelId(request = {}) {
9
+ return cleanText(request.transfer_channel_id)
10
+ || cleanText(request.transferChannelId)
11
+ || cleanText(request.channel_id)
12
+ || cleanText(request.channelId);
13
+ }
14
+
15
+ async function resolveTransferPacketId(client, transferChannelId, request = {}) {
16
+ let normalizedPacketId = cleanText(request.work_transfer_packet_id) || cleanText(request.workTransferPacketId) || cleanText(request.packet_id) || cleanText(request.packetId);
17
+ if (!normalizedPacketId) {
18
+ try {
19
+ const status = await client.getCommunicationChannelStatus({ transferChannelId });
20
+ normalizedPacketId = cleanText(status?.packet_id || status?.packetId || status?.work_transfer_packet_id);
21
+ } catch (error) {
22
+ void error;
23
+ }
24
+ }
25
+ return normalizedPacketId;
26
+ }
27
+
28
+ export function createTransferChannelsDomain(client) {
29
+ return {
30
+ listCommunicationChannels: (request) => listCommunicationChannels(client, request),
31
+ listOpenCommunicationChannels: (request) => listOpenCommunicationChannels(client, request),
32
+ getCommunicationChannelStatus: (request) => getCommunicationChannelStatus(client, request),
33
+ getCommunicationChannelParticipants: (request) => getCommunicationChannelParticipants(client, request),
34
+ openTransferChannel: (request) => openTransferChannel(client, request),
35
+ joinTransferChannel: (request) => joinTransferChannel(client, request),
36
+ resumeTransferChannel: (request) => resumeTransferChannel(client, request),
37
+ replyToTransferChannel: (request) => replyToTransferChannel(client, request),
38
+ closeTransferChannel: (request) => closeTransferChannel(client, request),
39
+ requestTransferClosure: (request) => requestTransferClosure(client, request),
40
+ openAgentChannel: (request) => openAgentChannel(client, request),
41
+ connectToTransferChannel: (request) => connectToTransferChannel(client, request),
42
+ startAgentConnection: (request) => startAgentConnection(client, request),
43
+ postAgentHeartbeat: (request) => postAgentHeartbeat(client, request),
44
+ closeAgentChannel: (request) => closeAgentChannel(client, request),
45
+ };
46
+ }
47
+
48
+ export async function listCommunicationChannels(client, {
49
+ workflowRunId,
50
+ workflow_run_id,
51
+ workTransferPacketId,
52
+ work_transfer_packet_id,
53
+ status,
54
+ channelStatus,
55
+ channel_status,
56
+ } = {}) {
57
+ return client._request('/api/agent-communications/transfer-channels', {
58
+ query: {
59
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
60
+ work_transfer_packet_id: cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId),
61
+ status: cleanText(status) || cleanText(channel_status) || cleanText(channelStatus),
62
+ },
63
+ });
64
+ }
65
+
66
+ export async function listOpenCommunicationChannels(client, request = {}) {
67
+ return listCommunicationChannels(client, { ...request, status: 'open' });
68
+ }
69
+
70
+ export async function getCommunicationChannelStatus(client, {
71
+ transferChannelId,
72
+ transfer_channel_id,
73
+ channelId,
74
+ channel_id,
75
+ } = {}) {
76
+ const normalizedTransferChannelId = cleanText(transfer_channel_id) || cleanText(transferChannelId) || cleanText(channel_id) || cleanText(channelId);
77
+ if (!normalizedTransferChannelId) throw new Error('transferChannelId is required.');
78
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/status`);
79
+ }
80
+
81
+ export async function getCommunicationChannelParticipants(client, {
82
+ transferChannelId,
83
+ transfer_channel_id,
84
+ channelId,
85
+ channel_id,
86
+ } = {}) {
87
+ const normalizedTransferChannelId = cleanText(transfer_channel_id) || cleanText(transferChannelId) || cleanText(channel_id) || cleanText(channelId);
88
+ if (!normalizedTransferChannelId) throw new Error('transferChannelId is required.');
89
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/participants`);
90
+ }
91
+
92
+ export async function openTransferChannel(client, {
93
+ workTransferPacketId,
94
+ work_transfer_packet_id,
95
+ packetId,
96
+ packet_id,
97
+ workflowRunId,
98
+ workflow_run_id,
99
+ channelKind = 'bidirectional',
100
+ channel_kind,
101
+ upstreamAgentSessionId,
102
+ upstream_agent_session_id,
103
+ upstreamActorSessionId,
104
+ upstream_actor_session_id,
105
+ downstreamAgentSessionId,
106
+ downstream_agent_session_id,
107
+ downstreamActorSessionId,
108
+ downstream_actor_session_id,
109
+ evidenceRequiredForClosure,
110
+ evidence_required_for_closure,
111
+ metadata = {},
112
+ } = {}) {
113
+ const normalizedPacketId = cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId);
114
+ if (!normalizedPacketId) throw new Error('work_transfer_packet_id is required.');
115
+ return client._request('/api/agent-communications/transfer-channels', {
116
+ method: 'POST',
117
+ body: {
118
+ work_transfer_packet_id: normalizedPacketId,
119
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
120
+ channel_kind: cleanText(channel_kind) || cleanText(channelKind) || 'bidirectional',
121
+ upstream_agent_session_id: cleanText(upstream_agent_session_id) || cleanText(upstreamAgentSessionId),
122
+ upstream_actor_session_id: cleanText(upstream_actor_session_id) || cleanText(upstreamActorSessionId),
123
+ downstream_agent_session_id: cleanText(downstream_agent_session_id) || cleanText(downstreamAgentSessionId),
124
+ downstream_actor_session_id: cleanText(downstream_actor_session_id) || cleanText(downstreamActorSessionId),
125
+ evidence_required_for_closure: evidence_required_for_closure ?? evidenceRequiredForClosure ?? true,
126
+ metadata: isPlainObject(metadata) ? metadata : {},
127
+ },
128
+ });
129
+ }
130
+
131
+ export async function joinTransferChannel(client, request = {}) {
132
+ const normalizedTransferChannelId = normalizeTransferChannelId(request);
133
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
134
+ const normalizedPacketId = await resolveTransferPacketId(client, normalizedTransferChannelId, request);
135
+ if (!normalizedPacketId) throw new Error('work_transfer_packet_id is required.');
136
+ const {
137
+ workflowRunId,
138
+ workflow_run_id,
139
+ participantRole,
140
+ participant_role,
141
+ participantKind,
142
+ participant_kind,
143
+ participantLabel,
144
+ participant_label,
145
+ agentSessionId,
146
+ agent_session_id,
147
+ actorSessionId,
148
+ actor_session_id,
149
+ currentPhase,
150
+ current_phase,
151
+ currentTaskSummary,
152
+ current_task_summary,
153
+ lastSeenMessageId,
154
+ last_seen_message_id,
155
+ lastSeenAt,
156
+ last_seen_at,
157
+ lastSeenHeartbeatAt,
158
+ last_seen_heartbeat_at,
159
+ metadata = {},
160
+ } = request;
161
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/join`, {
162
+ method: 'POST',
163
+ body: {
164
+ work_transfer_packet_id: normalizedPacketId,
165
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
166
+ participant_role: cleanText(participant_role) || cleanText(participantRole),
167
+ participant_kind: cleanText(participant_kind) || cleanText(participantKind) || 'agent_session',
168
+ participant_label: cleanText(participant_label) || cleanText(participantLabel),
169
+ agent_session_id: cleanText(agent_session_id) || cleanText(agentSessionId) || client.agentSessionId,
170
+ actor_session_id: cleanText(actor_session_id) || cleanText(actorSessionId),
171
+ current_phase: cleanText(current_phase) || cleanText(currentPhase),
172
+ current_task_summary: cleanText(current_task_summary) || cleanText(currentTaskSummary),
173
+ last_seen_message_id: cleanText(last_seen_message_id) || cleanText(lastSeenMessageId),
174
+ last_seen_at: last_seen_at || lastSeenAt,
175
+ last_seen_heartbeat_at: last_seen_heartbeat_at || lastSeenHeartbeatAt,
176
+ metadata: isPlainObject(metadata) ? metadata : {},
177
+ },
178
+ });
179
+ }
180
+
181
+ export async function resumeTransferChannel(client, request = {}) {
182
+ const normalizedTransferChannelId = normalizeTransferChannelId(request);
183
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
184
+ const normalizedPacketId = await resolveTransferPacketId(client, normalizedTransferChannelId, request);
185
+ if (!normalizedPacketId) throw new Error('work_transfer_packet_id is required.');
186
+ const {
187
+ workflowRunId,
188
+ workflow_run_id,
189
+ participantRole,
190
+ participant_role,
191
+ participantKind,
192
+ participant_kind,
193
+ participantLabel,
194
+ participant_label,
195
+ agentSessionId,
196
+ agent_session_id,
197
+ actorSessionId,
198
+ actor_session_id,
199
+ currentPhase,
200
+ current_phase,
201
+ currentTaskSummary,
202
+ current_task_summary,
203
+ lastSeenMessageId,
204
+ last_seen_message_id,
205
+ lastSeenAt,
206
+ last_seen_at,
207
+ lastSeenHeartbeatAt,
208
+ last_seen_heartbeat_at,
209
+ metadata = {},
210
+ } = request;
211
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/resume`, {
212
+ method: 'POST',
213
+ body: {
214
+ work_transfer_packet_id: normalizedPacketId,
215
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
216
+ participant_role: cleanText(participant_role) || cleanText(participantRole),
217
+ participant_kind: cleanText(participant_kind) || cleanText(participantKind) || 'agent_session',
218
+ participant_label: cleanText(participant_label) || cleanText(participantLabel),
219
+ agent_session_id: cleanText(agent_session_id) || cleanText(agentSessionId) || client.agentSessionId,
220
+ actor_session_id: cleanText(actor_session_id) || cleanText(actorSessionId),
221
+ current_phase: cleanText(current_phase) || cleanText(currentPhase),
222
+ current_task_summary: cleanText(current_task_summary) || cleanText(currentTaskSummary),
223
+ last_seen_message_id: cleanText(last_seen_message_id) || cleanText(lastSeenMessageId),
224
+ last_seen_at: last_seen_at || lastSeenAt,
225
+ last_seen_heartbeat_at: last_seen_heartbeat_at || lastSeenHeartbeatAt,
226
+ metadata: isPlainObject(metadata) ? metadata : {},
227
+ },
228
+ });
229
+ }
230
+
231
+ export async function replyToTransferChannel(client, request = {}) {
232
+ const normalizedTransferChannelId = normalizeTransferChannelId(request);
233
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
234
+ const {
235
+ senderAgentSessionId,
236
+ sender_agent_session_id,
237
+ senderActorSessionId,
238
+ sender_actor_session_id,
239
+ recipientAgentSessionId,
240
+ recipient_agent_session_id,
241
+ recipientActorSessionId,
242
+ recipient_actor_session_id,
243
+ messageKind,
244
+ message_kind,
245
+ bodyMarkdown,
246
+ body_markdown,
247
+ transferChannelMessageStatus,
248
+ transfer_channel_message_status,
249
+ messageStatus,
250
+ message_status,
251
+ payload = {},
252
+ scope = {},
253
+ requiredResponseSchema = {},
254
+ required_response_schema = {},
255
+ evidenceRefs = [],
256
+ evidence_refs = [],
257
+ metadata = {},
258
+ closureReason,
259
+ closure_reason,
260
+ failureReason,
261
+ failure_reason,
262
+ currentWaitingSide,
263
+ current_waiting_side,
264
+ } = request;
265
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/messages`, {
266
+ method: 'POST',
267
+ body: {
268
+ sender_agent_session_id: cleanText(sender_agent_session_id) || cleanText(senderAgentSessionId) || client.agentSessionId,
269
+ sender_actor_session_id: cleanText(sender_actor_session_id) || cleanText(senderActorSessionId),
270
+ recipient_agent_session_id: cleanText(recipient_agent_session_id) || cleanText(recipientAgentSessionId),
271
+ recipient_actor_session_id: cleanText(recipient_actor_session_id) || cleanText(recipientActorSessionId),
272
+ message_kind: cleanText(message_kind) || cleanText(messageKind) || 'clarification_request',
273
+ body_markdown: cleanText(body_markdown) || cleanText(bodyMarkdown),
274
+ transfer_channel_message_status: cleanText(transfer_channel_message_status) || cleanText(transferChannelMessageStatus) || cleanText(message_status) || cleanText(messageStatus),
275
+ payload: isPlainObject(payload) ? payload : {},
276
+ scope: isPlainObject(scope) ? scope : {},
277
+ required_response_schema: isPlainObject(required_response_schema) ? required_response_schema : (isPlainObject(requiredResponseSchema) ? requiredResponseSchema : {}),
278
+ evidence_refs: Array.isArray(evidence_refs) ? evidence_refs : evidenceRefs,
279
+ metadata: isPlainObject(metadata) ? metadata : {},
280
+ closure_reason: cleanText(closure_reason) || cleanText(closureReason),
281
+ failure_reason: cleanText(failure_reason) || cleanText(failureReason),
282
+ current_waiting_side: cleanText(current_waiting_side) || cleanText(currentWaitingSide),
283
+ },
284
+ });
285
+ }
286
+
287
+ export async function requestTransferClosure(client, request = {}) {
288
+ const normalizedTransferChannelId = normalizeTransferChannelId(request);
289
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
290
+ const {
291
+ senderAgentSessionId,
292
+ sender_agent_session_id,
293
+ senderActorSessionId,
294
+ sender_actor_session_id,
295
+ bodyMarkdown,
296
+ body_markdown,
297
+ closureReason,
298
+ closure_reason,
299
+ evidenceRefs = [],
300
+ evidence_refs = [],
301
+ metadata = {},
302
+ } = request;
303
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/closure-request`, {
304
+ method: 'POST',
305
+ body: {
306
+ sender_agent_session_id: cleanText(sender_agent_session_id) || cleanText(senderAgentSessionId) || client.agentSessionId,
307
+ sender_actor_session_id: cleanText(sender_actor_session_id) || cleanText(senderActorSessionId),
308
+ body_markdown: cleanText(body_markdown) || cleanText(bodyMarkdown),
309
+ closure_reason: cleanText(closure_reason) || cleanText(closureReason),
310
+ evidence_refs: Array.isArray(evidence_refs) ? evidence_refs : evidenceRefs,
311
+ metadata: isPlainObject(metadata) ? metadata : {},
312
+ },
313
+ });
314
+ }
315
+
316
+ export async function closeTransferChannel(client, request = {}) {
317
+ const normalizedTransferChannelId = normalizeTransferChannelId(request);
318
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
319
+ const {
320
+ closureStatus,
321
+ closure_status,
322
+ closureReason,
323
+ closure_reason,
324
+ failureReason,
325
+ failure_reason,
326
+ evidence = {},
327
+ evidenceManifestSha256,
328
+ evidence_manifest_sha256,
329
+ closedByAgentSessionId,
330
+ closed_by_agent_session_id,
331
+ closedByActorSessionId,
332
+ closed_by_actor_session_id,
333
+ closedByClaimId,
334
+ closed_by_claim_id,
335
+ metadata = {},
336
+ } = request;
337
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/close`, {
338
+ method: 'POST',
339
+ body: {
340
+ closure_status: cleanText(closure_status) || cleanText(closureStatus) || 'closed',
341
+ closure_reason: cleanText(closure_reason) || cleanText(closureReason),
342
+ failure_reason: cleanText(failure_reason) || cleanText(failureReason),
343
+ evidence: isPlainObject(evidence) ? evidence : {},
344
+ evidence_manifest_sha256: cleanText(evidence_manifest_sha256) || cleanText(evidenceManifestSha256),
345
+ closed_by_agent_session_id: cleanText(closed_by_agent_session_id) || cleanText(closedByAgentSessionId),
346
+ closed_by_actor_session_id: cleanText(closed_by_actor_session_id) || cleanText(closedByActorSessionId),
347
+ closed_by_claim_id: cleanText(closed_by_claim_id) || cleanText(closedByClaimId),
348
+ metadata: isPlainObject(metadata) ? metadata : {},
349
+ },
350
+ });
351
+ }
352
+
353
+ export async function openAgentChannel(client, request = {}) {
354
+ return connectToTransferChannel(client, request);
355
+ }
356
+
357
+ export async function connectToTransferChannel(client, request = {}) {
358
+ const normalizedTransferChannelId = normalizeTransferChannelId(request);
359
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
360
+ let normalizedPacketId = cleanText(request.work_transfer_packet_id) || cleanText(request.workTransferPacketId) || cleanText(request.packet_id) || cleanText(request.packetId);
361
+ if (!normalizedPacketId) {
362
+ try {
363
+ const status = await client.getCommunicationChannelStatus({ transferChannelId: normalizedTransferChannelId });
364
+ normalizedPacketId = cleanText(status?.packet_id || status?.packetId || status?.work_transfer_packet_id);
365
+ } catch (error) {
366
+ void error;
367
+ }
368
+ }
369
+ if (!normalizedPacketId) throw new Error('work_transfer_packet_id is required.');
370
+ const {
371
+ workflowRunId,
372
+ workflow_run_id,
373
+ participantRole,
374
+ participant_role,
375
+ expectedPeerRole,
376
+ expected_peer_role,
377
+ expectedMessageKind,
378
+ expected_message_kind,
379
+ proposalId,
380
+ proposal_id,
381
+ collaborationProposalId,
382
+ collaboration_proposal_id,
383
+ mode = 'communication_participant',
384
+ participantLabel,
385
+ participant_label,
386
+ participantRoleKey,
387
+ participant_role_key,
388
+ agentSessionId,
389
+ agent_session_id,
390
+ actorSessionId,
391
+ actor_session_id,
392
+ phase,
393
+ currentPhase,
394
+ current_phase,
395
+ currentTaskSummary,
396
+ current_task_summary,
397
+ expectedPayload = {},
398
+ expected_payload = {},
399
+ lastSeenMessageId,
400
+ last_seen_message_id,
401
+ lastCheckedAt,
402
+ last_checked_at,
403
+ staleAfterSeconds = 60,
404
+ stale_after_seconds,
405
+ operatorNudge,
406
+ operator_nudge,
407
+ observedAt,
408
+ observed_at,
409
+ metadata = {},
410
+ } = request;
411
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/connect`, {
412
+ method: 'POST',
413
+ body: {
414
+ work_transfer_packet_id: normalizedPacketId,
415
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
416
+ participant_role: cleanText(participant_role) || cleanText(participantRole),
417
+ expected_peer_role: cleanText(expected_peer_role) || cleanText(expectedPeerRole),
418
+ expected_message_kind: cleanText(expected_message_kind) || cleanText(expectedMessageKind),
419
+ proposal_id: cleanText(proposal_id) || cleanText(proposalId) || cleanText(collaboration_proposal_id) || cleanText(collaborationProposalId),
420
+ mode: cleanText(mode) || 'communication_participant',
421
+ participant_label: cleanText(participant_label) || cleanText(participantLabel) || cleanText(participant_role_key) || cleanText(participantRoleKey),
422
+ agent_session_id: cleanText(agent_session_id) || cleanText(agentSessionId) || client.agentSessionId,
423
+ actor_session_id: cleanText(actor_session_id) || cleanText(actorSessionId),
424
+ phase: cleanText(current_phase) || cleanText(currentPhase) || cleanText(phase),
425
+ current_task_summary: cleanText(current_task_summary) || cleanText(currentTaskSummary),
426
+ expected_payload: isPlainObject(expected_payload) ? expected_payload : isPlainObject(expectedPayload) ? expectedPayload : {},
427
+ last_seen_message_id: cleanText(last_seen_message_id) || cleanText(lastSeenMessageId),
428
+ last_checked_at: last_checked_at || lastCheckedAt,
429
+ stale_after_seconds: stale_after_seconds || staleAfterSeconds,
430
+ operator_nudge: cleanText(operator_nudge) || cleanText(operatorNudge),
431
+ observed_at: observed_at || observedAt,
432
+ metadata: isPlainObject(metadata) ? metadata : {},
433
+ },
434
+ });
435
+ }
436
+
437
+ export async function startAgentConnection(client, request = {}) {
438
+ const normalizedFirstMessage = isPlainObject(request.firstMessage) ? request.firstMessage : isPlainObject(request.first_message) ? request.first_message : {};
439
+ const normalizedTransferKind = normalizeTransferKind(cleanText(request.mode) || 'handoff');
440
+ let normalizedWorkflowRunId = cleanText(request.workflow_run_id) || cleanText(request.workflowRunId);
441
+ if (!normalizedWorkflowRunId) {
442
+ try {
443
+ const status = await client.currentWorkflowStatus();
444
+ normalizedWorkflowRunId =
445
+ cleanText(status?.workflow_run_id)
446
+ || cleanText(status?.workflowRunId)
447
+ || cleanText(status?.current_workflow_run_id)
448
+ || cleanText(status?.currentWorkflowRunId)
449
+ || cleanText(status?.summary?.workflow_run_id)
450
+ || cleanText(status?.summary?.workflowRunId)
451
+ || cleanText(status?.summary?.current_workflow_run_id)
452
+ || cleanText(status?.summary?.currentWorkflowRunId);
453
+ } catch (error) {
454
+ void error;
455
+ }
456
+ }
457
+ if (!normalizedWorkflowRunId) {
458
+ throw new Error('workflow_run_id is required to start an agent connection.');
459
+ }
460
+ const normalizedUpstreamAgent = cleanText(request.upstream_agent) || cleanText(request.upstreamAgent) || cleanText(request.upstream_agent_session_id) || cleanText(request.upstreamAgentSessionId) || cleanText(request.upstream_agent_id) || cleanText(request.upstreamAgentId);
461
+ const normalizedRecipientMode = cleanText(request.recipient_mode) || cleanText(request.recipientMode) || (normalizedUpstreamAgent ? 'agent_session' : 'role');
462
+ const normalizedParticipantRole = cleanText(request.participant_role) || cleanText(request.participantRole) || 'downstream';
463
+ const normalizedParticipantLabel = cleanText(request.participant_label) || cleanText(request.participantLabel) || normalizedParticipantRole;
464
+ const normalizedSenderAgentSessionId = cleanText(request.sender_agent_session_id) || cleanText(request.senderAgentSessionId) || client.agentSessionId;
465
+ const normalizedSenderActorSessionId = cleanText(request.sender_actor_session_id) || cleanText(request.senderActorSessionId);
466
+ const normalizedFirstMessageKind = normalizeConnectionFirstMessageKind(
467
+ cleanText(normalizedFirstMessage.kind) || cleanText(normalizedFirstMessage.message_kind) || cleanText(normalizedFirstMessage.messageKind),
468
+ normalizedTransferKind,
469
+ );
470
+ const normalizedExpectedMessageKind = cleanText(request.expected_message_kind) || cleanText(request.expectedMessageKind) || 'connection_accepted';
471
+ const normalizedObjective = cleanText(request.objective) || cleanText(request.purpose) || cleanText(normalizedFirstMessage.body) || cleanText(normalizedFirstMessage.body_markdown) || cleanText(normalizedFirstMessage.bodyMarkdown) || 'Establish governed coordination.';
472
+ const transferResult = await client.transferWorkPacket({
473
+ workflowRunId: normalizedWorkflowRunId,
474
+ transferKind: normalizedTransferKind,
475
+ objective: normalizedObjective,
476
+ requestedOutcome: cleanText(request.purpose) || normalizedObjective,
477
+ target: {
478
+ intent: normalizedTransferKind,
479
+ recipient_mode: normalizedRecipientMode,
480
+ preferred_agent_session_id: normalizedUpstreamAgent,
481
+ preferred_role_key: cleanText(request.upstream_role) || cleanText(request.upstreamRole),
482
+ },
483
+ artifacts: [],
484
+ issues: [],
485
+ expectedEvidence: [],
486
+ preferredModes: ['inline_payload', 'bundle', 'artifact_refs'],
487
+ capabilities: {},
488
+ senderAgentSessionId: normalizedSenderAgentSessionId,
489
+ senderActorSessionId: normalizedSenderActorSessionId,
490
+ subject: cleanText(request.purpose) || normalizedObjective,
491
+ bodyMarkdown:
492
+ cleanText(normalizedFirstMessage.body_markdown)
493
+ || cleanText(normalizedFirstMessage.bodyMarkdown)
494
+ || cleanText(normalizedFirstMessage.body)
495
+ || `Connection request: ${normalizedObjective}`,
496
+ cleanupPolicy: cleanText(request.cleanup_policy) || cleanText(request.cleanupPolicy),
497
+ messageKind: normalizedFirstMessageKind,
498
+ message_kind: normalizedFirstMessageKind,
499
+ metadata: isPlainObject(request.metadata) ? request.metadata : {},
500
+ });
501
+ const transferChannel = transferResult.communication_transfer_channel || {};
502
+ const connection = await client.connectToTransferChannel({
503
+ transferChannelId: transferChannel.transfer_channel_id || transferChannel.channel_id || transferResult.channel_id,
504
+ workTransferPacketId: transferResult.work_transfer_packet?.work_transfer_packet_id || transferResult.packet_id || transferResult.transfer_packet_id,
505
+ workflowRunId: normalizedWorkflowRunId,
506
+ participantRole: normalizedParticipantRole,
507
+ expectedPeerRole: cleanText(request.upstream_role) || cleanText(request.upstreamRole) || 'upstream',
508
+ expectedMessageKind: normalizedExpectedMessageKind,
509
+ proposalId: transferResult.transfer_negotiation?.proposal_id,
510
+ mode: 'communication_participant',
511
+ participantLabel: normalizedParticipantLabel,
512
+ senderAgentSessionId: normalizedSenderAgentSessionId,
513
+ senderActorSessionId: normalizedSenderActorSessionId,
514
+ currentPhase: 'channel_ready',
515
+ currentTaskSummary: cleanText(request.purpose) || normalizedObjective,
516
+ expectedPayload: {
517
+ purpose: cleanText(request.purpose) || normalizedObjective,
518
+ first_message_kind: normalizedFirstMessageKind,
519
+ first_message_body:
520
+ cleanText(normalizedFirstMessage.body_markdown)
521
+ || cleanText(normalizedFirstMessage.bodyMarkdown)
522
+ || cleanText(normalizedFirstMessage.body)
523
+ || null,
524
+ },
525
+ lastSeenMessageId: transferResult.communication_message?.agent_message_id,
526
+ staleAfterSeconds: request.stale_after_seconds ?? request.staleAfterSeconds ?? 300,
527
+ operatorNudge:
528
+ cleanText(request.operator_nudge)
529
+ || cleanText(request.operatorNudge)
530
+ || `upstream, please send ${normalizedExpectedMessageKind}.`,
531
+ observedAt: transferResult.communication_message?.created_at || transferResult.transfer_receipt?.created_at,
532
+ metadata: {
533
+ ...(isPlainObject(request.metadata) ? request.metadata : {}),
534
+ start_agent_connection: true,
535
+ },
536
+ });
537
+ const handshake = connection.handshake || {};
538
+ const status = connection.connected ? 'waiting' : (connection.stop_reason ? 'failed' : 'waiting');
539
+ const transferPacketId = transferResult.work_transfer_packet?.work_transfer_packet_id || transferResult.transfer_receipt?.transfer_packet_id || transferResult.packet_id || null;
540
+ const channelId = connection.channel_id || transferChannel.transfer_channel_id || transferChannel.channel_id || null;
541
+ return {
542
+ status,
543
+ channel_id: channelId,
544
+ transfer_packet_id: transferPacketId,
545
+ correlation_id: connection.correlation_id || handshake.correlation_id || null,
546
+ handshake_state: connection.handshake_state || handshake.handshake_state || null,
547
+ waiting_side: connection.waiting_on || connection.expected_from || handshake.waiting_side || null,
548
+ expected_message: connection.expected_message_kind || handshake.expected_message_kind || normalizedExpectedMessageKind,
549
+ last_heartbeat_at: handshake.last_heartbeat_at || connection.collaboration_heartbeat?.observed_at || null,
550
+ last_receipt_id: handshake.last_receipt_id || transferResult.transfer_receipt?.receipt_id || null,
551
+ operator_nudge: connection.operator_nudge || handshake.operator_nudge || null,
552
+ handshake,
553
+ connection,
554
+ transfer: transferResult,
555
+ first_message: {
556
+ kind: normalizedFirstMessageKind,
557
+ body: cleanText(normalizedFirstMessage.body_markdown) || cleanText(normalizedFirstMessage.bodyMarkdown) || cleanText(normalizedFirstMessage.body) || null,
558
+ },
559
+ transfer_channel: transferChannel,
560
+ transfer_receipt: transferResult.transfer_receipt || null,
561
+ communication_message: transferResult.communication_message || null,
562
+ };
563
+ }
564
+
565
+ export async function postAgentHeartbeat(client, {
566
+ transferChannelId,
567
+ transfer_channel_id,
568
+ channelId,
569
+ channel_id,
570
+ workTransferPacketId,
571
+ work_transfer_packet_id,
572
+ packetId,
573
+ packet_id,
574
+ workflowRunId,
575
+ workflow_run_id,
576
+ participantRole,
577
+ participant_role,
578
+ role,
579
+ activityState,
580
+ activity_state,
581
+ agentSessionId,
582
+ agent_session_id,
583
+ actorSessionId,
584
+ actor_session_id,
585
+ currentPhase,
586
+ current_phase,
587
+ phase,
588
+ currentTaskSummary,
589
+ current_task_summary,
590
+ isActive,
591
+ is_active,
592
+ observedAt,
593
+ observed_at,
594
+ metadata = {},
595
+ } = {}) {
596
+ const normalizedTransferChannelId = cleanText(transfer_channel_id) || cleanText(transferChannelId) || cleanText(channel_id) || cleanText(channelId);
597
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
598
+ let normalizedPacketId = cleanText(work_transfer_packet_id) || cleanText(workTransferPacketId) || cleanText(packet_id) || cleanText(packetId);
599
+ if (!normalizedPacketId) {
600
+ try {
601
+ const status = await client.getCommunicationChannelStatus({ transferChannelId: normalizedTransferChannelId });
602
+ normalizedPacketId = cleanText(status?.packet_id || status?.packetId || status?.work_transfer_packet_id);
603
+ } catch (error) {
604
+ void error;
605
+ }
606
+ }
607
+ if (!normalizedPacketId) throw new Error('work_transfer_packet_id is required.');
608
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/heartbeats`, {
609
+ method: 'POST',
610
+ body: {
611
+ work_transfer_packet_id: normalizedPacketId,
612
+ workflow_run_id: cleanText(workflow_run_id) || cleanText(workflowRunId),
613
+ participant_role: cleanText(participant_role) || cleanText(participantRole) || cleanText(role),
614
+ activity_state: cleanText(activity_state) || cleanText(activityState) || 'active',
615
+ agent_session_id: cleanText(agent_session_id) || cleanText(agentSessionId) || client.agentSessionId,
616
+ actor_session_id: cleanText(actor_session_id) || cleanText(actorSessionId),
617
+ current_phase: cleanText(current_phase) || cleanText(currentPhase) || cleanText(phase),
618
+ current_task_summary: cleanText(current_task_summary) || cleanText(currentTaskSummary),
619
+ is_active: is_active ?? isActive ?? true,
620
+ observed_at: observed_at || observedAt,
621
+ metadata: isPlainObject(metadata) ? metadata : {},
622
+ },
623
+ });
624
+ }
625
+
626
+ export async function closeAgentChannel(client, {
627
+ transferChannelId,
628
+ transfer_channel_id,
629
+ channelId,
630
+ channel_id,
631
+ closureStatus,
632
+ closure_status,
633
+ closureReason,
634
+ closure_reason,
635
+ failureReason,
636
+ failure_reason,
637
+ evidence = {},
638
+ evidenceManifestSha256,
639
+ evidence_manifest_sha256,
640
+ closedByAgentSessionId,
641
+ closed_by_agent_session_id,
642
+ closedByActorSessionId,
643
+ closed_by_actor_session_id,
644
+ closedByClaimId,
645
+ closed_by_claim_id,
646
+ metadata = {},
647
+ } = {}) {
648
+ const normalizedTransferChannelId = cleanText(transfer_channel_id) || cleanText(transferChannelId) || cleanText(channel_id) || cleanText(channelId);
649
+ if (!normalizedTransferChannelId) throw new Error('transfer_channel_id is required.');
650
+ return client._request(`/api/agent-communications/transfer-channels/${encodeURIComponent(normalizedTransferChannelId)}/close`, {
651
+ method: 'POST',
652
+ body: {
653
+ closure_status: cleanText(closure_status) || cleanText(closureStatus) || 'closed',
654
+ closure_reason: cleanText(closure_reason) || cleanText(closureReason),
655
+ failure_reason: cleanText(failure_reason) || cleanText(failureReason),
656
+ evidence: isPlainObject(evidence) ? evidence : {},
657
+ evidence_manifest_sha256: cleanText(evidence_manifest_sha256) || cleanText(evidenceManifestSha256),
658
+ closed_by_agent_session_id: cleanText(closed_by_agent_session_id) || cleanText(closedByAgentSessionId),
659
+ closed_by_actor_session_id: cleanText(closed_by_actor_session_id) || cleanText(closedByActorSessionId),
660
+ closed_by_claim_id: cleanText(closed_by_claim_id) || cleanText(closedByClaimId),
661
+ metadata: isPlainObject(metadata) ? metadata : {},
662
+ },
663
+ });
664
+ }
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { AIEngineClient, createAIEngineClient } from './client.js';
2
- export const AI_ENGINE_CLIENT_VERSION = '1.1.85';
2
+ export const AI_ENGINE_CLIENT_VERSION = '1.1.86';
3
3
  export { GOVERNED_MUTATION_REQUIRED_CAPABILITIES, AI_ENGINE_CLIENT_CAPABILITIES, TASK_BOUND_SUBSTRATE_EXECUTION_POLICY } from './constants/governance.js';
4
4
  export { LOGA_CONTRACT, LOGA_INTERACTION_CONTRACT, LOGA_NAVIGATION_CONTRACT, LOGA_PROJECTION_WORKFLOW } from './constants/loga.js';
5
5
  export {