@consiliency/agent-board-schema 1.2.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.
Files changed (92) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +11 -0
  3. package/README.md +55 -0
  4. package/bin/agent-board-schema.js +97 -0
  5. package/fixtures/already-applied.json +181 -0
  6. package/fixtures/divergent-history.json +173 -0
  7. package/fixtures/production-history.json +173 -0
  8. package/migrations/20260501000001_agent_board_schema_version.sql +12 -0
  9. package/migrations/20260502000000_agent_board_schema.sql +180 -0
  10. package/migrations/20260503000000_agent_board_rpcs.sql +422 -0
  11. package/migrations/20260503000001_agent_board_coordination_rpcs.sql +229 -0
  12. package/migrations/20260504000000_agent_board_read_models.sql +206 -0
  13. package/migrations/20260505000000_agent_board_inbox_schema.sql +341 -0
  14. package/migrations/20260506000000_agent_board_inbox_delivery_rpcs.sql +1200 -0
  15. package/migrations/20260506000001_agent_board_inbox_callback_rpcs.sql +330 -0
  16. package/migrations/20260507000000_agent_board_inbox_reads.sql +334 -0
  17. package/migrations/20260508000000_agent_board_callback_runtime.sql +453 -0
  18. package/migrations/20260508000001_agent_board_inbox_service_role_reads.sql +10 -0
  19. package/migrations/20260510000000_agent_board_dblint_repairs.sql +413 -0
  20. package/migrations/20260511000000_agent_board_auth_schema.sql +146 -0
  21. package/migrations/20260511000001_agent_board_auth_credentials.sql +39 -0
  22. package/migrations/20260512000000_agent_board_auth_provisioning_rpcs.sql +622 -0
  23. package/migrations/20260512000001_agent_board_auth_v1_rpcs.sql +798 -0
  24. package/migrations/20260512000002_agent_board_auth_v2_rpcs.sql +1243 -0
  25. package/migrations/20260512000003_agent_board_auth_rls.sql +484 -0
  26. package/migrations/20260513000000_agent_board_backup_ops.sql +34 -0
  27. package/migrations/20260513000001_agent_board_retention.sql +160 -0
  28. package/migrations/20260513000002_agent_board_monitoring_views.sql +227 -0
  29. package/migrations/20260514000000_agent_board_auth_rls_id_qualification.sql +150 -0
  30. package/migrations/20260515000000_agent_board_boardopt.sql +493 -0
  31. package/migrations/20260516000000_agent_board_callbackcap.sql +113 -0
  32. package/migrations/20260517000000_agent_board_addressing.sql +542 -0
  33. package/migrations/20260628000000_agent_board_signing_store.sql +174 -0
  34. package/migrations/20260628000001_agent_board_signing_proof_rpcs.sql +215 -0
  35. package/migrations/20260628000002_agent_board_signature_rls_reads.sql +300 -0
  36. package/migrations/20260628000003_agent_board_signed_write_gateway.sql +288 -0
  37. package/migrations/20260628000004_agent_board_fleet_registry.sql +411 -0
  38. package/migrations/20260628000005_agent_board_fleet_policy.sql +509 -0
  39. package/migrations/20260628000006_agent_board_fleet_read_models.sql +170 -0
  40. package/migrations/20260629000100_agent_board_fleet_registry_repair.sql +411 -0
  41. package/migrations/20260629000101_agent_board_fleet_policy_refresh.sql +509 -0
  42. package/migrations/20260629000102_agent_board_fleet_read_models_refresh.sql +170 -0
  43. package/migrations/20260630000100_agent_board_harness_kind_open_vocab.sql +15 -0
  44. package/migrations/20260710000000_agent_board_authbound_boundary.sql +155 -0
  45. package/migrations/20260710000100_agent_board_schema_version_rpc.sql +14 -0
  46. package/migrations/20260710000400_agent_board_nonfleet_identity.sql +87 -0
  47. package/migrations/20260710000401_agent_board_workload_providers.sql +39 -0
  48. package/migrations/20260711000000_agent_board_provision_system_fail_closed.sql +242 -0
  49. package/migrations/20260711000100_canary_signed_fleet_enforcement.sql +234 -0
  50. package/migrations/20260712000000_agent_board_bundle_endpoint_compat.sql +97 -0
  51. package/migrations/20260713000000_agent_board_rls_reassert_board_scoping.sql +90 -0
  52. package/package.json +42 -0
  53. package/provenance.json +580 -0
  54. package/schema-manifest.json +458 -0
  55. package/src/check.js +23 -0
  56. package/src/index.js +50 -0
  57. package/src/materialize.js +73 -0
  58. package/src/plan.js +44 -0
  59. package/src/tooling.test.mjs +97 -0
  60. package/tests/agent_board_addressing.test.sql +166 -0
  61. package/tests/agent_board_auth_rls.test.sql +243 -0
  62. package/tests/agent_board_auth_rls_id_qualification.test.sql +225 -0
  63. package/tests/agent_board_auth_rpcs.test.sql +311 -0
  64. package/tests/agent_board_auth_schema.test.sql +411 -0
  65. package/tests/agent_board_authbound_boundary.test.sql +148 -0
  66. package/tests/agent_board_boardopt.test.sql +170 -0
  67. package/tests/agent_board_bundle_endpoint_compat.test.sql +49 -0
  68. package/tests/agent_board_callback_runtime.test.sql +425 -0
  69. package/tests/agent_board_callbackcap.test.sql +222 -0
  70. package/tests/agent_board_canary_signed_fleet_enforcement.test.sql +60 -0
  71. package/tests/agent_board_dblint_rpcs.test.sql +247 -0
  72. package/tests/agent_board_fleet_policy.test.sql +370 -0
  73. package/tests/agent_board_fleet_read_models.test.sql +158 -0
  74. package/tests/agent_board_fleet_registry.test.sql +149 -0
  75. package/tests/agent_board_inbox_reads.test.sql +471 -0
  76. package/tests/agent_board_inbox_rpcs.test.sql +452 -0
  77. package/tests/agent_board_inbox_schema.test.sql +355 -0
  78. package/tests/agent_board_nonfleet_identity.test.sql +26 -0
  79. package/tests/agent_board_rls_reassert_board_scoping.test.sql +39 -0
  80. package/tests/agent_board_schema_version.test.sql +24 -0
  81. package/tests/agent_board_schema_version_rpc.test.sql +40 -0
  82. package/tests/agent_board_signature_rls_reads.test.sql +133 -0
  83. package/tests/agent_board_signed_write_gateway.test.sql +219 -0
  84. package/tests/agent_board_signing_proof_rpcs.test.sql +143 -0
  85. package/tests/agent_board_signing_store.test.sql +183 -0
  86. package/tests/agent_board_smoke.test.sql +12 -0
  87. package/tests/agent_board_v1_invariants.test.sql +298 -0
  88. package/tests/agent_board_v2_invariants.test.sql +753 -0
  89. package/tests/agent_board_workload_providers.test.sql +15 -0
  90. package/tests/fixtures/adopter-base.sql +19 -0
  91. package/tests/fixtures/operator-hardening.sql +27 -0
  92. package/tests/fixtures/test-prereqs.sql +84 -0
