antenna-openclaw-plugin 1.2.10 → 1.2.12
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.
- package/index.ts +187 -3
- package/package.json +1 -1
- package/skills/antenna/EVENTS.md +96 -0
- package/skills/antenna/SKILL.md +44 -2
package/index.ts
CHANGED
|
@@ -640,7 +640,7 @@ export default function register(api: any) {
|
|
|
640
640
|
// ═══════════════════════════════════════════════════════════════════
|
|
641
641
|
api.registerTool({
|
|
642
642
|
name: "antenna_event_create",
|
|
643
|
-
description: "Create an event. Returns a shareable link (antenna.fyi/
|
|
643
|
+
description: "Create an event. Returns a shareable link (antenna.fyi/events/CODE) for participants to join.",
|
|
644
644
|
parameters: {
|
|
645
645
|
type: "object",
|
|
646
646
|
properties: {
|
|
@@ -653,6 +653,8 @@ export default function register(api: any) {
|
|
|
653
653
|
ends_at: { type: "string", description: "End time ISO" },
|
|
654
654
|
description: { type: "string", description: "Event description" },
|
|
655
655
|
og_image: { type: "string", description: "OG image URL for social sharing" },
|
|
656
|
+
requires_approval: { type: "boolean", description: "Require host approval to join (default false)" },
|
|
657
|
+
screening_questions: { type: "array", items: { type: "string" }, description: "Screening questions for applicants" },
|
|
656
658
|
},
|
|
657
659
|
required: ["name", "sender_id", "channel"],
|
|
658
660
|
},
|
|
@@ -669,6 +671,8 @@ export default function register(api: any) {
|
|
|
669
671
|
p_ends_at: params.ends_at || new Date(Date.now() + 12*60*60*1000).toISOString(),
|
|
670
672
|
p_description: params.description || null,
|
|
671
673
|
p_og_image: params.og_image || null,
|
|
674
|
+
p_requires_approval: params.requires_approval || false,
|
|
675
|
+
p_screening_questions: params.screening_questions || null,
|
|
672
676
|
});
|
|
673
677
|
if (error) return ok({ error: error.message });
|
|
674
678
|
return ok(data);
|
|
@@ -708,13 +712,16 @@ export default function register(api: any) {
|
|
|
708
712
|
// ═══════════════════════════════════════════════════════════════════
|
|
709
713
|
api.registerTool({
|
|
710
714
|
name: "antenna_event_join",
|
|
711
|
-
description: "Join an event by its code from the event URL.",
|
|
715
|
+
description: "Join an event by its code from the event URL. Auto-checks in if event has started and you're within 1km.",
|
|
712
716
|
parameters: {
|
|
713
717
|
type: "object",
|
|
714
718
|
properties: {
|
|
715
719
|
code: { type: "string", description: "Event code" },
|
|
716
720
|
sender_id: { type: "string" },
|
|
717
721
|
channel: { type: "string" },
|
|
722
|
+
lat: { type: "number", description: "Latitude (optional, for auto-checkin)" },
|
|
723
|
+
lng: { type: "number", description: "Longitude (optional, for auto-checkin)" },
|
|
724
|
+
application_context: { type: "string", description: "Application context from screening conversation" },
|
|
718
725
|
},
|
|
719
726
|
required: ["code", "sender_id", "channel"],
|
|
720
727
|
},
|
|
@@ -722,8 +729,64 @@ export default function register(api: any) {
|
|
|
722
729
|
const cfg = getConfig(api);
|
|
723
730
|
const supabase = getSupabase(cfg);
|
|
724
731
|
const deviceId = deriveDeviceId(params.sender_id, params.channel);
|
|
725
|
-
|
|
732
|
+
|
|
733
|
+
// Profile gate
|
|
734
|
+
const { data: profile } = await supabase.rpc("get_profile", { p_device_id: deviceId });
|
|
735
|
+
if (!profile) {
|
|
736
|
+
return ok({ joined: false, error: "Create a profile first before joining events" });
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
let lat = params.lat;
|
|
740
|
+
let lng = params.lng;
|
|
741
|
+
|
|
742
|
+
// Auto-read profile location if not provided
|
|
743
|
+
if (lat == null || lng == null) {
|
|
744
|
+
try {
|
|
745
|
+
const { data: loc } = await supabase.rpc("get_profile_location", { p_device_id: deviceId });
|
|
746
|
+
if (loc?.found) { lat = loc.lat; lng = loc.lng; }
|
|
747
|
+
} catch {}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const { data, error } = await supabase.rpc("join_event", { p_code: params.code, p_device_id: deviceId, p_application_context: params.application_context || null });
|
|
726
751
|
if (error) return ok({ error: error.message });
|
|
752
|
+
if (!data?.joined) return ok(data);
|
|
753
|
+
|
|
754
|
+
// Auto-checkin if event started and we have GPS
|
|
755
|
+
if (lat != null && lng != null) {
|
|
756
|
+
try {
|
|
757
|
+
const { data: evt } = await supabase.rpc("get_event", { p_code: params.code });
|
|
758
|
+
const startsAt = evt?.starts_at ? new Date(evt.starts_at) : null;
|
|
759
|
+
if (startsAt && startsAt <= new Date()) {
|
|
760
|
+
if (evt.lat != null && evt.lng != null) {
|
|
761
|
+
const R = 6371000;
|
|
762
|
+
const dLat = (evt.lat - lat) * Math.PI / 180;
|
|
763
|
+
const dLng = (evt.lng - lng) * Math.PI / 180;
|
|
764
|
+
const a = Math.sin(dLat/2)**2 + Math.cos(lat*Math.PI/180)*Math.cos(evt.lat*Math.PI/180)*Math.sin(dLng/2)**2;
|
|
765
|
+
const dist = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
|
766
|
+
if (dist <= 1000) {
|
|
767
|
+
const fuzzy = fuzzyCoords(lat, lng);
|
|
768
|
+
await supabase.rpc("event_checkin", { p_code: params.code, p_device_id: deviceId, p_lat: fuzzy.lat, p_lng: fuzzy.lng });
|
|
769
|
+
data.checked_in = true;
|
|
770
|
+
} else {
|
|
771
|
+
data.checked_in = false;
|
|
772
|
+
data.checkin_reason = "too far";
|
|
773
|
+
data.distance_m = Math.round(dist);
|
|
774
|
+
}
|
|
775
|
+
} else {
|
|
776
|
+
const fuzzy = fuzzyCoords(lat, lng);
|
|
777
|
+
await supabase.rpc("event_checkin", { p_code: params.code, p_device_id: deviceId, p_lat: fuzzy.lat, p_lng: fuzzy.lng });
|
|
778
|
+
data.checked_in = true;
|
|
779
|
+
}
|
|
780
|
+
} else {
|
|
781
|
+
data.checked_in = false;
|
|
782
|
+
data.checkin_reason = "event not started yet";
|
|
783
|
+
}
|
|
784
|
+
} catch {
|
|
785
|
+
data.checked_in = false;
|
|
786
|
+
data.checkin_reason = "checkin failed";
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
727
790
|
return ok(data);
|
|
728
791
|
},
|
|
729
792
|
});
|
|
@@ -943,6 +1006,127 @@ export default function register(api: any) {
|
|
|
943
1006
|
},
|
|
944
1007
|
});
|
|
945
1008
|
|
|
1009
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1010
|
+
// Tool: antenna_event_update
|
|
1011
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1012
|
+
api.registerTool({
|
|
1013
|
+
name: "antenna_event_update",
|
|
1014
|
+
description: "Update event info. Only the creator or co-host can update.",
|
|
1015
|
+
parameters: {
|
|
1016
|
+
type: "object",
|
|
1017
|
+
properties: {
|
|
1018
|
+
code: { type: "string", description: "Event code" },
|
|
1019
|
+
sender_id: { type: "string" },
|
|
1020
|
+
channel: { type: "string" },
|
|
1021
|
+
name: { type: "string", description: "New event name" },
|
|
1022
|
+
description: { type: "string", description: "New event description" },
|
|
1023
|
+
og_image: { type: "string", description: "New OG image URL" },
|
|
1024
|
+
lat: { type: "number", description: "New event latitude" },
|
|
1025
|
+
lng: { type: "number", description: "New event longitude" },
|
|
1026
|
+
starts_at: { type: "string", description: "New start time ISO" },
|
|
1027
|
+
ends_at: { type: "string", description: "New end time ISO" },
|
|
1028
|
+
},
|
|
1029
|
+
required: ["code", "sender_id", "channel"],
|
|
1030
|
+
},
|
|
1031
|
+
async execute(_id: string, params: any) {
|
|
1032
|
+
const cfg = getConfig(api);
|
|
1033
|
+
const supabase = getSupabase(cfg);
|
|
1034
|
+
const deviceId = deriveDeviceId(params.sender_id, params.channel);
|
|
1035
|
+
const { data, error } = await supabase.rpc("update_event", {
|
|
1036
|
+
p_code: params.code, p_device_id: deviceId,
|
|
1037
|
+
p_name: params.name || null, p_description: params.description || null,
|
|
1038
|
+
p_og_image: params.og_image || null, p_lat: params.lat || null, p_lng: params.lng || null,
|
|
1039
|
+
p_starts_at: params.starts_at || null, p_ends_at: params.ends_at || null,
|
|
1040
|
+
});
|
|
1041
|
+
if (error) return ok({ error: error.message });
|
|
1042
|
+
return ok(data);
|
|
1043
|
+
},
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1047
|
+
// Tool: antenna_event_approve
|
|
1048
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1049
|
+
api.registerTool({
|
|
1050
|
+
name: "antenna_event_approve",
|
|
1051
|
+
description: "Approve a pending participant. Only the creator or co-host can approve.",
|
|
1052
|
+
parameters: {
|
|
1053
|
+
type: "object",
|
|
1054
|
+
properties: {
|
|
1055
|
+
code: { type: "string", description: "Event code" },
|
|
1056
|
+
sender_id: { type: "string" },
|
|
1057
|
+
channel: { type: "string" },
|
|
1058
|
+
ref: { type: "string", description: "Ref number of the participant to approve" },
|
|
1059
|
+
},
|
|
1060
|
+
required: ["code", "sender_id", "channel", "ref"],
|
|
1061
|
+
},
|
|
1062
|
+
async execute(_id: string, params: any) {
|
|
1063
|
+
const cfg = getConfig(api);
|
|
1064
|
+
const supabase = getSupabase(cfg);
|
|
1065
|
+
const deviceId = deriveDeviceId(params.sender_id, params.channel);
|
|
1066
|
+
const { data, error } = await supabase.rpc("approve_participant", {
|
|
1067
|
+
p_code: params.code, p_device_id: deviceId, p_target_ref: params.ref,
|
|
1068
|
+
});
|
|
1069
|
+
if (error) return ok({ error: error.message });
|
|
1070
|
+
return ok(data);
|
|
1071
|
+
},
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1075
|
+
// Tool: antenna_event_reject
|
|
1076
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1077
|
+
api.registerTool({
|
|
1078
|
+
name: "antenna_event_reject",
|
|
1079
|
+
description: "Reject a pending participant. Only the creator or co-host can reject.",
|
|
1080
|
+
parameters: {
|
|
1081
|
+
type: "object",
|
|
1082
|
+
properties: {
|
|
1083
|
+
code: { type: "string", description: "Event code" },
|
|
1084
|
+
sender_id: { type: "string" },
|
|
1085
|
+
channel: { type: "string" },
|
|
1086
|
+
ref: { type: "string", description: "Ref number of the participant to reject" },
|
|
1087
|
+
},
|
|
1088
|
+
required: ["code", "sender_id", "channel", "ref"],
|
|
1089
|
+
},
|
|
1090
|
+
async execute(_id: string, params: any) {
|
|
1091
|
+
const cfg = getConfig(api);
|
|
1092
|
+
const supabase = getSupabase(cfg);
|
|
1093
|
+
const deviceId = deriveDeviceId(params.sender_id, params.channel);
|
|
1094
|
+
const { data, error } = await supabase.rpc("reject_participant", {
|
|
1095
|
+
p_code: params.code, p_device_id: deviceId, p_target_ref: params.ref,
|
|
1096
|
+
});
|
|
1097
|
+
if (error) return ok({ error: error.message });
|
|
1098
|
+
return ok(data);
|
|
1099
|
+
},
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1103
|
+
// Tool: antenna_event_add_host
|
|
1104
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1105
|
+
api.registerTool({
|
|
1106
|
+
name: "antenna_event_add_host",
|
|
1107
|
+
description: "Add a co-host to an event. Only the creator can add co-hosts.",
|
|
1108
|
+
parameters: {
|
|
1109
|
+
type: "object",
|
|
1110
|
+
properties: {
|
|
1111
|
+
code: { type: "string", description: "Event code" },
|
|
1112
|
+
sender_id: { type: "string" },
|
|
1113
|
+
channel: { type: "string" },
|
|
1114
|
+
ref: { type: "string", description: "Ref number of the participant to make co-host" },
|
|
1115
|
+
},
|
|
1116
|
+
required: ["code", "sender_id", "channel", "ref"],
|
|
1117
|
+
},
|
|
1118
|
+
async execute(_id: string, params: any) {
|
|
1119
|
+
const cfg = getConfig(api);
|
|
1120
|
+
const supabase = getSupabase(cfg);
|
|
1121
|
+
const deviceId = deriveDeviceId(params.sender_id, params.channel);
|
|
1122
|
+
const { data, error } = await supabase.rpc("add_cohost", {
|
|
1123
|
+
p_code: params.code, p_device_id: deviceId, p_target_ref: params.ref,
|
|
1124
|
+
});
|
|
1125
|
+
if (error) return ok({ error: error.message });
|
|
1126
|
+
return ok(data);
|
|
1127
|
+
},
|
|
1128
|
+
});
|
|
1129
|
+
|
|
946
1130
|
// ═══════════════════════════════════════════════════════════════════
|
|
947
1131
|
// Service: poll for new matches every 10 minutes → notify instantly
|
|
948
1132
|
// ═══════════════════════════════════════════════════════════════════
|
package/package.json
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: antenna-events
|
|
3
|
+
description: "Antenna Event Mode — create events, manage participants, GPS check-in. Use when a user wants to create an event, join an event, check in, scan event participants, or manage event settings."
|
|
4
|
+
tools:
|
|
5
|
+
- antenna_event_create
|
|
6
|
+
- antenna_event_join
|
|
7
|
+
- antenna_event_scan
|
|
8
|
+
- antenna_event_end
|
|
9
|
+
- antenna_event_checkin
|
|
10
|
+
- antenna_event_upload_image
|
|
11
|
+
- antenna_bind
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Antenna Event Mode
|
|
15
|
+
|
|
16
|
+
Create real-world events where everyone's AI agent handles the networking.
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
1. **Create**: `antenna_event_create(name, description)` → get shareable link
|
|
21
|
+
2. **Share**: Send `antenna.fyi/events/CODE` to attendees
|
|
22
|
+
3. **Join**: Attendees' agents call `antenna_event_join(code)`
|
|
23
|
+
4. **Check in**: At the venue, `antenna_event_checkin(code)` — GPS verified ≤1km
|
|
24
|
+
5. **Discover**: `antenna_event_scan(code)` — no distance limit inside events
|
|
25
|
+
|
|
26
|
+
## Tools
|
|
27
|
+
|
|
28
|
+
### `antenna_event_create`
|
|
29
|
+
Create an event. Returns a shareable link (antenna.fyi/events/CODE).
|
|
30
|
+
- `name`: event name
|
|
31
|
+
- `sender_id`, `channel`: from context
|
|
32
|
+
- `lat`, `lng`: optional event location
|
|
33
|
+
- `starts_at`, `ends_at`: optional time range (default: now to +12h)
|
|
34
|
+
- `description`: optional event description
|
|
35
|
+
- `og_image`: optional OG image URL for social sharing preview
|
|
36
|
+
|
|
37
|
+
**GPS flow for events:** If the user doesn't provide coordinates, generate a bind link (`antenna_bind` with `purpose="event"` and `event_code`) and ask them to open it at the event location. The GPS will update the event's coordinates, NOT the user's profile.
|
|
38
|
+
|
|
39
|
+
### `antenna_event_join`
|
|
40
|
+
Join an event by code. Auto-checks in if event already started and user GPS is within 1km.
|
|
41
|
+
- `code`: from the event URL (antenna.fyi/events/CODE)
|
|
42
|
+
- `sender_id`, `channel`: from context
|
|
43
|
+
- **Requires profile** — user must have a profile before joining
|
|
44
|
+
- If event has started + user has GPS + within 1km → auto check-in
|
|
45
|
+
|
|
46
|
+
### `antenna_event_scan`
|
|
47
|
+
Scan people in an event. No distance limit — returns all participants.
|
|
48
|
+
- `code`: event code
|
|
49
|
+
- `sender_id`, `channel`: from context
|
|
50
|
+
- Returns profiles with `checked_in` status and `role` (creator/participant)
|
|
51
|
+
- Header shows "X joined, Y checked in"
|
|
52
|
+
|
|
53
|
+
### `antenna_event_end`
|
|
54
|
+
End an event. Only the creator can end it.
|
|
55
|
+
- `code`: event code
|
|
56
|
+
- `sender_id`, `channel`: from context
|
|
57
|
+
|
|
58
|
+
### `antenna_event_checkin`
|
|
59
|
+
Check in at an event — marks you as present at the event location.
|
|
60
|
+
- `code`: event code
|
|
61
|
+
- `sender_id`, `channel`: from context
|
|
62
|
+
- `lat`, `lng`: optional GPS (auto-reads profile location if not provided)
|
|
63
|
+
- GPS verified: must be within 1km of event location
|
|
64
|
+
- Event must have GPS set for check-in to work
|
|
65
|
+
|
|
66
|
+
### `antenna_event_upload_image`
|
|
67
|
+
Upload an image for an event OG preview. Returns a public URL.
|
|
68
|
+
- `image_base64`: base64-encoded image data
|
|
69
|
+
- `content_type`: MIME type (default image/png)
|
|
70
|
+
- `event_code`: event code
|
|
71
|
+
|
|
72
|
+
### `antenna_bind` (for events)
|
|
73
|
+
Generate a GPS link for setting event location.
|
|
74
|
+
- `purpose`: set to `"event"`
|
|
75
|
+
- `event_code`: the event code
|
|
76
|
+
- GPS from this link writes to the event, not the user's profile
|
|
77
|
+
|
|
78
|
+
## Agent Behavior
|
|
79
|
+
|
|
80
|
+
### When someone says "create an event"
|
|
81
|
+
1. Ask for event name (required) and description (optional)
|
|
82
|
+
2. Call `antenna_event_create`
|
|
83
|
+
3. If no GPS provided, call `antenna_bind(purpose="event", event_code=CODE)` and send the link
|
|
84
|
+
4. Share the event URL with the user
|
|
85
|
+
|
|
86
|
+
### When someone shares an event link
|
|
87
|
+
1. Extract the code from `antenna.fyi/events/CODE`
|
|
88
|
+
2. Call `antenna_event_join(code)` — this will auto-check in if applicable
|
|
89
|
+
3. If join fails with "Create a profile first", guide profile creation then retry
|
|
90
|
+
|
|
91
|
+
### When someone says "who's here" at an event
|
|
92
|
+
1. Call `antenna_event_scan(code)`
|
|
93
|
+
2. Analyze profiles against what you know about the user
|
|
94
|
+
3. Recommend who they should meet and why
|
|
95
|
+
4. Creator appears with organizer badge
|
|
96
|
+
|
package/skills/antenna/SKILL.md
CHANGED
|
@@ -73,6 +73,24 @@ Scan for nearby people **and events**. Returns raw profile cards + active events
|
|
|
73
73
|
- `channel`: the channel name (telegram, whatsapp, discord, etc.)
|
|
74
74
|
- Returns `profiles` (nearby people) + `nearby_events` (active events with name, participants count, code)
|
|
75
75
|
|
|
76
|
+
**Location staleness:** Before scanning, check if the user's GPS is recent. If `last_seen_at` is older than 2 hours, prompt the user to update their location (`antenna_bind` or `antenna_checkin`). Stale GPS = wrong results.
|
|
77
|
+
|
|
78
|
+
## GPS Logic
|
|
79
|
+
|
|
80
|
+
**Profile GPS** — the user's location ("where am I")
|
|
81
|
+
- Updated via `antenna_bind(purpose="profile")` or `antenna_checkin`
|
|
82
|
+
- Fuzzy-hashed to ~150m for privacy
|
|
83
|
+
- Used for: `antenna_scan` (nearby people/events), `antenna_event_checkin` (distance check)
|
|
84
|
+
- Has `last_seen_at` timestamp. **Expires conceptually after 2h** — agent should prompt refresh
|
|
85
|
+
|
|
86
|
+
**Event GPS** — the event's location ("where is the event")
|
|
87
|
+
- Set via `antenna_bind(purpose="event")` or `antenna_event_create(lat, lng)`
|
|
88
|
+
- Precise coordinates (NOT blurred)
|
|
89
|
+
- Used for: check-in distance verification (≤1km), `nearby_events` discovery (5km)
|
|
90
|
+
- Does not expire — event location is fixed
|
|
91
|
+
|
|
92
|
+
**Relationship:** check-in = compare profile GPS vs event GPS. scan = use profile GPS to find nearby people + events.
|
|
93
|
+
|
|
76
94
|
After receiving the nearby profiles, **you decide** who to recommend:
|
|
77
95
|
- Use everything you know about the user: their SOUL.md, memory, recent conversations, interests, current mood
|
|
78
96
|
- Compare each nearby person's three-line card against your understanding of the user
|
|
@@ -277,7 +295,7 @@ Plugin 自带后台服务,每 10 分钟轮询一次 Supabase 查新的 mutual
|
|
|
277
295
|
用户不需要主动问,agent 会自动收到通知。
|
|
278
296
|
|
|
279
297
|
### `antenna_event_create`
|
|
280
|
-
Create an event. Returns a shareable link (antenna.fyi/
|
|
298
|
+
Create an event. Returns a shareable link (antenna.fyi/events/CODE).
|
|
281
299
|
- `name`: event name
|
|
282
300
|
- `sender_id`, `channel`: from context
|
|
283
301
|
- `lat`, `lng`: optional event location
|
|
@@ -294,7 +312,7 @@ End an event. Only the creator can end it.
|
|
|
294
312
|
|
|
295
313
|
### `antenna_event_join`
|
|
296
314
|
Join an event by code.
|
|
297
|
-
- `code`: from the event URL (antenna.fyi/
|
|
315
|
+
- `code`: from the event URL (antenna.fyi/events/CODE)
|
|
298
316
|
- `sender_id`, `channel`: from context
|
|
299
317
|
|
|
300
318
|
### `antenna_event_scan`
|
|
@@ -314,3 +332,27 @@ Upload an image for an event OG preview. Returns a public URL.
|
|
|
314
332
|
- `image_base64`: base64-encoded image data
|
|
315
333
|
- `content_type`: MIME type (default image/png)
|
|
316
334
|
- `event_code`: event code
|
|
335
|
+
|
|
336
|
+
### `antenna_event_update`
|
|
337
|
+
Update event info. Only creator or co-host can update.
|
|
338
|
+
- `code`: event code
|
|
339
|
+
- `sender_id`, `channel`: from context
|
|
340
|
+
- `name`, `description`, `og_image`, `lat`, `lng`, `starts_at`, `ends_at`: all optional, only provided fields are updated
|
|
341
|
+
|
|
342
|
+
### `antenna_event_approve`
|
|
343
|
+
Approve a pending participant. Only creator or co-host.
|
|
344
|
+
- `code`: event code
|
|
345
|
+
- `sender_id`, `channel`: from context
|
|
346
|
+
- `ref`: participant ref number from scan
|
|
347
|
+
|
|
348
|
+
### `antenna_event_reject`
|
|
349
|
+
Reject a pending participant. Only creator or co-host.
|
|
350
|
+
- `code`: event code
|
|
351
|
+
- `sender_id`, `channel`: from context
|
|
352
|
+
- `ref`: participant ref number from scan
|
|
353
|
+
|
|
354
|
+
### `antenna_event_add_host`
|
|
355
|
+
Add a co-host to the event. Only creator can add.
|
|
356
|
+
- `code`: event code
|
|
357
|
+
- `sender_id`, `channel`: from context
|
|
358
|
+
- `ref`: participant ref number to promote to co-host
|