@canonmsg/backend-contracts 6.4.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,23 +29,11 @@
29
29
  * endpoints validate against these schemas directly).
30
30
  */
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.CANON_VERB_SCHEMA_REFS = exports.CANON_VERBS_JSON_SCHEMA = exports.VERB_SESSION_CONFIG_JSON_SCHEMA = exports.VERB_NATIVE_METADATA_JSON_SCHEMA = void 0;
32
+ exports.CANON_VERB_SCHEMA_REFS = exports.CANON_VERBS_JSON_SCHEMA = exports.VERB_NATIVE_METADATA_JSON_SCHEMA = void 0;
33
33
  exports.getVerbInputSchema = getVerbInputSchema;
34
34
  exports.getVerbResultSchema = getVerbResultSchema;
35
35
  const verbContract_js_1 = require("./verbContract.js");
36
36
  const REF = (def) => ({ $ref: `#/$defs/${def}` });
37
- const groupInviteRequirementsDef = {
38
- type: 'object',
39
- description: 'Independent gates on a pending group invite. policyApproval is social '
40
- + 'consent; ownerSessionSetup means the agent owner must choose the '
41
- + 'runtime session configuration before membership is activated.',
42
- required: ['policyApproval', 'ownerSessionSetup'],
43
- additionalProperties: false,
44
- properties: {
45
- policyApproval: { type: 'boolean' },
46
- ownerSessionSetup: { type: 'boolean' },
47
- },
48
- };
49
37
  const selfContextDef = {
50
38
  type: 'object',
51
39
  description: 'Private note-to-self attached to a cross-conversation send. Visible only to the '
@@ -315,50 +303,6 @@ exports.VERB_NATIVE_METADATA_JSON_SCHEMA = {
315
303
  },
316
304
  },
317
305
  };