@@ -0,0 +1,542 @@
1
+ create or replace function agent_board._addressing_descriptors_array(p_descriptors jsonb)
2
+ returns jsonb
3
+ language sql
4
+ immutable
5
+ set search_path = ''
6
+ as $$
7
+ select case
8
+ when p_descriptors is null then '[]'::jsonb
9
+ when jsonb_typeof(p_descriptors) = 'array' then p_descriptors
10
+ else jsonb_build_array(p_descriptors)
11
+ end;
12
+ $$;
13
+
14
+ create or replace function agent_board._resolve_addressing_recipient_rows(
15
+ p_actor_agent_id uuid,
16
+ p_recipient_descriptors jsonb
17
+ )
18
+ returns table(
19
+ ordinal integer,
20
+ recipient_agent_id uuid,
21
+ handle text,
22
+ display_name text,
23
+ descriptor jsonb,
24
+ warning text,
25
+ denied_reason text
26
+ )
27
+ language plpgsql
28
+ security definer
29
+ set search_path = agent_board, public
30
+ as $$
31
+ declare
32
+ v_descriptor jsonb;
33
+ v_kind text;
34
+ v_index integer := 0;
35
+ v_match_count integer;
36
+ v_group_alias text;
37
+ v_role text;
38
+ begin
39
+ for v_descriptor in
40
+ select value
41
+ from jsonb_array_elements(agent_board._addressing_descriptors_array(p_recipient_descriptors))
42
+ loop
43
+ v_index := v_index + 1;
44
+ v_kind := v_descriptor ->> 'kind';
45
+
46
+ if v_kind = 'explicit_set' then
47
+ return query
48
+ select v_index * 100000 + nested.ordinal,
49
+ nested.recipient_agent_id,
50
+ nested.handle,
51
+ nested.display_name,
52
+ nested.descriptor,
53
+ nested.warning,
54
+ nested.denied_reason
55
+ from agent_board._resolve_addressing_recipient_rows(
56
+ p_actor_agent_id,
57
+ coalesce(v_descriptor -> 'recipients', '[]'::jsonb)
58
+ ) nested;
59
+ elsif v_kind = 'agent_id' then
60
+ select count(*) into v_match_count
61
+ from agent_board.agents a
62
+ where a.id = (v_descriptor ->> 'agentId')::uuid
63
+ and a.status = 'active';
64
+
65
+ if v_match_count = 1 then
66
+ return query
67
+ select v_index, a.id, a.handle, a.display_name, v_descriptor, null::text, null::text
68
+ from agent_board.agents a
69
+ where a.id = (v_descriptor ->> 'agentId')::uuid
70
+ and a.status = 'active';
71
+ else
72
+ return query select v_index, null::uuid, null::text, null::text, v_descriptor, null::text, 'unknown agent_id'::text;
73
+ end if;
74
+ elsif v_kind in ('agent_handle', 'human_handle') then
75
+ select count(*) into v_match_count
76
+ from agent_board.agents a
77
+ where a.handle = v_descriptor ->> 'handle'
78
+ and a.status = 'active'
79
+ and (
80
+ (v_kind = 'agent_handle' and a.agent_type <> 'human')
81
+ or (v_kind = 'human_handle' and a.agent_type = 'human')
82
+ );
83
+
84
+ if v_match_count = 1 then
85
+ return query
86
+ select v_index, a.id, a.handle, a.display_name, v_descriptor, null::text, null::text
87
+ from agent_board.agents a
88
+ where a.handle = v_descriptor ->> 'handle'
89
+ and a.status = 'active'
90
+ and (
91
+ (v_kind = 'agent_handle' and a.agent_type <> 'human')
92
+ or (v_kind = 'human_handle' and a.agent_type = 'human')
93
+ );
94
+ elsif v_match_count = 0 then
95
+ return query select v_index, null::uuid, null::text, null::text, v_descriptor, null::text, 'unknown handle'::text;
96
+ else
97
+ return query select v_index, null::uuid, null::text, null::text, v_descriptor, null::text, 'ambiguous handle'::text;
98
+ end if;
99
+ elsif v_kind = 'group_alias' then
100
+ v_group_alias := nullif(trim(v_descriptor ->> 'groupAlias'), '');
101
+ return query
102
+ select v_index,
103
+ a.id,
104
+ a.handle,
105
+ a.display_name,
106
+ v_descriptor,
107
+ null::text,
108
+ null::text
109
+ from agent_board.agents a
110
+ where a.status = 'active'
111
+ and (
112
+ a.metadata ->> 'groupAlias' = v_group_alias
113
+ or a.metadata ->> 'group_alias' = v_group_alias
114
+ or coalesce(a.metadata -> 'groupAliases', '[]'::jsonb) ? v_group_alias
115
+ or coalesce(a.metadata -> 'group_aliases', '[]'::jsonb) ? v_group_alias
116
+ )
117
+ order by a.handle, a.id;
118
+
119
+ if not found then
120
+ return query select v_index, null::uuid, null::text, null::text, v_descriptor, null::text, 'unknown group_alias'::text;
121
+ end if;
122
+ elsif v_kind = 'role_selector' then
123
+ v_role := nullif(trim(v_descriptor ->> 'role'), '');
124
+ return query
125
+ select v_index,
126
+ a.id,
127
+ a.handle,
128
+ a.display_name,
129
+ v_descriptor,
130
+ null::text,
131
+ null::text
132
+ from agent_board.agents a
133
+ where a.status = 'active'
134
+ and (
135
+ a.agent_type = v_role
136
+ or a.kind::text = v_role
137
+ or a.metadata ->> 'role' = v_role
138
+ or coalesce(a.metadata -> 'roles', '[]'::jsonb) ? v_role
139
+ or coalesce(a.metadata -> 'scopes', '[]'::jsonb) ? v_role
140
+ )
141
+ order by a.handle, a.id;
142
+
143
+ if not found then
144
+ return query select v_index, null::uuid, null::text, null::text, v_descriptor, null::text, 'unknown role_selector'::text;
145
+ end if;
146
+ else
147
+ return query select v_index, null::uuid, null::text, null::text, v_descriptor, null::text, 'unsupported descriptor kind'::text;
148
+ end if;
149
+ end loop;
150
+ end;
151
+ $$;
152
+
153
+ create or replace function agent_board.resolve_recipients(
154
+ p_actor_agent_id uuid default null,
155
+ p_recipient_descriptors jsonb default '[]'::jsonb
156
+ )
157
+ returns table("resolvedRecipients" jsonb, warnings jsonb, "deniedRecipients" jsonb, "idempotentThreadReuse" boolean)
158
+ language plpgsql
159
+ security definer
160
+ set search_path = agent_board, public
161
+ as $$
162
+ begin
163
+ return query
164
+ with resolved as (
165
+ select *
166
+ from agent_board._resolve_addressing_recipient_rows(p_actor_agent_id, p_recipient_descriptors)
167
+ ),
168
+ accepted as (
169
+ select distinct on (recipient_agent_id)
170
+ recipient_agent_id,
171
+ handle,
172
+ display_name,
173
+ descriptor,
174
+ ordinal
175
+ from resolved
176
+ where recipient_agent_id is not null
177
+ order by recipient_agent_id, ordinal
178
+ ),
179
+ ordered_accepted as (
180
+ select *
181
+ from accepted
182
+ order by ordinal, handle, recipient_agent_id
183
+ ),
184
+ duplicate_count as (
185
+ select greatest(count(*) - count(distinct recipient_agent_id), 0) as collapsed
186
+ from resolved
187
+ where recipient_agent_id is not null
188
+ )
189
+ select coalesce(
190
+ jsonb_agg(
191
+ jsonb_build_object(
192
+ 'agentId', ordered_accepted.recipient_agent_id::text,
193
+ 'handle', ordered_accepted.handle,
194
+ 'displayName', ordered_accepted.display_name,
195
+ 'descriptor', ordered_accepted.descriptor
196
+ )
197
+ order by ordered_accepted.ordinal, ordered_accepted.handle, ordered_accepted.recipient_agent_id
198
+ ) filter (where ordered_accepted.recipient_agent_id is not null),
199
+ '[]'::jsonb
200
+ ) as "resolvedRecipients",
201
+ case
202
+ when (select collapsed from duplicate_count) > 0
203
+ then jsonb_build_array((select collapsed::text || ' duplicate recipient(s) collapsed' from duplicate_count))
204
+ else '[]'::jsonb
205
+ end as warnings,
206
+ coalesce(
207
+ jsonb_agg(
208
+ jsonb_build_object('descriptor', denied.descriptor, 'reason', denied.denied_reason)
209
+ order by denied.ordinal
210
+ ) filter (where denied.denied_reason is not null),
211
+ '[]'::jsonb
212
+ ) as "deniedRecipients",
213
+ false as "idempotentThreadReuse"
214
+ from ordered_accepted
215
+ full join resolved denied on false;
216
+ end;
217
+ $$;
218
+
219
+ create or replace function agent_board.expand_recipients_dry_run(
220
+ p_actor_agent_id uuid default null,
221
+ p_recipient_descriptors jsonb default '[]'::jsonb,
222
+ p_thread_idempotency_key text default null
223
+ )
224
+ returns table("resolvedRecipients" jsonb, warnings jsonb, "deniedRecipients" jsonb, "idempotentThreadReuse" boolean)
225
+ language plpgsql
226
+ security definer
227
+ set search_path = agent_board, public
228
+ as $$
229
+ begin
230
+ return query
231
+ select r."resolvedRecipients",
232
+ r.warnings,
233
+ r."deniedRecipients",
234
+ exists (
235
+ select 1
236
+ from agent_board.threads t
237
+ where t.created_by_agent_id = coalesce(p_actor_agent_id, agent_board.current_agent_id())
238
+ and t.metadata ->> 'addressingThreadKey' = nullif(trim(p_thread_idempotency_key), '')
239
+ ) as "idempotentThreadReuse"
240
+ from agent_board.resolve_recipients(p_actor_agent_id, p_recipient_descriptors) r;
241
+ end;
242
+ $$;
243
+
244
+ create or replace function agent_board.create_or_find_thread(
245
+ p_created_by_agent_id uuid,
246
+ p_subject text,
247
+ p_idempotency_key text,
248
+ p_thread_type text default 'coordination',
249
+ p_metadata jsonb default '{}'::jsonb
250
+ )
251
+ returns table(thread_id uuid, thread_type text, subject text, status text, last_message_sequence bigint, created_at timestamptz, updated_at timestamptz, reused boolean)
252
+ language plpgsql
253
+ security definer
254
+ set search_path = agent_board, public
255
+ as $$
256
+ declare
257
+ v_actor_agent_id uuid;
258
+ v_key text := nullif(trim(p_idempotency_key), '');
259
+ v_thread agent_board.threads%rowtype;
260
+ begin
261
+ v_actor_agent_id := agent_board._resolved_actor_agent_id(p_created_by_agent_id, 'p_created_by_agent_id');
262
+ if nullif(trim(p_subject), '') is null or v_key is null then
263
+ raise exception 'subject and idempotency key are required' using errcode = '22023';
264
+ end if;
265
+
266
+ select *
267
+ into v_thread
268
+ from agent_board.threads t
269
+ where t.created_by_agent_id = v_actor_agent_id
270
+ and t.metadata ->> 'addressingThreadKey' = v_key
271
+ order by t.created_at desc
272
+ limit 1
273
+ for update;
274
+
275
+ if v_thread.id is not null then
276
+ return query select v_thread.id, v_thread.thread_type, v_thread.subject, v_thread.status, v_thread.last_message_sequence, v_thread.created_at, v_thread.updated_at, true;
277
+ return;
278
+ end if;
279
+
280
+ insert into agent_board.threads(thread_type, created_by_agent_id, subject, metadata)
281
+ values (
282
+ coalesce(nullif(trim(p_thread_type), ''), 'coordination'),
283
+ v_actor_agent_id,
284
+ trim(p_subject),
285
+ coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('addressingThreadKey', v_key)
286
+ )
287
+ returning * into v_thread;
288
+
289
+ return query select v_thread.id, v_thread.thread_type, v_thread.subject, v_thread.status, v_thread.last_message_sequence, v_thread.created_at, v_thread.updated_at, false;
290
+ end;
291
+ $$;
292
+
293
+ create or replace function agent_board._addressing_agent_ids_or_raise(
294
+ p_actor_agent_id uuid,
295
+ p_recipient_descriptors jsonb
296
+ )
297
+ returns uuid[]
298
+ language plpgsql
299
+ security definer
300
+ set search_path = agent_board, public
301
+ as $$
302
+ declare
303
+ v_result record;
304
+ v_ids uuid[];
305
+ begin
306
+ select * into v_result
307
+ from agent_board.resolve_recipients(p_actor_agent_id, p_recipient_descriptors);
308
+
309
+ if jsonb_array_length(v_result."deniedRecipients") > 0 then
310
+ raise exception 'recipient descriptor resolution failed' using errcode = '22023', detail = v_result."deniedRecipients"::text;
311
+ end if;
312
+
313
+ select array_agg((value ->> 'agentId')::uuid)
314
+ into v_ids
315
+ from jsonb_array_elements(v_result."resolvedRecipients") as value;
316
+
317
+ if v_ids is null or cardinality(v_ids) = 0 then
318
+ raise exception 'recipient descriptors resolved no recipients' using errcode = '22023';
319
+ end if;
320
+
321
+ return v_ids;
322
+ end;
323
+ $$;
324
+
325
+ drop function if exists agent_board.send_direct_message(uuid, uuid, jsonb, text, text, text, text, text, jsonb);
326
+ drop function if exists agent_board.send_direct_message(uuid, uuid, jsonb, text, text, text, text, text, text, jsonb);
327
+
328
+ create or replace function agent_board.send_direct_message(
329
+ p_thread_id uuid,
330
+ p_author_agent_id uuid,
331
+ p_recipient_descriptor jsonb,
332
+ p_addressing_mode text,
333
+ p_subject text,
334
+ p_body text,
335
+ p_message_type text,
336
+ p_priority text,
337
+ p_idempotency_key text,
338
+ p_metadata jsonb
339
+ )
340
+ returns table(message_id uuid, delivery_recipient_id uuid, inbox_item_id uuid, callback_outbox_count integer, created_at timestamptz)
341
+ language plpgsql
342
+ security definer
343
+ set search_path = agent_board, public
344
+ as $$
345
+ declare
346
+ v_recipients uuid[];
347
+ begin
348
+ if p_addressing_mode <> 'addressing_v1' then
349
+ raise exception 'invalid addressing mode' using errcode = '22023';
350
+ end if;
351
+ v_recipients := agent_board._addressing_agent_ids_or_raise(p_author_agent_id, jsonb_build_array(p_recipient_descriptor));
352
+ if cardinality(v_recipients) <> 1 then
353
+ raise exception 'direct message requires exactly one recipient' using errcode = '22023';
354
+ end if;
355
+
356
+ return query
357
+ select *
358
+ from agent_board.send_direct_message(
359
+ p_thread_id,
360
+ p_author_agent_id,
361
+ v_recipients[1],
362
+ p_subject,
363
+ p_body,
364
+ p_message_type,
365
+ p_priority,
366
+ p_idempotency_key,
367
+ p_metadata
368
+ );
369
+ end;
370
+ $$;
371
+
372
+ drop function if exists agent_board.send_multicast_message(uuid, uuid, jsonb, text, text, text, text, text, jsonb);
373
+ drop function if exists agent_board.send_multicast_message(uuid, uuid, jsonb, text, text, text, text, text, text, jsonb);
374
+
375
+ create or replace function agent_board.send_multicast_message(
376
+ p_thread_id uuid,
377
+ p_author_agent_id uuid,
378
+ p_recipient_descriptors jsonb,
379
+ p_addressing_mode text,
380
+ p_subject text,
381
+ p_body text,
382
+ p_message_type text,
383
+ p_priority text,
384
+ p_idempotency_key text,
385
+ p_metadata jsonb
386
+ )
387
+ returns table(message_id uuid, delivered_recipient_count integer, inbox_item_count integer, callback_outbox_count integer, created_at timestamptz)
388
+ language plpgsql
389
+ security definer
390
+ set search_path = agent_board, public
391
+ as $$
392
+ begin
393
+ if p_addressing_mode <> 'addressing_v1' then
394
+ raise exception 'invalid addressing mode' using errcode = '22023';
395
+ end if;
396
+
397
+ return query
398
+ select *
399
+ from agent_board.send_multicast_message(
400
+ p_thread_id,
401
+ p_author_agent_id,
402
+ agent_board._addressing_agent_ids_or_raise(p_author_agent_id, p_recipient_descriptors),
403
+ p_subject,
404
+ p_body,
405
+ p_message_type,
406
+ p_priority,
407
+ p_idempotency_key,
408
+ p_metadata
409
+ );
410
+ end;
411
+ $$;
412
+
413
+ drop function if exists agent_board.post_board_message(uuid, uuid, text, text, text, text, text, text, jsonb);
414
+ drop function if exists agent_board.post_board_message(uuid, uuid, text, text, text, text, text, text, text, jsonb);
415
+
416
+ create or replace function agent_board.post_board_message(
417
+ p_thread_id uuid,
418
+ p_author_agent_id uuid,
419
+ p_board_slug text,
420
+ p_addressing_mode text,
421
+ p_subject text,
422
+ p_body text,
423
+ p_message_type text,
424
+ p_priority text,
425
+ p_idempotency_key text,
426
+ p_metadata jsonb
427
+ )
428
+ returns table(message_id uuid, board_id uuid, delivered_recipient_count integer, callback_outbox_count integer, created_at timestamptz)
429
+ language plpgsql
430
+ security definer
431
+ set search_path = agent_board, public
432
+ as $$
433
+ declare
434
+ v_board_id uuid;
435
+ begin
436
+ if p_addressing_mode <> 'addressing_v1' then
437
+ raise exception 'invalid addressing mode' using errcode = '22023';
438
+ end if;
439
+
440
+ select b.id into v_board_id
441
+ from agent_board.boards b
442
+ where b.slug = nullif(trim(p_board_slug), '')
443
+ and b.status = 'active';
444
+ if v_board_id is null then
445
+ raise exception 'board slug not found' using errcode = 'P0002';
446
+ end if;
447
+
448
+ return query
449
+ select *
450
+ from agent_board.post_board_message(
451
+ p_thread_id,
452
+ p_author_agent_id,
453
+ v_board_id,
454
+ p_subject,
455
+ p_body,
456
+ p_message_type,
457
+ p_priority,
458
+ p_idempotency_key,
459
+ p_metadata
460
+ );
461
+ end;
462
+ $$;
463
+
464
+ drop function if exists agent_board.create_tasking_delivery(uuid, uuid, text, text, jsonb, text, text, text, text, jsonb);
465
+ drop function if exists agent_board.create_tasking_delivery(uuid, uuid, text, text, jsonb, text, text, text, text, text, jsonb);
466
+
467
+ create or replace function agent_board.create_tasking_delivery(
468
+ p_thread_id uuid,
469
+ p_created_by_agent_id uuid,
470
+ p_title text,
471
+ p_details text,
472
+ p_recipient_descriptors jsonb,
473
+ p_board_slug text,
474
+ p_addressing_mode text,
475
+ p_priority text,
476
+ p_orchestration_mode text,
477
+ p_idempotency_key text,
478
+ p_metadata jsonb
479
+ )
480
+ returns table(task_id uuid, created_event_id uuid, delivered_recipient_count integer, inbox_item_count integer, callback_outbox_count integer, created_at timestamptz, updated_at timestamptz)
481
+ language plpgsql
482
+ security definer
483
+ set search_path = agent_board, public
484
+ as $$
485
+ declare
486
+ v_recipient_ids uuid[];
487
+ v_board_id uuid;
488
+ begin
489
+ if p_addressing_mode <> 'addressing_v1' then
490
+ raise exception 'invalid addressing mode' using errcode = '22023';
491
+ end if;
492
+
493
+ if p_recipient_descriptors is not null then
494
+ v_recipient_ids := agent_board._addressing_agent_ids_or_raise(p_created_by_agent_id, p_recipient_descriptors);
495
+ end if;
496
+ if nullif(trim(p_board_slug), '') is not null then
497
+ select b.id into v_board_id
498
+ from agent_board.boards b
499
+ where b.slug = trim(p_board_slug)
500
+ and b.status = 'active';
501
+ if v_board_id is null then
502
+ raise exception 'board slug not found' using errcode = 'P0002';
503
+ end if;
504
+ end if;
505
+
506
+ return query
507
+ select result.task_id,
508
+ result.created_event_id,
509
+ result.delivered_recipient_count,
510
+ result.inbox_item_count,
511
+ result.callback_outbox_count,
512
+ result.created_at,
513
+ result.updated_at
514
+ from agent_board.create_tasking_delivery(
515
+ p_thread_id,
516
+ p_created_by_agent_id,
517
+ p_title,
518
+ p_details,
519
+ v_recipient_ids,
520
+ v_board_id,
521
+ p_priority,
522
+ p_orchestration_mode,
523
+ p_idempotency_key,
524
+ p_metadata
525
+ ) result;
526
+ end;
527
+ $$;
528
+
529
+ revoke all on function agent_board.resolve_recipients(uuid, jsonb) from public, anon;
530
+ revoke all on function agent_board.expand_recipients_dry_run(uuid, jsonb, text) from public, anon;
531
+ revoke all on function agent_board.create_or_find_thread(uuid, text, text, text, jsonb) from public, anon;
532
+ revoke all on function agent_board.send_direct_message(uuid, uuid, jsonb, text, text, text, text, text, text, jsonb) from public, anon;
533
+ revoke all on function agent_board.send_multicast_message(uuid, uuid, jsonb, text, text, text, text, text, text, jsonb) from public, anon;
534
+ revoke all on function agent_board.post_board_message(uuid, uuid, text, text, text, text, text, text, text, jsonb) from public, anon;
535
+ revoke all on function agent_board.create_tasking_delivery(uuid, uuid, text, text, jsonb, text, text, text, text, text, jsonb) from public, anon;
536
+ grant execute on function agent_board.resolve_recipients(uuid, jsonb) to authenticated, service_role;
537
+ grant execute on function agent_board.expand_recipients_dry_run(uuid, jsonb, text) to authenticated, service_role;
538
+ grant execute on function agent_board.create_or_find_thread(uuid, text, text, text, jsonb) to authenticated, service_role;
539
+ grant execute on function agent_board.send_direct_message(uuid, uuid, jsonb, text, text, text, text, text, text, jsonb) to authenticated, service_role;
540
+ grant execute on function agent_board.send_multicast_message(uuid, uuid, jsonb, text, text, text, text, text, text, jsonb) to authenticated, service_role;
541
+ grant execute on function agent_board.post_board_message(uuid, uuid, text, text, text, text, text, text, text, jsonb) to authenticated, service_role;
542
+ grant execute on function agent_board.create_tasking_delivery(uuid, uuid, text, text, jsonb, text, text, text, text, text, jsonb) to authenticated, service_role;