@hirey/hi-mcp-server 0.1.1 → 0.1.2

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,741 @@
1
+ // Hi external agent gateway 的正式公共合同。
2
+ // 这个包只承载协议常量、类型与输入归一化,不承载任何数据库或 HTTP 逻辑。
3
+ export const AGENT_ENDPOINT_KINDS = ['webhook', 'http_api', 'pull_stream'];
4
+ export const AGENT_DELIVERY_PROFILES = [
5
+ 'generic.event-webhook.v1',
6
+ 'openclaw.hooks.agent.v1',
7
+ 'openresponses.v1',
8
+ 'hi.sse.v1',
9
+ ];
10
+ export const AGENT_INSTALLATION_RECEIVING_CAPABILITIES = [
11
+ 'pull_stream',
12
+ 'claim_ack',
13
+ 'generic_webhook',
14
+ 'claude_channel',
15
+ 'openclaw_hooks',
16
+ 'openresponses',
17
+ 'local_receiver',
18
+ ];
19
+ export const AGENT_INSTALLATION_RECEIVING_CAPABILITY_STATUSES = ['active', 'disabled'];
20
+ export const AGENT_CAPABILITY_BINDING_PROFILES = [
21
+ 'hi.capability-http.v1',
22
+ 'hi.mcp.tool-call.v1',
23
+ ];
24
+ export const AGENT_DELIVERY_ENDPOINT_STATUSES = ['active', 'disabled'];
25
+ export const AGENT_SUBSCRIPTION_STATUSES = ['active', 'disabled'];
26
+ export const AGENT_EVENT_STATUSES = ['queued', 'processing', 'consumed', 'failed'];
27
+ export const AGENT_EVENT_ACK_STATUSES = ['consumed', 'failed', 'queued'];
28
+ export const AGENT_GATEWAY_EVENT_TOPICS = [
29
+ 'agent.message.created',
30
+ 'pairing.created',
31
+ 'pairing.updated',
32
+ 'listing_matching_session.updated',
33
+ 'meeting.negotiation.updated',
34
+ 'meeting.execution.requested',
35
+ ];
36
+ export const AGENT_GATEWAY_PUBLIC_SCOPES = [
37
+ 'agent.register',
38
+ 'agent.connect',
39
+ 'agent.activate',
40
+ 'agent.me.read',
41
+ 'agent.installation.read',
42
+ 'agent.installation.write',
43
+ 'agent.endpoints.read',
44
+ 'agent.endpoints.write',
45
+ 'agent.subscriptions.read',
46
+ 'agent.subscriptions.write',
47
+ 'agent.delivery.test',
48
+ 'agent.events.stream',
49
+ 'agent.events.claim',
50
+ 'agent.events.fetch',
51
+ 'agent.events.ack',
52
+ ];
53
+ function isPlainObject(input) {
54
+ return !!input && typeof input === 'object' && !Array.isArray(input);
55
+ }
56
+ export function normalizeText(input) {
57
+ return String(input || '').trim();
58
+ }
59
+ function normalizeStringArray(input, max) {
60
+ if (!Array.isArray(input))
61
+ return [];
62
+ const values = Array.from(new Set(input
63
+ .map((value) => normalizeText(value))
64
+ .filter(Boolean)));
65
+ return values.slice(0, Math.max(0, max));
66
+ }
67
+ function normalizeJsonRecord(input) {
68
+ return isPlainObject(input) ? input : null;
69
+ }
70
+ function normalizeNullableUrl(input) {
71
+ const raw = normalizeText(input);
72
+ if (!raw)
73
+ return null;
74
+ const parsed = new URL(raw);
75
+ if (!/^https?:$/i.test(parsed.protocol))
76
+ throw new Error('invalid_agent_endpoint_url');
77
+ return parsed.toString();
78
+ }
79
+ export function normalizeAgentEndpointKind(input) {
80
+ const kind = normalizeText(input).toLowerCase();
81
+ if (AGENT_ENDPOINT_KINDS.includes(kind))
82
+ return kind;
83
+ throw new Error('invalid_agent_endpoint_kind');
84
+ }
85
+ export function normalizeAgentDeliveryProfile(input) {
86
+ const profile = normalizeText(input);
87
+ if (AGENT_DELIVERY_PROFILES.includes(profile))
88
+ return profile;
89
+ throw new Error('invalid_agent_endpoint_profile');
90
+ }
91
+ export function normalizeAgentInstallationReceivingCapabilityKind(input) {
92
+ const kind = normalizeText(input).toLowerCase();
93
+ if (AGENT_INSTALLATION_RECEIVING_CAPABILITIES.includes(kind)) {
94
+ return kind;
95
+ }
96
+ throw new Error('invalid_agent_installation_capability_kind');
97
+ }
98
+ export function normalizeAgentInstallationReceivingCapabilityStatus(input) {
99
+ const status = normalizeText(input).toLowerCase();
100
+ if (!status)
101
+ return 'active';
102
+ if (AGENT_INSTALLATION_RECEIVING_CAPABILITY_STATUSES.includes(status)) {
103
+ return status;
104
+ }
105
+ throw new Error('invalid_agent_installation_capability_status');
106
+ }
107
+ export function normalizeAgentDeliveryEndpointStatus(input) {
108
+ const status = normalizeText(input).toLowerCase();
109
+ if (!status)
110
+ return 'active';
111
+ if (AGENT_DELIVERY_ENDPOINT_STATUSES.includes(status)) {
112
+ return status;
113
+ }
114
+ throw new Error('invalid_agent_endpoint_status');
115
+ }
116
+ export function normalizeAgentSubscriptionStatus(input) {
117
+ const status = normalizeText(input).toLowerCase();
118
+ if (!status)
119
+ return 'active';
120
+ if (AGENT_SUBSCRIPTION_STATUSES.includes(status)) {
121
+ return status;
122
+ }
123
+ throw new Error('invalid_agent_subscription_status');
124
+ }
125
+ export function normalizeAgentEventStatus(input) {
126
+ const status = normalizeText(input).toLowerCase();
127
+ if (!status)
128
+ return 'queued';
129
+ if (AGENT_EVENT_STATUSES.includes(status))
130
+ return status;
131
+ throw new Error('invalid_agent_event_status');
132
+ }
133
+ export function normalizeAgentEventAckStatus(input) {
134
+ const status = normalizeText(input).toLowerCase();
135
+ if (AGENT_EVENT_ACK_STATUSES.includes(status))
136
+ return status;
137
+ throw new Error('invalid_agent_event_ack_status');
138
+ }
139
+ export function normalizeAgentGatewayTopic(input) {
140
+ const topic = normalizeText(input).toLowerCase();
141
+ if (AGENT_GATEWAY_EVENT_TOPICS.includes(topic))
142
+ return topic;
143
+ throw new Error('unsupported_agent_gateway_topic');
144
+ }
145
+ function normalizeGenericEventWebhookEndpointConfig(input) {
146
+ if (input == null)
147
+ return null;
148
+ const row = isPlainObject(input) ? input : {};
149
+ const mode = normalizeText(row.mode);
150
+ if (mode && mode !== 'accepted_is_terminal') {
151
+ throw new Error('invalid_agent_endpoint_config');
152
+ }
153
+ return mode ? { mode: 'accepted_is_terminal' } : null;
154
+ }
155
+ function normalizeOpenClawHooksAgentEndpointConfig(input) {
156
+ if (input == null)
157
+ return null;
158
+ const row = isPlainObject(input) ? input : {};
159
+ const wakeMode = normalizeText(row.wake_mode);
160
+ if (wakeMode && wakeMode !== 'now' && wakeMode !== 'next-heartbeat') {
161
+ throw new Error('invalid_agent_endpoint_config');
162
+ }
163
+ const timeoutSeconds = row.timeout_seconds == null || row.timeout_seconds === ''
164
+ ? null
165
+ : Number(row.timeout_seconds);
166
+ if (timeoutSeconds != null && (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0)) {
167
+ throw new Error('invalid_agent_endpoint_config');
168
+ }
169
+ return {
170
+ name: normalizeText(row.name) || null,
171
+ agent_id: normalizeText(row.agent_id) || null,
172
+ session_key_prefix: normalizeText(row.session_key_prefix) || null,
173
+ message_prefix: normalizeText(row.message_prefix) || null,
174
+ wake_mode: wakeMode ? wakeMode : null,
175
+ deliver: typeof row.deliver === 'boolean' ? row.deliver : null,
176
+ channel: normalizeText(row.channel) || null,
177
+ to: normalizeText(row.to) || null,
178
+ model: normalizeText(row.model) || null,
179
+ thinking: normalizeText(row.thinking) || null,
180
+ timeout_seconds: timeoutSeconds == null ? null : Math.floor(timeoutSeconds),
181
+ };
182
+ }
183
+ function normalizeOpenResponsesEndpointConfig(input) {
184
+ const row = isPlainObject(input) ? input : {};
185
+ const model = normalizeText(row.model);
186
+ if (!model)
187
+ throw new Error('invalid_agent_endpoint_config');
188
+ return {
189
+ model,
190
+ agent_id: normalizeText(row.agent_id) || null,
191
+ session_key: normalizeText(row.session_key) || null,
192
+ session_key_prefix: normalizeText(row.session_key_prefix) || null,
193
+ instructions: normalizeText(row.instructions) || null,
194
+ user: normalizeText(row.user) || null,
195
+ };
196
+ }
197
+ export function normalizeAgentEndpointConfigForProfile(profile, input) {
198
+ if (profile === 'generic.event-webhook.v1') {
199
+ return normalizeGenericEventWebhookEndpointConfig(input);
200
+ }
201
+ if (profile === 'openclaw.hooks.agent.v1') {
202
+ return normalizeOpenClawHooksAgentEndpointConfig(input);
203
+ }
204
+ if (profile === 'openresponses.v1') {
205
+ return normalizeOpenResponsesEndpointConfig(input);
206
+ }
207
+ if (profile === 'hi.sse.v1') {
208
+ if (input == null)
209
+ return null;
210
+ if (!isPlainObject(input) || Object.keys(input).length === 0)
211
+ return null;
212
+ throw new Error('invalid_agent_endpoint_config');
213
+ }
214
+ return normalizeJsonRecord(input);
215
+ }
216
+ export function normalizeAgentEndpointInput(input) {
217
+ const row = isPlainObject(input) ? input : {};
218
+ const kind = normalizeAgentEndpointKind(row.kind);
219
+ const profile = normalizeAgentDeliveryProfile(row.profile);
220
+ const url = profile === 'hi.sse.v1'
221
+ ? null
222
+ : normalizeNullableUrl(row.url);
223
+ return {
224
+ kind,
225
+ profile,
226
+ status: normalizeAgentDeliveryEndpointStatus(row.status),
227
+ capability_ids: normalizeStringArray(row.capability_ids, 100),
228
+ url,
229
+ auth: normalizeJsonRecord(row.auth),
230
+ config: normalizeAgentEndpointConfigForProfile(profile, row.config),
231
+ };
232
+ }
233
+ export const normalizeAgentDeliveryEndpointInput = normalizeAgentEndpointInput;
234
+ export function normalizeAgentEndpointList(input) {
235
+ if (isPlainObject(input) && Array.isArray(input.endpoints)) {
236
+ return input.endpoints.map((row) => normalizeAgentEndpointInput(row));
237
+ }
238
+ if (Array.isArray(input)) {
239
+ return input.map((row) => normalizeAgentEndpointInput(row));
240
+ }
241
+ if (isPlainObject(input)) {
242
+ if (Object.prototype.hasOwnProperty.call(input, 'kind')) {
243
+ return [normalizeAgentEndpointInput(input)];
244
+ }
245
+ if (isPlainObject(input.endpoint)) {
246
+ return [normalizeAgentEndpointInput(input.endpoint)];
247
+ }
248
+ }
249
+ throw new Error('missing_agent_endpoints');
250
+ }
251
+ export const normalizeAgentDeliveryEndpointList = normalizeAgentEndpointList;
252
+ export function normalizeAgentSubscriptionInput(input) {
253
+ const row = isPlainObject(input) ? input : {};
254
+ return {
255
+ topic: normalizeAgentGatewayTopic(row.topic),
256
+ status: normalizeAgentSubscriptionStatus(row.status),
257
+ filter: normalizeJsonRecord(row.filter),
258
+ };
259
+ }
260
+ export function normalizeAgentSubscriptionList(input) {
261
+ if (isPlainObject(input) && Array.isArray(input.subscriptions)) {
262
+ return input.subscriptions.map((row) => normalizeAgentSubscriptionInput(row));
263
+ }
264
+ if (Array.isArray(input)) {
265
+ return input.map((row) => normalizeAgentSubscriptionInput(row));
266
+ }
267
+ if (isPlainObject(input)) {
268
+ if (Object.prototype.hasOwnProperty.call(input, 'topic')) {
269
+ return [normalizeAgentSubscriptionInput(input)];
270
+ }
271
+ if (isPlainObject(input.subscription)) {
272
+ return [normalizeAgentSubscriptionInput(input.subscription)];
273
+ }
274
+ }
275
+ throw new Error('missing_agent_subscriptions');
276
+ }
277
+ export function normalizeAgentInstallationReceivingCapabilityInput(input) {
278
+ const row = isPlainObject(input) ? input : {};
279
+ return {
280
+ kind: normalizeAgentInstallationReceivingCapabilityKind(row.kind),
281
+ status: normalizeAgentInstallationReceivingCapabilityStatus(row.status),
282
+ config: normalizeJsonRecord(row.config),
283
+ };
284
+ }
285
+ export function normalizeAgentInstallationDeliveryDeclaration(input) {
286
+ if (input == null)
287
+ return null;
288
+ const row = isPlainObject(input) ? input : {};
289
+ const sourceCapabilities = Array.isArray(row.capabilities)
290
+ ? row.capabilities
291
+ : (Array.isArray(input) ? input : []);
292
+ const deduped = new Map();
293
+ for (const entry of sourceCapabilities) {
294
+ const normalized = normalizeAgentInstallationReceivingCapabilityInput(entry);
295
+ deduped.set(normalized.kind, normalized);
296
+ }
297
+ const capabilities = Array.from(deduped.values());
298
+ const preferredRaw = normalizeText(row.preferred);
299
+ const preferred = preferredRaw
300
+ ? normalizeAgentInstallationReceivingCapabilityKind(preferredRaw)
301
+ : null;
302
+ if (preferred && !capabilities.some((entry) => entry.kind === preferred && entry.status !== 'disabled')) {
303
+ throw new Error('invalid_agent_installation_preferred_capability');
304
+ }
305
+ return {
306
+ capabilities,
307
+ preferred,
308
+ };
309
+ }
310
+ export function applyAgentInstallationDeliveryDeclarationMetadata(metadata, declaration) {
311
+ const next = metadata ? { ...metadata } : {};
312
+ if (declaration == null) {
313
+ delete next.delivery_capabilities;
314
+ }
315
+ else {
316
+ next.delivery_capabilities = declaration;
317
+ }
318
+ return Object.keys(next).length > 0 ? next : null;
319
+ }
320
+ export function extractAgentInstallationDeliveryDeclaration(metadata) {
321
+ if (!metadata || !isPlainObject(metadata))
322
+ return null;
323
+ if (!Object.prototype.hasOwnProperty.call(metadata, 'delivery_capabilities'))
324
+ return null;
325
+ return normalizeAgentInstallationDeliveryDeclaration(metadata.delivery_capabilities);
326
+ }
327
+ export function normalizeAgentGatewayResourceRef(input) {
328
+ const row = isPlainObject(input) ? input : {};
329
+ const resourceType = normalizeText(row.resource_type);
330
+ const resourceId = normalizeText(row.resource_id);
331
+ if (!resourceType || !resourceId) {
332
+ throw new Error('invalid_agent_gateway_resource_ref');
333
+ }
334
+ return {
335
+ resource_type: resourceType,
336
+ resource_id: resourceId,
337
+ scope_type: normalizeText(row.scope_type) || null,
338
+ scope_id: normalizeText(row.scope_id) || null,
339
+ pairing_id: normalizeText(row.pairing_id) || null,
340
+ conversation_id: normalizeText(row.conversation_id) || null,
341
+ source_message_id: normalizeText(row.source_message_id) || null,
342
+ };
343
+ }
344
+ export function normalizeAgentGatewayPreview(input) {
345
+ const row = isPlainObject(input) ? input : null;
346
+ if (!row)
347
+ return null;
348
+ const preview = {
349
+ title: normalizeText(row.title) || null,
350
+ text: normalizeText(row.text) || null,
351
+ actor_agent_id: normalizeText(row.actor_agent_id) || null,
352
+ status: normalizeText(row.status) || null,
353
+ direction: normalizeText(row.direction) || null,
354
+ };
355
+ return Object.values(preview).some((value) => !!value) ? preview : null;
356
+ }
357
+ export function parseAgentEventAfterSeq(input) {
358
+ if (input == null || input === '')
359
+ return 0;
360
+ const value = Number(input);
361
+ if (!Number.isFinite(value) || value < 0)
362
+ throw new Error('invalid_agent_event_after_seq');
363
+ return Math.floor(value);
364
+ }
365
+ export function parseAgentEventBatchLimit(input, fallback = 20, max = 100) {
366
+ if (input == null || input === '')
367
+ return fallback;
368
+ const value = Number(input);
369
+ if (!Number.isFinite(value) || value <= 0)
370
+ throw new Error('invalid_agent_event_batch_limit');
371
+ return Math.max(1, Math.min(max, Math.floor(value)));
372
+ }
373
+ export function parseAgentEventRetryAfterMs(input) {
374
+ if (input == null || input === '')
375
+ return null;
376
+ const value = Number(input);
377
+ if (!Number.isFinite(value) || value < 0)
378
+ throw new Error('invalid_agent_event_retry_after_ms');
379
+ return Math.floor(value);
380
+ }
381
+ export function buildAgentEventFetchUri(eventId) {
382
+ return `/v1/agent-events/${normalizeText(eventId)}`;
383
+ }
384
+ export const GATE_ANCHOR_TYPES = ['crm_message_id', 'call_intent_id', 'system_event_id'];
385
+ export const MEETING_MODALITIES = ['phone', 'zoom'];
386
+ export const MEETING_NEGOTIATION_ACTIONS = ['propose', 'reschedule', 'commit', 'cancel'];
387
+ export const MEETING_PROPOSAL_APPROVAL_KINDS = ['select', 'approve', 'reject'];
388
+ const MEETING_EXECUTION_OPERATIONS = [
389
+ 'schedule_zoom',
390
+ 'schedule_phone',
391
+ 'change_zoom',
392
+ 'change_phone',
393
+ 'cancel_zoom',
394
+ 'cancel_phone',
395
+ ];
396
+ function toNullableInt(input) {
397
+ if (input == null || input === '')
398
+ return null;
399
+ const value = Number(input);
400
+ if (!Number.isFinite(value))
401
+ return null;
402
+ return Math.floor(value);
403
+ }
404
+ function toNullableBoolean(input) {
405
+ if (input === true)
406
+ return true;
407
+ if (input === false)
408
+ return false;
409
+ return null;
410
+ }
411
+ export function normalizeGateAnchor(input) {
412
+ if (!isPlainObject(input))
413
+ return { ok: false, reason: 'missing_anchor' };
414
+ const type = normalizeText(input.type);
415
+ const id = normalizeText(input.id);
416
+ if (!type && !id)
417
+ return { ok: false, reason: 'missing_anchor' };
418
+ if (!type || !id || !GATE_ANCHOR_TYPES.includes(type)) {
419
+ return {
420
+ ok: false,
421
+ reason: 'invalid_anchor',
422
+ detail: {
423
+ received_type: type || null,
424
+ received_id: id || null,
425
+ },
426
+ };
427
+ }
428
+ return { ok: true, anchor: { type: type, id } };
429
+ }
430
+ export function normalizeMeetingCommitToken(input) {
431
+ if (!isPlainObject(input)) {
432
+ return {
433
+ ok: false,
434
+ reason: 'missing_commit_token',
435
+ missing_fields: ['commit_token'],
436
+ detail: {
437
+ received_type: input == null ? 'null' : (Array.isArray(input) ? 'array' : typeof input),
438
+ },
439
+ };
440
+ }
441
+ const ticketId = normalizeText(input.ticket_id || input.id);
442
+ const scenario = normalizeText(input.scenario).toLowerCase();
443
+ const missingFields = [];
444
+ if (!ticketId)
445
+ missingFields.push('commit_token.ticket_id');
446
+ if (!scenario)
447
+ missingFields.push('commit_token.scenario');
448
+ let anchor = null;
449
+ if ((input.anchor ?? null) !== null) {
450
+ const anchorResult = normalizeGateAnchor(input.anchor);
451
+ if (!anchorResult.ok) {
452
+ return {
453
+ ok: false,
454
+ reason: anchorResult.reason === 'missing_anchor' ? 'missing_commit_token' : 'invalid_commit_token',
455
+ missing_fields: ['commit_token.anchor.type', 'commit_token.anchor.id'],
456
+ detail: anchorResult.detail,
457
+ };
458
+ }
459
+ anchor = anchorResult.anchor;
460
+ }
461
+ if (missingFields.length > 0) {
462
+ return {
463
+ ok: false,
464
+ reason: 'invalid_commit_token',
465
+ missing_fields: Array.from(new Set(missingFields)),
466
+ };
467
+ }
468
+ return {
469
+ ok: true,
470
+ token: {
471
+ ticket_id: ticketId,
472
+ scenario,
473
+ status: normalizeText(input.status) || null,
474
+ version: toNullableInt(input.version),
475
+ anchor,
476
+ left_committed: toNullableBoolean(input.left_committed),
477
+ right_committed: toNullableBoolean(input.right_committed),
478
+ },
479
+ };
480
+ }
481
+ export function buildMeetingCommitToken(input) {
482
+ const ticket = isPlainObject(input.ticket) ? input.ticket : null;
483
+ if (!ticket)
484
+ return null;
485
+ const ticketId = normalizeText(ticket.ticket_id || ticket.id);
486
+ const scenario = (normalizeText(ticket.scenario) || normalizeText(input.fallback_scenario)).toLowerCase();
487
+ if (!ticketId || !scenario)
488
+ return null;
489
+ let anchor = null;
490
+ if ((ticket.anchor ?? null) !== null) {
491
+ const anchorResult = normalizeGateAnchor(ticket.anchor);
492
+ if (!anchorResult.ok)
493
+ return null;
494
+ anchor = anchorResult.anchor;
495
+ }
496
+ else if (input.fallback_anchor) {
497
+ anchor = input.fallback_anchor;
498
+ }
499
+ return {
500
+ ticket_id: ticketId,
501
+ scenario,
502
+ status: normalizeText(ticket.status) || null,
503
+ version: toNullableInt(ticket.version),
504
+ anchor,
505
+ left_committed: toNullableBoolean(ticket.left_committed),
506
+ right_committed: toNullableBoolean(ticket.right_committed),
507
+ };
508
+ }
509
+ function normalizeMeetingProposalApprovalKind(input) {
510
+ const value = normalizeText(input).toLowerCase();
511
+ return MEETING_PROPOSAL_APPROVAL_KINDS.includes(value)
512
+ ? value
513
+ : '';
514
+ }
515
+ export function normalizeMeetingProposalApprovalRef(input) {
516
+ if (!isPlainObject(input))
517
+ return null;
518
+ const approvalId = normalizeText(input.approval_id || input.id);
519
+ const proposalId = normalizeText(input.proposal_id);
520
+ const pairingId = normalizeText(input.pairing_id);
521
+ const approvalKind = normalizeMeetingProposalApprovalKind(input.approval_kind);
522
+ const sourceAgentId = normalizeText(input.source_agent_id);
523
+ const sourceMessageId = normalizeText(input.source_message_id);
524
+ const responseText = normalizeText(input.response_text);
525
+ const selectedOptionKey = normalizeText(input.selected_option_key) || null;
526
+ const slotKey = normalizeText(input.slot_key) || null;
527
+ if (!approvalId || !proposalId || !pairingId || !approvalKind || !sourceAgentId || !sourceMessageId || !responseText) {
528
+ return null;
529
+ }
530
+ return {
531
+ approval_id: approvalId,
532
+ proposal_id: proposalId,
533
+ pairing_id: pairingId,
534
+ approval_kind: approvalKind,
535
+ source_agent_id: sourceAgentId,
536
+ source_message_id: sourceMessageId,
537
+ response_text: responseText,
538
+ selected_option_key: selectedOptionKey,
539
+ slot_key: slotKey,
540
+ };
541
+ }
542
+ export function normalizeMeetingCommitAuthorityRef(input) {
543
+ if (!isPlainObject(input))
544
+ return null;
545
+ const pairingId = normalizeText(input.pairing_id);
546
+ const scenario = normalizeText(input.scenario).toLowerCase();
547
+ const modality = normalizeText(input.modality).toLowerCase();
548
+ const negotiationKey = normalizeText(input.negotiation_key);
549
+ const negotiationVersion = toNullableInt(input.negotiation_version);
550
+ const proposalId = normalizeText(input.proposal_id) || null;
551
+ const slotKey = normalizeText(input.slot_key);
552
+ const slotStartAt = normalizeText(input.slot_start_at) || null;
553
+ const slotEndAt = normalizeText(input.slot_end_at) || null;
554
+ const timezone = normalizeText(input.timezone) || null;
555
+ const durationMinutes = toNullableInt(input.duration_minutes);
556
+ const sourceAgentId = normalizeText(input.source_agent_id);
557
+ const targetAgentId = normalizeText(input.target_agent_id);
558
+ const sourceMessageId = normalizeText(input.source_message_id);
559
+ const targetMessageId = normalizeText(input.target_message_id);
560
+ if (!pairingId
561
+ || !scenario
562
+ || !MEETING_MODALITIES.includes(modality)
563
+ || !negotiationKey
564
+ || negotiationVersion == null
565
+ || !slotKey
566
+ || !sourceAgentId
567
+ || !targetAgentId
568
+ || !sourceMessageId
569
+ || !targetMessageId) {
570
+ return null;
571
+ }
572
+ return {
573
+ pairing_id: pairingId,
574
+ scenario,
575
+ modality: modality,
576
+ negotiation_key: negotiationKey,
577
+ negotiation_version: negotiationVersion,
578
+ proposal_id: proposalId,
579
+ slot_key: slotKey,
580
+ slot_start_at: slotStartAt,
581
+ slot_end_at: slotEndAt,
582
+ timezone,
583
+ duration_minutes: durationMinutes,
584
+ source_agent_id: sourceAgentId,
585
+ target_agent_id: targetAgentId,
586
+ source_message_id: sourceMessageId,
587
+ target_message_id: targetMessageId,
588
+ };
589
+ }
590
+ export function normalizeMeetingAuthorityBindingRef(input) {
591
+ if (!isPlainObject(input))
592
+ return null;
593
+ const authorityBindingId = normalizeText(input.authority_binding_id || input.binding_id || input.id);
594
+ const pairingId = normalizeText(input.pairing_id);
595
+ const proposalId = normalizeText(input.proposal_id);
596
+ const proposalApprovalId = normalizeText(input.proposal_approval_id);
597
+ const commitAuthorityId = normalizeText(input.commit_authority_id);
598
+ const negotiationKey = normalizeText(input.negotiation_key);
599
+ const negotiationVersion = toNullableInt(input.negotiation_version);
600
+ const slotKey = normalizeText(input.slot_key);
601
+ const sourceAgentId = normalizeText(input.source_agent_id);
602
+ const targetAgentId = normalizeText(input.target_agent_id);
603
+ const sourceMessageId = normalizeText(input.source_message_id);
604
+ const targetMessageId = normalizeText(input.target_message_id);
605
+ if (!authorityBindingId
606
+ || !pairingId
607
+ || !proposalId
608
+ || !proposalApprovalId
609
+ || !commitAuthorityId
610
+ || !negotiationKey
611
+ || negotiationVersion == null
612
+ || !slotKey
613
+ || !sourceAgentId
614
+ || !targetAgentId
615
+ || !sourceMessageId
616
+ || !targetMessageId) {
617
+ return null;
618
+ }
619
+ return {
620
+ authority_binding_id: authorityBindingId,
621
+ pairing_id: pairingId,
622
+ proposal_id: proposalId,
623
+ proposal_approval_id: proposalApprovalId,
624
+ commit_authority_id: commitAuthorityId,
625
+ negotiation_key: negotiationKey,
626
+ negotiation_version: negotiationVersion,
627
+ slot_key: slotKey,
628
+ source_agent_id: sourceAgentId,
629
+ target_agent_id: targetAgentId,
630
+ source_message_id: sourceMessageId,
631
+ target_message_id: targetMessageId,
632
+ };
633
+ }
634
+ export function normalizeMeetingExecutionTypedRefs(input) {
635
+ if (!isPlainObject(input))
636
+ return null;
637
+ const proposalId = normalizeText(input.proposal_id);
638
+ const proposalApprovalId = normalizeText(input.proposal_approval_id);
639
+ const commitAuthorityId = normalizeText(input.commit_authority_id);
640
+ const authorityBindingId = normalizeText(input.authority_binding_id);
641
+ if (!proposalId || !proposalApprovalId || !commitAuthorityId || !authorityBindingId)
642
+ return null;
643
+ const proposalApprovalRef = input.proposal_approval_ref == null
644
+ ? null
645
+ : normalizeMeetingProposalApprovalRef(input.proposal_approval_ref);
646
+ const commitAuthorityRef = input.commit_authority_ref == null
647
+ ? null
648
+ : normalizeMeetingCommitAuthorityRef(input.commit_authority_ref);
649
+ const authorityBindingRef = input.authority_binding_ref == null
650
+ ? null
651
+ : normalizeMeetingAuthorityBindingRef(input.authority_binding_ref);
652
+ if (input.proposal_approval_ref != null && !proposalApprovalRef)
653
+ return null;
654
+ if (input.commit_authority_ref != null && !commitAuthorityRef)
655
+ return null;
656
+ if (input.authority_binding_ref != null && !authorityBindingRef)
657
+ return null;
658
+ return {
659
+ proposal_id: proposalId,
660
+ proposal_approval_id: proposalApprovalId,
661
+ commit_authority_id: commitAuthorityId,
662
+ authority_binding_id: authorityBindingId,
663
+ proposal_approval_ref: proposalApprovalRef,
664
+ commit_authority_ref: commitAuthorityRef,
665
+ authority_binding_ref: authorityBindingRef,
666
+ };
667
+ }
668
+ export function normalizeMeetingExecutionCommand(input) {
669
+ if (!isPlainObject(input))
670
+ return null;
671
+ const executionId = normalizeText(input.execution_id);
672
+ const outboxId = normalizeText(input.outbox_id);
673
+ const negotiationId = normalizeText(input.negotiation_id);
674
+ const negotiationKey = normalizeText(input.negotiation_key);
675
+ const pairingId = normalizeText(input.pairing_id);
676
+ const scenario = normalizeText(input.scenario).toLowerCase();
677
+ const modality = normalizeText(input.modality).toLowerCase();
678
+ const operation = normalizeText(input.operation).toLowerCase();
679
+ const sourceAgentId = normalizeText(input.source_agent_id);
680
+ const targetAgentId = normalizeText(input.target_agent_id);
681
+ const payload = isPlainObject(input.payload) ? { ...input.payload } : null;
682
+ const participantAgentIds = normalizeStringArray(input.participant_agent_ids, 100);
683
+ const taskRefIds = normalizeStringArray(input.task_ref_ids, 100);
684
+ const needRefIds = normalizeStringArray(input.need_ref_ids, 100);
685
+ if (!executionId
686
+ || !outboxId
687
+ || !negotiationId
688
+ || !negotiationKey
689
+ || !pairingId
690
+ || !scenario
691
+ || !MEETING_MODALITIES.includes(modality)
692
+ || !MEETING_EXECUTION_OPERATIONS.includes(operation)
693
+ || !sourceAgentId
694
+ || !targetAgentId
695
+ || !payload) {
696
+ return null;
697
+ }
698
+ const commitTokenResult = input.commit_token == null ? null : normalizeMeetingCommitToken(input.commit_token);
699
+ if (input.commit_token != null && !(commitTokenResult && commitTokenResult.ok))
700
+ return null;
701
+ const typedRefs = input.typed_refs == null ? null : normalizeMeetingExecutionTypedRefs(input.typed_refs);
702
+ if (input.typed_refs != null && !typedRefs)
703
+ return null;
704
+ return {
705
+ execution_id: executionId,
706
+ outbox_id: outboxId,
707
+ negotiation_id: negotiationId,
708
+ negotiation_key: negotiationKey,
709
+ pairing_id: pairingId,
710
+ scenario,
711
+ modality: modality,
712
+ operation: operation,
713
+ source_agent_id: sourceAgentId,
714
+ target_agent_id: targetAgentId,
715
+ pairing_kind: normalizeText(input.pairing_kind) || null,
716
+ participant_agent_ids: participantAgentIds.length > 0 ? participantAgentIds : null,
717
+ task_ref_ids: taskRefIds.length > 0 ? taskRefIds : null,
718
+ need_ref_ids: needRefIds.length > 0 ? needRefIds : null,
719
+ commit_token: commitTokenResult && commitTokenResult.ok ? commitTokenResult.token : null,
720
+ authority_binding_id: normalizeText(input.authority_binding_id) || null,
721
+ typed_refs: typedRefs,
722
+ payload,
723
+ created_at: normalizeText(input.created_at) || null,
724
+ };
725
+ }
726
+ export function normalizeMeetingExecutionReceipt(input) {
727
+ if (!isPlainObject(input))
728
+ return null;
729
+ const executionId = normalizeText(input.execution_id);
730
+ const outboxId = normalizeText(input.outbox_id);
731
+ const status = normalizeText(input.status).toLowerCase();
732
+ if (!executionId || !outboxId || (status !== 'sent' && status !== 'failed'))
733
+ return null;
734
+ return {
735
+ execution_id: executionId,
736
+ outbox_id: outboxId,
737
+ status: status,
738
+ result: isPlainObject(input.result) ? { ...input.result } : null,
739
+ error: normalizeText(input.error) || null,
740
+ };
741
+ }