318
- const sessionConfigValueDef = {
319
- type: 'string',
320
- pattern: verbContract_js_1.VERB_ID_PATTERNS.runtimeOptionValue,
321
- maxLength: verbContract_js_1.VERB_LIMITS.sessionConfigValueChars,
322
- };
323
- exports.VERB_SESSION_CONFIG_JSON_SCHEMA = {
324
- type: 'object',
325
- description: 'Typed setup policy for an agent target. Values are stable runtime-advertised '
326
- + 'option ids and are validated against the target descriptor before session creation; '
327
- + 'labels, prompts, workspace paths, and arbitrary fields are not permitted.',
328
- additionalProperties: false,
329
- properties: {
330
- model: sessionConfigValueDef,
331
- permissionMode: sessionConfigValueDef,
332
- effort: sessionConfigValueDef,
333
- workspaceId: {
334
- type: 'string',
335
- pattern: verbContract_js_1.VERB_ID_PATTERNS.workspaceOptionId,
336
- maxLength: verbContract_js_1.VERB_LIMITS.sessionConfigValueChars,
337
- },
338
- executionMode: { enum: ['worktree', 'locked'] },
339
- runtimeControlValues: {
340
- type: 'object',
341
- maxProperties: verbContract_js_1.VERB_LIMITS.sessionConfigValues,
342
- propertyNames: {
343
- pattern: verbContract_js_1.VERB_ID_PATTERNS.runtimeControlId,
344
- not: {
345
- enum: [
346
- 'model',
347
- 'workspace',
348
- 'executionMode',
349
- 'permissionMode',
350
- 'effort',
351
- 'interrupt',
352
- 'runtimeControlValues',
353
- 'updatedAt',
354
- 'updatedBy',
355
- ],
356
- },
357
- },
358
- additionalProperties: sessionConfigValueDef,
359
- },
360
- },
361
- };
362
306
  const timeoutFields = (maxMs, ceilingNote) => ({
363
307
  timeoutMs: {
364
308
  type: 'integer',
@@ -388,7 +332,7 @@ const send_to_input = {
388
332
  + 'sends -> admission resolve + create + send (the core reachOut composite). User '
389
333
  + 'targets resolve admission first: open targets get the message, approval-required '
390
334
  + 'targets get a contact request (send deferred and auto-fulfilled on approval), '
391
- + "owner-only targets surface as status 'unavailable' with reason owner-only.",
335
+ + "closed targets surface as status 'unavailable' with reason closed.",
392
336
  additionalProperties: false,
393
337
  properties: {
394
338
  targetConversationId: { type: 'string', pattern: verbContract_js_1.VERB_ID_PATTERNS.runtimeId },
@@ -412,11 +356,6 @@ const send_to_input = {
412
356
  + `truncate to ${verbContract_js_1.VERB_LIMITS.contactRequestNoteChars} chars.`,
413
357
  },
414
358
  sessionSelection: REF('sessionSelection'),
415
- sessionConfig: {
416
- oneOf: [REF('sessionConfig'), { type: 'null' }],
417
- description: 'Coding-agent session setup (model/permissionMode/effort/workspaceId/executionMode); '
418
- + 'only applied to agent targets, stripped for humans.',
419
- },
420
359
  messageOptions: REF('messageOptions'),
421
360
  },
422
361
  oneOf: [
@@ -843,11 +782,9 @@ const create_group_input = {
843
782
  description: "Create a group conversation. Each target's groupJoinPolicy is enforced "
844
783
  + 'server-side with staged admission: directly-addable members join at '
845
784
  + 'creation, approval-required members become pending group_invite '
846
- + 'requests; agents needing explicit group-session setup become pending '
847
- + 'owner requests; hard-denied members are skipped (see the result). A '
785
+ + 'requests; hard-denied members are skipped (see the result). A '
848
786
  + 'creator-only group is valid when at least one requested member has a '
849
- + 'pending invite. A creator that itself requires setup cannot create '
850
- + 'groups (403 CREATE_GROUP_CREATOR_SETUP_REQUIRED). Under MLS, membership '
787
+ + 'pending invite. Under MLS, membership '
851
788
  + 'changes are Add/Remove proposals + Commit — a group operation is a '
852
789
  + 'cryptographic state change, not a codec swap.',
853
790
  required: ['name', 'memberIds'],
@@ -866,8 +803,8 @@ const create_group_input = {
866
803
  const create_group_result = {
867
804
  type: 'object',
868
805
  description: 'Staged admission: the group exists with the directly-added members; '
869
- + '`pending` lists group_invite requests awaiting policy approval, owner '
870
- + 'session setup, or both; `skipped` lists hard-denied targets.',
806
+ + '`pending` lists group_invite requests awaiting policy approval; '
807
+ + '`skipped` lists hard-denied targets.',
871
808
  required: ['status', 'conversationId', 'added', 'pending', 'skipped'],
872
809
  additionalProperties: true,
873
810
  properties: {
@@ -881,12 +818,11 @@ const create_group_result = {
881
818
  type: 'array',
882
819
  items: {
883
820
  type: 'object',
884
- required: ['userId', 'requestId', 'requirements'],
821
+ required: ['userId', 'requestId'],
885
822
  additionalProperties: true,
886
823
  properties: {
887
824
  userId: { type: 'string' },
888
825
  requestId: { type: 'string' },
889
- requirements: REF('groupInviteRequirements'),
890
826
  },
891
827
  },
892
828
  },
@@ -906,8 +842,8 @@ const create_group_result = {
906
842
  };
907
843
  const add_member_input = {
908
844
  type: 'object',
909
- description: 'A target needing policy approval and/or explicit owner session setup '
910
- + 'yields one pending group_invite. Under MLS an add is an Add proposal '
845
+ description: 'A target needing policy approval yields one pending group_invite. '
846
+ + 'Under MLS an add is an Add proposal '
911
847
  + '+ Commit (new epoch), not a server-side membership write — the verb '
912
848
  + 'semantics are stable, the mechanism is not.',
913
849
  required: ['conversationId', 'userId'],
@@ -918,8 +854,7 @@ const add_member_input = {
918
854
  },
919
855
  };
920
856
  const add_member_result = {
921
- description: 'Targets needing policy approval and/or owner session setup yield one '
922
- + 'pending group_invite routed to the target or agent owner.',
857
+ description: 'Targets needing policy approval yield an exact pending group invite.',
923
858
  oneOf: [
924
859
  {
925
860
  type: 'object',
@@ -929,12 +864,11 @@ const add_member_result = {
929
864
  },
930
865
  {
931
866
  type: 'object',
932
- required: ['status', 'requestId', 'requirements'],
867
+ required: ['status', 'requestId'],
933
868
  additionalProperties: true,
934
869
  properties: {
935
870
  status: { const: 'pending' },
936
871
  requestId: { type: 'string' },
937
- requirements: REF('groupInviteRequirements'),
938
872
  },
939
873
  },
940
874
  ],
@@ -1001,72 +935,6 @@ const list_contacts_result = {
1001
935
  },
1002
936
  },
1003
937
  };
1004
- const list_contact_requests_input = {
1005
- type: 'object',
1006
- additionalProperties: false,
1007
- properties: {
1008
- direction: { enum: ['inbound', 'outbound'] },
1009
- includeResolved: { type: 'boolean' },
1010
- limit: { type: 'integer', minimum: 1, maximum: 100 },
1011
- },
1012
- };
1013
- const list_contact_requests_result = {
1014
- type: 'object',
1015
- description: 'Contact requests, newest first, capped at 100. Defaults to pending inbound; '
1016
- + 'requesters use direction=outbound with includeResolved=true to recover lifecycle state. '
1017
- + 'Items are SerializedContactRequest (backend-contracts contactRequest.ts).',
1018
- required: ['requests'],
1019
- additionalProperties: true,
1020
- properties: {
1021
- requests: {
1022
- type: 'array',
1023
- items: {
1024
- type: 'object',
1025
- required: ['id', 'requesterId', 'targetId', 'status', 'kind', 'phase'],
1026
- additionalProperties: true,
1027
- properties: {
1028
- id: { type: 'string' },
1029
- requesterId: { type: 'string' },
1030
- requesterName: { type: 'string' },
1031
- targetId: { type: 'string' },
1032
- status: { enum: ['pending', 'approved', 'rejected', 'expired', 'cancelled'] },
1033
- kind: { enum: ['dm', 'group_invite'] },
1034
- phase: {
1035
- enum: [
1036
- 'awaiting_owner',
1037
- 'starting',
1038
- 'connected',
1039
- 'rejected',
1040
- 'expired',
1041
- 'cancelled',
1042
- 'failed',
1043
- ],
1044
- },
1045
- message: { type: ['string', 'null'] },
1046
- createdAt: { type: ['string', 'null'] },
1047
- expiresAt: { type: ['string', 'null'] },
1048
- },
1049
- },
1050
- },
1051
- },
1052
- };
1053
- const cancel_contact_request_input = {
1054
- type: 'object',
1055
- required: ['requestId'],
1056
- additionalProperties: false,
1057
- properties: {
1058
- requestId: { type: 'string', pattern: verbContract_js_1.VERB_ID_PATTERNS.runtimeId },
1059
- },
1060
- };
1061
- const cancel_contact_request_result = {
1062
- type: 'object',
1063
- required: ['status', 'requestId'],
1064
- additionalProperties: true,
1065
- properties: {
1066
- status: { const: 'cancelled' },
1067
- requestId: { type: 'string' },
1068
- },
1069
- };
1070
938
  const list_conversations_input = {
1071
939
  type: 'object',
1072
940
  additionalProperties: false,
@@ -1160,7 +1028,6 @@ exports.CANON_VERBS_JSON_SCHEMA = {
1160
1028
  + 'deliberately NOT verbs — they stay host-mediated.',
1161
1029
  $defs: {
1162
1030
  messageId: messageIdDef,
1163
- groupInviteRequirements: groupInviteRequirementsDef,
1164
1031
  selfContext: selfContextDef,
1165
1032
  sessionSelection: sessionSelectionDef,
1166
1033
  mediaAttachment: mediaAttachmentDef,
@@ -1173,7 +1040,6 @@ exports.CANON_VERBS_JSON_SCHEMA = {
1173
1040
  sessionRule: sessionRuleDef,
1174
1041
  runtimeCard: runtimeCardDef,
1175
1042
  native: exports.VERB_NATIVE_METADATA_JSON_SCHEMA,
1176
- sessionConfig: exports.VERB_SESSION_CONFIG_JSON_SCHEMA,
1177
1043
  send_to_input,
1178
1044
  send_to_result,
1179
1045
  request_input_input,
@@ -1202,12 +1068,8 @@ exports.CANON_VERBS_JSON_SCHEMA = {
1202
1068
  leave_conversation_result,
1203
1069
  list_contacts_input,
1204
1070
  list_contacts_result,
1205
- list_contact_requests_input,
1206
- list_contact_requests_result,
1207
1071
  list_conversations_input,
1208
1072
  list_conversations_result,
1209
- cancel_contact_request_input,
1210
- cancel_contact_request_result,
1211
1073
  no_reply_input,
1212
1074
  no_reply_result,
1213
1075
  },
@@ -47,7 +47,6 @@ exports.VERB_WIRE_ENVELOPE_FIELDS = {
47
47
  'canonContactId',
48
48
  'sourceConversationId',
49
49
  'sessionSelection',
50
- 'sessionConfig',
51
50
  'idempotencyKey',
52
51
  'replyTo',
53
52
  'replyToPosition',
@@ -116,9 +115,7 @@ exports.VERB_WIRE_ENVELOPE_FIELDS = {
116
115
  optional: [],
117
116
  },
118
117
  list_contacts: { required: [], optional: [] },
119
- list_contact_requests: { required: [], optional: [] },
120
118
  list_conversations: { required: [], optional: ['limit'] },
121
- cancel_contact_request: { required: ['requestId'], optional: [] },
122
119
  no_reply: { required: [], optional: ['conversationId', 'messageId'] },
123
120
  };
124
121
  // ---------------------------------------------------------------------------
@@ -160,7 +157,6 @@ const wireTurnDef = {
160
157
  additionalProperties: false,
161
158
  properties: {
162
159
  turnId: { type: ['string', 'null'] },
163
- sourceMessageId: { type: 'string', minLength: 1 },
164
160
  turnSemantics: { enum: ['progress', 'turn_complete', 'control'] },
165
161
  deliveryIntent: { enum: ['queue', 'interrupt', 'interleave', 'stop'] },
166
162
  replyBehavior: { enum: ['allow_auto_reply', 'suppress_auto_reply'] },
@@ -208,9 +204,6 @@ const wireEnvelopeDef = {
208
204
  },
209
205
  ],
210
206
  },
211
- sessionConfig: {
212
- oneOf: [verbSchemas_js_1.VERB_SESSION_CONFIG_JSON_SCHEMA, { type: 'null' }],
213
- },
214
207
  idempotencyKey: {
215
208
  type: 'string',
216
209
  pattern: verbContract_js_1.VERB_ID_PATTERNS.runtimeId,
@@ -286,13 +279,7 @@ exports.CANON_VERB_WIRE_JSON_SCHEMA = {
286
279
  // ---------------------------------------------------------------------------
287
280
  // Intent <-> wire projection (json codec)
288
281
  // ---------------------------------------------------------------------------
289
- const TURN_KEYS = [
290
- 'turnId',
291
- 'sourceMessageId',
292
- 'turnSemantics',
293
- 'deliveryIntent',
294
- 'replyBehavior',
295
- ];
282
+ const TURN_KEYS = ['turnId', 'turnSemantics', 'deliveryIntent', 'replyBehavior'];
296
283
  function splitTurnMetadata(metadata) {
297
284
  if (!metadata || typeof metadata !== 'object')
298
285
  return { turn: undefined, rest: undefined };
@@ -350,7 +337,6 @@ function projectVerbIntentToWire(verb, intent, options) {
350
337
  canonContactId: input.canonContactId,
351
338
  sourceConversationId: input.sourceConversationId,
352
339
  sessionSelection: input.sessionSelection,
353
- sessionConfig: input.sessionConfig,
354
340
  idempotencyKey: messageOptions.messageId,
355
341
  replyTo: messageOptions.replyTo,
356
342
  replyToPosition: messageOptions.replyToPosition,
@@ -480,22 +466,10 @@ function projectVerbIntentToWire(verb, intent, options) {
480
466
  case 'list_contacts': {
481
467
  break;
482
468
  }
483
- case 'list_contact_requests': {
484
- value = compact({
485
- direction: input.direction,
486
- includeResolved: input.includeResolved,
487
- limit: input.limit,
488
- });
489
- break;
490
- }
491
469
  case 'list_conversations': {
492
470
  envelope = compact({ limit: input.limit });
493
471
  break;
494
472
  }
495
- case 'cancel_contact_request': {
496
- envelope = compact({ requestId: input.requestId });
497
- break;
498
- }
499
473
  case 'no_reply': {
500
474
  envelope = compact({ conversationId: input.conversationId, messageId: input.messageId });
501
475
  value = compact({ reason: input.reason });
@@ -541,7 +515,6 @@ function mergeVerbWireToIntent(request) {
541
515
  canonContactId: envelope.canonContactId,
542
516
  sourceConversationId: envelope.sourceConversationId,
543
517
  sessionSelection: envelope.sessionSelection,
544
- sessionConfig: envelope.sessionConfig,
545
518
  text: value.text,
546
519
  selfContext: value.selfContext,
547
520
  requestMessage: value.requestMessage,
@@ -635,16 +608,8 @@ function mergeVerbWireToIntent(request) {
635
608
  return compact({ conversationId: envelope.conversationId });
636
609
  case 'list_contacts':
637
610
  return {};
638
- case 'list_contact_requests':
639
- return compact({
640
- direction: value.direction,
641
- includeResolved: value.includeResolved,
642
- limit: value.limit,
643
- });
644
611
  case 'list_conversations':
645
612
  return compact({ limit: envelope.limit });
646
- case 'cancel_contact_request':
647
- return compact({ requestId: envelope.requestId });
648
613
  case 'no_reply':
649
614
  return compact({ conversationId: envelope.conversationId, messageId: envelope.messageId, reason: value.reason });
650
615
  }
@@ -0,0 +1,109 @@
1
+ /** The deliberately small policy vocabulary for principal communication. */
2
+ export type CommunicationRule = 'open' | 'approval-required' | 'closed';
3
+ /** Missing or invalid policy never widens access. */
4
+ export declare function readCommunicationRule(value: unknown): CommunicationRule;
5
+ /** Canon conversation selection is principal-neutral; a conversation is a runtime session boundary. */
6
+ export type DirectConversationSelection = {
7
+ mode: 'latest_or_new';
8
+ } | {
9
+ mode: 'new';
10
+ } | {
11
+ mode: 'specific';
12
+ conversationId: string;
13
+ };
14
+ export type CommunicateInput = {
15
+ action: 'message_existing';
16
+ conversationId: string;
17
+ text: string;
18
+ messageId?: string;
19
+ } | {
20
+ action: 'start_direct';
21
+ principalId: string;
22
+ text: string;
23
+ selection?: DirectConversationSelection;
24
+ messageId?: string;
25
+ } | {
26
+ action: 'create_group';
27
+ name: string;
28
+ memberIds: string[];
29
+ } | {
30
+ action: 'forward_message';
31
+ sourceConversationId: string;
32
+ targetConversationId: string;
33
+ messageId: string;
34
+ text?: string;
35
+ } | {
36
+ action: 'share_contact';
37
+ conversationId: string;
38
+ contactUserId: string;
39
+ text?: string;
40
+ messageId?: string;
41
+ } | {
42
+ action: 'manage_group_members';
43
+ conversationId: string;
44
+ userId: string;
45
+ operation: 'add' | 'remove';
46
+ };
47
+ export type CommunicateResult = {
48
+ status: 'messaged';
49
+ conversationId: string;
50
+ messageId: string;
51
+ created?: boolean;
52
+ reused?: boolean;
53
+ } | {
54
+ status: 'requested' | 'pending';
55
+ requestId: string;
56
+ } | {
57
+ status: 'created';
58
+ conversationId: string;
59
+ added: string[];
60
+ pending: Array<{
61
+ userId: string;
62
+ requestId: string;
63
+ }>;
64
+ skipped: Array<{
65
+ userId: string;
66
+ reason: string;
67
+ }>;
68
+ } | {
69
+ status: 'forwarded';
70
+ messageId: string;
71
+ targetConversationId: string;
72
+ } | {
73
+ status: 'shared';
74
+ conversationId: string;
75
+ messageId: string;
76
+ } | {
77
+ status: 'added' | 'removed';
78
+ conversationId: string;
79
+ userId: string;
80
+ } | {
81
+ status: 'approval_required';
82
+ reason: string;
83
+ } | {
84
+ status: 'blocked' | 'unavailable';
85
+ reason: string;
86
+ };
87
+ /** Principal-neutral app/SDK command. Humans may open a composer before sending. */
88
+ export interface StartDirectInput {
89
+ targetUserId: string;
90
+ opener?: {
91
+ text: string;
92
+ messageId?: string;
93
+ } | null;
94
+ selection?: DirectConversationSelection;
95
+ }
96
+ export type StartDirectResult = {
97
+ status: 'opened' | 'messaged';
98
+ conversationId: string;
99
+ messageId?: string;
100
+ created?: boolean;
101
+ reused?: boolean;
102
+ } | {
103
+ status: 'requested' | 'pending';
104
+ requestId: string;
105
+ } | {
106
+ status: 'blocked' | 'unavailable';
107
+ reason: string;
108
+ };
109
+ export declare function parseDirectConversationSelection(value: unknown): DirectConversationSelection;
@@ -0,0 +1,27 @@
1
+ /** Missing or invalid policy never widens access. */
2
+ export function readCommunicationRule(value) {
3
+ if (value === 'open' || value === 'approval-required' || value === 'closed') {
4
+ return value;
5
+ }
6
+ return 'approval-required';
7
+ }
8
+ export function parseDirectConversationSelection(value) {
9
+ if (value == null)
10
+ return { mode: 'latest_or_new' };
11
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
12
+ throw new Error('selection must be an object');
13
+ }
14
+ const record = value;
15
+ if (record.mode === 'latest_or_new' || record.mode === 'new') {
16
+ return { mode: record.mode };
17
+ }
18
+ if (record.mode === 'specific') {
19
+ const conversationId = typeof record.conversationId === 'string'
20
+ ? record.conversationId.trim()
21
+ : '';
22
+ if (!conversationId)
23
+ throw new Error('selection.conversationId is required');
24
+ return { mode: 'specific', conversationId };
25
+ }
26
+ throw new Error('selection.mode is invalid');
27
+ }
@@ -3,7 +3,7 @@ export declare function normalizeStoredString(value: unknown): string | null;
3
3
  /**
4
4
  * Firestore Timestamp-like -> ISO 8601, or null. Accepts only objects exposing
5
5
  * `toDate()`. A raw `Date` is deliberately NOT accepted: that matches both call
6
- * sites this replaced. `message.ts` and `contactRequest.ts` keep their own
6
+ * sites this replaced. `message.ts` keeps its own
7
7
  * Date-tolerant normalizers — a different contract, not this one.
8
8
  */
9
9
  export declare function firestoreTimestampToISOString(value: unknown): string | null;
@@ -10,7 +10,7 @@ export function normalizeStoredString(value) {
10
10
  /**
11
11
  * Firestore Timestamp-like -> ISO 8601, or null. Accepts only objects exposing
12
12
  * `toDate()`. A raw `Date` is deliberately NOT accepted: that matches both call
13
- * sites this replaced. `message.ts` and `contactRequest.ts` keep their own
13
+ * sites this replaced. `message.ts` keeps its own
14
14
  * Date-tolerant normalizers — a different contract, not this one.
15
15
  */
16
16
  export function firestoreTimestampToISOString(value) {
package/dist/index.d.ts CHANGED
@@ -8,12 +8,12 @@ export * from './runtimeCardStorage.js';
8
8
  export * from './turnProtocol.js';
9
9
  export * from './agentBehaviorPolicy.js';
10
10
  export * from './agentSearch.js';
11
- export * from './contactRequest.js';
12
11
  export * from './verbContract.js';
13
12
  export * from './verbSchemas.js';
14
13
  export * from './verbWire.js';
15
- export * from './accessPolicy.js';
14
+ export * from './communication.js';
16
15
  export * from './apiErrors.js';
17
16
  export * from './firestoreValues.js';
18
17
  export * from './moderation.js';
19
18
  export * from './selfContext.js';
19
+ export * from './replyAuthority.js';
package/dist/index.js CHANGED
@@ -8,12 +8,12 @@ export * from './runtimeCardStorage.js';
8
8
  export * from './turnProtocol.js';
9
9
  export * from './agentBehaviorPolicy.js';
10
10
  export * from './agentSearch.js';
11
- export * from './contactRequest.js';
12
11
  export * from './verbContract.js';
13
12
  export * from './verbSchemas.js';
14
13
  export * from './verbWire.js';
15
- export * from './accessPolicy.js';
14
+ export * from './communication.js';
16
15
  export * from './apiErrors.js';
17
16
  export * from './firestoreValues.js';
18
17
  export * from './moderation.js';
19
18
  export * from './selfContext.js';
19
+ export * from './replyAuthority.js';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Opaque, server-issued authority for one agent reply to one inbound message.
3
+ *
4
+ * The stream delivers this beside the triggering message. Runtimes keep it out
5
+ * of model-visible schemas and return it only on the ordinary reply path.
6
+ */
7
+ export interface AgentReplyAuthorityV1 {
8
+ schema: 'canon.agent-reply-authority.v1';
9
+ sourceMessageId: string;
10
+ token: string;
11
+ expiresAt: string;
12
+ }
@@ -0,0 +1 @@
1
+ export {};