antenna-openclaw-plugin 1.3.30 → 1.3.39
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 +390 -417
- package/openclaw.plugin.json +2 -2
- package/package.json +3 -3
- package/skills/antenna/EVENTS.md +163 -0
- package/skills/antenna/SKILL.md +237 -270
- package/migrations/drift_bottles.sql +0 -177
- package/tests/drift-bottle.test.ts +0 -109
package/skills/antenna/SKILL.md
CHANGED
|
@@ -1,368 +1,335 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: antenna
|
|
3
|
-
description: "
|
|
3
|
+
description: "Nearby people discovery via Antenna. Use when a user shares location, asks who's nearby, wants to set up their profile card, or interacts with match results. Handles location-based social discovery through the antenna_scan, antenna_profile, antenna_accept, antenna_check_matches, and antenna_bind tools."
|
|
4
4
|
metadata: { "openclaw": { "always": true } }
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Antenna -
|
|
7
|
+
# Antenna - Nearby People Discovery
|
|
8
8
|
|
|
9
|
-
Antenna
|
|
9
|
+
You have access to Antenna for location-based social discovery.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**How to call Antenna:**
|
|
12
|
+
- If you have Antenna plugin tools registered (antenna_scan, antenna_profile, etc.) - use them directly.
|
|
13
|
+
- If not, use CLI: `antenna <command> [flags]`. Example: `antenna scan --id <platform>:<user_id>`. The CLI supports all the same features.
|
|
14
|
+
- All tool names map to CLI commands: `antenna_scan` → `antenna scan`, `antenna_event_create` → `antenna event --create`, etc.
|
|
15
|
+
- **Always pass `chat_id`** when calling any Antenna tool. This is the chat/channel ID from your message context (e.g. Discord channel ID, Telegram chat ID). Antenna uses it to send you notifications about matches and event approvals.
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
- 📡 **附近扫描** - `antenna_scan`,基于 GPS 的周边发现
|
|
15
|
-
- 🌍 **全球推荐** - `antenna_discover`,每天 1 个最匹配的人
|
|
16
|
-
- 🔗 **Profile 链接** - 用户收到 `antenna.fyi/p/xxx` 链接,agent 读取后直接 accept
|
|
17
|
-
- 🎪 **活动** - `antenna_event_scan`,同一个活动里的人
|
|
17
|
+
## Onboarding - 装上之后主动引导
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Plugin 安装后,agent 应该**主动**开始引导,不要等用户问"怎么用"。
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- 如果有 Antenna plugin tools(antenna_scan, antenna_profile 等),直接用。
|
|
24
|
-
- 如果没有,用 CLI:`antenna <command> [flags]`。
|
|
25
|
-
- **所有 tool 必须传 `chat_id`**--Antenna 用它发通知。
|
|
26
|
-
|
|
27
|
-
## Onboarding - 装上后主动引导
|
|
28
|
-
|
|
29
|
-
Plugin 安装后,agent **主动**开始引导,不要等用户问。
|
|
30
|
-
|
|
31
|
-
**前置条件:** 用户需要先在 antenna.fyi 注册账号,从 Dashboard 获取 API key。如果没注册,引导去 antenna.fyi。
|
|
21
|
+
**前置条件:** 用户需要先在 antenna.fyi 注册账号,从 Dashboard (antenna.fyi/me) 获取 API key,然后把 key 交给 agent。如果用户还没注册,引导他们去 antenna.fyi 注册。
|
|
32
22
|
|
|
33
23
|
### 流程
|
|
34
24
|
|
|
35
|
-
|
|
36
|
-
> "嘿,你装了 Antenna
|
|
37
|
-
|
|
38
|
-
用户给了 API key 后,调 `antenna config --key <key>` 验证。这会返回 `user_id` 和 `device_id`。
|
|
39
|
-
|
|
40
|
-
**⚠️ 之后所有操作必须用 API key 验证返回的 device_id(格式 `user:xxx`)。不要自己拼 `channel:sender_id`。** 这样 agent 创建的 profile 才能在 dashboard 上显示。
|
|
25
|
+
**第一步:打招呼 + 解释**
|
|
26
|
+
> "嘿,你装了 Antenna--它能帮你发现附近有意思的人。先确认一下,你在 antenna.fyi 注册过了吗?拿到 API key 了吗?有了的话我帮你做张名片,然后看看附近有谁。"
|
|
41
27
|
|
|
42
28
|
**第二步:聊天收集 → 生成名片 → 确认**
|
|
43
29
|
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
- 从中提炼
|
|
30
|
+
Agent 跟用户聊几句,了解他们是谁、做什么、对什么感兴趣、想认识什么人。然后 agent 自己完成以下工作(不需要用户参与):
|
|
31
|
+
- 生成 matching_context(~200 字,用于 embedding 匹配,不展示给别人)
|
|
32
|
+
- 从中提炼 line1/2/3 + 选一个 emoji + display_name
|
|
47
33
|
|
|
48
|
-
|
|
34
|
+
然后展示名片预览给用户确认:
|
|
49
35
|
> 你的名片:
|
|
50
|
-
> Yi
|
|
36
|
+
> 🦦 Yi
|
|
51
37
|
> · Product Designer,做 AI 搜索体验
|
|
52
38
|
> · 对 AI agent、音乐、游泳感兴趣
|
|
53
39
|
> · 想认识做 AI 产品和独立创作的人
|
|
54
40
|
>
|
|
55
41
|
> 这样可以吗?要改哪里告诉我。
|
|
56
42
|
|
|
57
|
-
|
|
43
|
+
用户确认后才调 `antenna_profile(action="set")` 保存(matching_context + line1/2/3 + emoji + name 一起存)。
|
|
44
|
+
用户要改 → 改完重新预览 → 再确认。
|
|
58
45
|
|
|
59
|
-
|
|
46
|
+
**不要跳过确认。名片是展示给别人看的,必须让用户看过才存。**
|
|
60
47
|
|
|
61
|
-
|
|
62
|
-
> "你想填什么联系方式?这个只有双向匹配后才会展示给对方,不会公开。"
|
|
48
|
+
**第二步半:名片存好后,立刻推荐 2-3 个匹配的人**
|
|
63
49
|
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
名片保存成功后,**立刻**调 `antenna_discover` 获取 2-3 个全球推荐,让用户马上看到 Antenna 的价值:
|
|
51
|
+
> "名片存好了!我先帮你看看有谁跟你特别像——"
|
|
52
|
+
> (展示 2-3 个推荐 + 个性化匹配理由)
|
|
66
53
|
|
|
67
|
-
|
|
54
|
+
这一步让用户立刻体验到产品价值,不要跳过。
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
**第三步:推荐完后,立刻调 antenna_bind**
|
|
70
57
|
|
|
71
|
-
|
|
72
|
-
> "名片存好了!我先帮你看看有谁跟你特别像--"
|
|
58
|
+
**这一步是强制的。** 名片保存成功后,你**必须立刻**调用 `antenna_bind` 生成链接并发给用户。不要问用户要不要,不要等用户说什么,直接调。
|
|
73
59
|
|
|
74
|
-
|
|
60
|
+
调用 `antenna_bind` 生成链接,发给用户:
|
|
61
|
+
> "名片存好了 ✅ 点这个链接,在手机浏览器打开,允许定位就行:
|
|
62
|
+
> [链接]
|
|
63
|
+
> 我收到你的位置后会自动帮你看看附近有谁。"
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
备选:如果用户在 Telegram/WhatsApp 里,也可以直接发位置消息。但优先用链接。
|
|
77
66
|
|
|
78
|
-
|
|
79
|
-
> "这是你的公开名片链接:[public_url]
|
|
80
|
-
> 你可以把它发给别人,对方的 agent 看到链接就能直接 accept 你。
|
|
81
|
-
>
|
|
82
|
-
> Antenna 能帮你做这些事:
|
|
83
|
-
> 📡 **附近扫描** - 发位置或绑定 GPS,看看周围有没有有意思的人
|
|
84
|
-
> 🌍 **每日推荐** - 每天帮你找一个全球最像你的人
|
|
85
|
-
> 🔗 **名片链接** - 把你的链接发给任何人,对方 agent 看到就能 accept
|
|
86
|
-
> 🎪 **活动** - 创建或加入活动,认识同一个场景里的人
|
|
87
|
-
> 🍾 **漂流瓶** - 写一段话丢出去,随机一个陌生人会收到
|
|
88
|
-
>
|
|
89
|
-
> 想试哪个?"
|
|
90
|
-
|
|
91
|
-
**第五步:调 antenna_bind 获取 GPS 链接**
|
|
67
|
+
**⚠️ 如果你保存了名片但没有调 antenna_bind,你就没有完成 onboarding。**
|
|
92
68
|
|
|
93
|
-
|
|
94
|
-
> "点这个链接,在手机浏览器打开,允许定位就行:[链接]"
|
|
69
|
+
**第四步:设置匹配检查定时任务**
|
|
95
70
|
|
|
96
|
-
|
|
71
|
+
onboarding 完成后,帮用户设置一个每小时自动检查匹配的 cron 任务,这样有人 accept 用户时能及时通知。
|
|
97
72
|
|
|
98
|
-
|
|
73
|
+
如果你有 cron 能力(Hermes: `hermes cron`,OpenClaw: `openclaw cron`),创建一个定时任务:
|
|
74
|
+
- 每 1 小时调用 `antenna_check_matches`
|
|
75
|
+
- 如果有新的 mutual match 或 incoming accept,通知用户
|
|
76
|
+
- 如果没有新匹配,不打扰用户
|
|
99
77
|
|
|
100
|
-
|
|
78
|
+
示例(Hermes):
|
|
101
79
|
```
|
|
102
|
-
|
|
80
|
+
hermes cron add --every 1h --message "Check antenna matches: call antenna_check_matches. If there are new mutual matches or incoming accepts, tell the user. Also call antenna_discover once per day to get a global recommendation. If nothing new, reply HEARTBEAT_OK."
|
|
103
81
|
```
|
|
104
82
|
|
|
105
|
-
|
|
106
|
-
> "要我每天帮你找一个全球最像你的人吗?"
|
|
107
|
-
|
|
108
|
-
### Linking to antenna.fyi account
|
|
83
|
+
**第五步:问用户要不要全球推荐**
|
|
109
84
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
2. 调 `antenna_link_account(api_key = "ant_xxx")`
|
|
113
|
-
3. 确认:"关联成功!你现在可以在 dashboard 上看到完整的 profile 和匹配记录了。"
|
|
85
|
+
cron 设完后,问用户一句:
|
|
86
|
+
> "要我每天帮你找一个全球最像你的人吗?"
|
|
114
87
|
|
|
115
|
-
|
|
88
|
+
用户说要 → cron 每天调 `antenna_discover` 推送。
|
|
89
|
+
用户说不要 → 只在 scan 没人时 fallback。
|
|
116
90
|
|
|
117
|
-
|
|
91
|
+
**第六步:启动实时通知**
|
|
118
92
|
|
|
119
|
-
|
|
120
|
-
- 用户分享位置 → `antenna_scan`
|
|
121
|
-
- 用户问"附近有谁" → `antenna_scan`
|
|
122
|
-
- 用户收到 profile 链接(`antenna.fyi/p/xxx`)→ 读取 profile → 判断 → `antenna_accept`
|
|
123
|
-
- 用户想编辑名片 → `antenna_profile`
|
|
124
|
-
- 用户说 accept / skip → `antenna_accept` / `antenna_pass`
|
|
125
|
-
- 用户问匹配状态 → `antenna_check_matches`
|
|
93
|
+
onboarding 完成后,启动 `antenna watch` 后台进程,实时接收匹配通知和活动审批通知。
|
|
126
94
|
|
|
127
|
-
|
|
95
|
+
**判断方法(不要猜):**
|
|
96
|
+
1. 先试 `antenna status --id <device_id>` - 如果输出 "Watch: ✅ running",已经在跑,不需要再启动
|
|
97
|
+
2. 如果不在跑,试 `antenna watch --id <device_id> --push hermes,openclaw &` 启动后台进程
|
|
98
|
+
3. 如果 exec 报错(不支持后台进程),用 cron 替代:
|
|
128
99
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
100
|
+
Hermes cron:
|
|
101
|
+
```
|
|
102
|
+
hermes cron add --every 1h --message "Check antenna matches: call antenna_check_matches. If there are new mutual matches or incoming accepts, tell the user. If nothing new, reply HEARTBEAT_OK."
|
|
103
|
+
```
|
|
133
104
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
105
|
+
OpenClaw cron:
|
|
106
|
+
```
|
|
107
|
+
openclaw cron add --every 1h --message "Check antenna matches: call antenna_check_matches. If there are new mutual matches or incoming accepts, tell the user. If nothing new, reply HEARTBEAT_OK."
|
|
108
|
+
```
|
|
137
109
|
|
|
138
|
-
|
|
139
|
-
用户收到 `antenna.fyi/p/xxx` 链接时:
|
|
140
|
-
1. 用 `web_fetch` 读取页面--页面里有 `<script id="antenna-profile-data">` JSON,包含完整 profile
|
|
141
|
-
2. 读取 more_information、interest_tags、个人描述等
|
|
142
|
-
3. 结合你对用户的了解,判断是否推荐
|
|
143
|
-
4. 如果用户想 accept → 调 `antenna_accept(profile_slug="xxx")`
|
|
110
|
+
**优先级:** watch > cron。watch 是 2 分钟延迟,cron 是 1 小时。
|
|
144
111
|
|
|
145
|
-
|
|
112
|
+
## When to use
|
|
146
113
|
|
|
147
|
-
|
|
148
|
-
|
|
114
|
+
- **首次安装后**: 主动开始 onboarding(名片 → 位置)
|
|
115
|
+
- User shares a location (Telegram live location, WhatsApp pin, or tells you where they are)
|
|
116
|
+
- User asks "附近有谁" / "who's nearby" / "周围有什么人"
|
|
117
|
+
- User says "我想找一个 xxx 的人" / "find me someone who..."
|
|
118
|
+
- User wants to set up or edit their profile card (名片)
|
|
119
|
+
- User accepts or skips a match
|
|
120
|
+
- User asks about match status or wants to exchange contact info
|
|
149
121
|
|
|
150
122
|
## Tools
|
|
151
123
|
|
|
152
124
|
### `antenna_scan`
|
|
153
|
-
|
|
154
|
-
- `
|
|
155
|
-
- `
|
|
156
|
-
- `
|
|
157
|
-
-
|
|
158
|
-
-
|
|
125
|
+
Scan for nearby people **and events**. Returns raw profile cards + active events within 5km.
|
|
126
|
+
**Read-only - does NOT update your location.** To update location, use `antenna_checkin` or `antenna_bind`.
|
|
127
|
+
- `lat`, `lng`: coordinates (from `LocationLat`/`LocationLon` context, or geocoded from user input)
|
|
128
|
+
- `radius_m`: search radius in meters (default 500, max 1000) for people; events search uses 5km
|
|
129
|
+
- `sender_id`: the user's id from message context
|
|
130
|
+
- `channel`: the platform/channel name (any platform works: telegram, discord, whatsapp, webchat, signal, slack, matrix, clawx, etc.)
|
|
131
|
+
- Returns `profiles` (nearby people) + `nearby_events` (active events with name, participants count, code)
|
|
159
132
|
|
|
160
|
-
**GPS
|
|
133
|
+
**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.
|
|
134
|
+
|
|
135
|
+
## GPS Logic
|
|
136
|
+
|
|
137
|
+
**Profile GPS** - the user's location ("where am I")
|
|
138
|
+
- Updated via `antenna_bind(purpose="profile")` or `antenna_checkin`
|
|
139
|
+
- Location is never stored raw
|
|
140
|
+
- Used for: `antenna_scan` (nearby people/events), `antenna_event_checkin` (distance check)
|
|
141
|
+
- Has `last_seen_at` timestamp. **Expires conceptually after 2h** - agent should prompt refresh
|
|
142
|
+
|
|
143
|
+
**Event GPS** - the event's location ("where is the event")
|
|
144
|
+
- Set via `antenna_bind(purpose="event")` or `antenna_event_create(lat, lng)`
|
|
145
|
+
- Precise coordinates (NOT blurred)
|
|
146
|
+
- Used for: check-in distance verification (≤1km), `nearby_events` discovery (5km)
|
|
147
|
+
- Does not expire - event location is fixed
|
|
148
|
+
|
|
149
|
+
**Relationship:** check-in = compare profile GPS vs event GPS. scan = use profile GPS to find nearby people + events.
|
|
150
|
+
|
|
151
|
+
After receiving the nearby profiles, **you decide** who to recommend:
|
|
152
|
+
- Use everything you know about the user: their SOUL.md, memory, recent conversations, interests, current mood
|
|
153
|
+
- Compare each nearby person's three-line card against your understanding of the user
|
|
154
|
+
- Write a personalized match reason for each person you recommend
|
|
155
|
+
- Skip people who clearly aren't a match - don't recommend everyone
|
|
156
|
+
- If you're unsure, lean toward recommending (let the user decide)
|
|
161
157
|
|
|
162
158
|
### `antenna_profile`
|
|
163
|
-
|
|
164
|
-
- `action`:"get"
|
|
165
|
-
- `sender_id`, `channel
|
|
166
|
-
- "set"
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
- **
|
|
170
|
-
- **
|
|
171
|
-
- **
|
|
172
|
-
- **
|
|
173
|
-
- **
|
|
174
|
-
- **
|
|
159
|
+
View or update the user's name card.
|
|
160
|
+
- `action`: "get" or "set"
|
|
161
|
+
- `sender_id`, `channel`: from context
|
|
162
|
+
- For "set": `display_name`, `emoji`, `line1`, `line2`, `line3`, `visible`, `matching_context`
|
|
163
|
+
|
|
164
|
+
The name card has:
|
|
165
|
+
- **emoji**: a single emoji that represents them
|
|
166
|
+
- **display_name**: how they want to be called
|
|
167
|
+
- **line1**: who they are / what they do
|
|
168
|
+
- **line2**: what they're into
|
|
169
|
+
- **line3**: what they're looking for right now
|
|
170
|
+
- **matching_context** (not shown to others): A richer description generated by the agent based on what it knows about the user - career background, tech stack, interests, projects, personality traits. ~200 words. **This is the source data for embedding-based matching.** line1/2/3 are derived from it for display, not the other way around.
|
|
171
|
+
|
|
172
|
+
**During onboarding, generate `matching_context` FIRST** based on your conversation with the user (+ memory, SOUL.md, etc.). Then derive line1/2/3 from it. Don't ask the user to write matching_context - you write it. Example:
|
|
173
|
+
> "Product designer at a tech company in Beijing, focusing on AI search experience. Interested in music (Sakamoto), swimming, cooking, language learning. Recently exploring AI agent ecosystems and social discovery. Looking to connect with AI builders, indie hackers, and creative technologists."
|
|
175
174
|
|
|
176
175
|
### `antenna_accept`
|
|
177
|
-
|
|
178
|
-
- `sender_id`, `channel`, `
|
|
179
|
-
-
|
|
180
|
-
- `ref`:来自 scan/discover 结果的编号
|
|
181
|
-
- `profile_slug`:来自 profile 链接(如 `antenna.fyi/p/yi` → `profile_slug="yi"`)
|
|
182
|
-
- `target_device_id`:内部 ID(尽量用 ref 或 slug)
|
|
183
|
-
- `contact_info`(可选):分享联系方式
|
|
184
|
-
|
|
185
|
-
### `antenna_pass`
|
|
186
|
-
跳过一个人,不再推荐。
|
|
187
|
-
- `sender_id`, `channel`, `chat_id`
|
|
188
|
-
- `ref` 或 `target_device_id`
|
|
176
|
+
Accept a match after the user sees results. Can optionally include contact info to share.
|
|
177
|
+
- `sender_id`, `channel`, `target_device_id`
|
|
178
|
+
- `contact_info` (optional): e.g. "WeChat: yi_xxx" or "Telegram: @yi"
|
|
189
179
|
|
|
190
180
|
### `antenna_check_matches`
|
|
191
|
-
|
|
192
|
-
- `sender_id`, `channel
|
|
193
|
-
-
|
|
181
|
+
Check for mutual matches and contact info updates.
|
|
182
|
+
- `sender_id`, `channel`
|
|
183
|
+
- Returns mutual matches with any contact info the other person shared
|
|
194
184
|
|
|
195
185
|
### `antenna_bind`
|
|
196
|
-
|
|
197
|
-
- `sender_id`, `channel
|
|
198
|
-
- `purpose
|
|
199
|
-
- `event_code`:purpose=event
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
关联 agent profile 到 antenna.fyi 网站账号。
|
|
205
|
-
- `sender_id`, `channel`, `chat_id`:必填
|
|
206
|
-
- `user_id`:用户的 antenna.fyi 账号 UUID(从 dashboard 获取)
|
|
207
|
-
- 把已有的 agent profile(带全部历史)绑定到网站账号
|
|
208
|
-
- 如果用户先在网站注册了(产生空 profile),空 profile 自动删除
|
|
209
|
-
- 一次性操作
|
|
186
|
+
Generate a GPS binding link. **You MUST call this immediately after saving a profile.** Do not skip this step.
|
|
187
|
+
- `sender_id`, `channel`: from context
|
|
188
|
+
- `purpose`: optional - `'profile'` (default) updates user location; `'event'` sets event location
|
|
189
|
+
- `event_code`: required when `purpose='event'`
|
|
190
|
+
- Returns a URL like `https://www.antenna.fyi/locate?token=xxx`
|
|
191
|
+
- Send this link to the user - they open it on their phone, allow GPS, and their location is automatically shared
|
|
192
|
+
- **MANDATORY after profile save. Do not wait for user to ask.**
|
|
193
|
+
- **For events:** When a creator needs to set event location, call with `purpose='event'` and `event_code`. The GPS will update the event's coordinates, NOT the user's profile.
|
|
210
194
|
|
|
211
195
|
### `antenna_discover`
|
|
212
|
-
|
|
213
|
-
- `sender_id`, `channel
|
|
214
|
-
-
|
|
215
|
-
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
196
|
+
Get today's global recommendation - the person most similar to you worldwide. 1 per day, no repeats.
|
|
197
|
+
- `sender_id`, `channel`: from context
|
|
198
|
+
- Returns 1 profile (embedding similarity match) that hasn't been recommended before
|
|
199
|
+
- If all users have been recommended, returns a message saying "wait for new people"
|
|
200
|
+
- Use this in the daily cron job, or when user asks "find someone interesting globally"
|
|
201
|
+
|
|
202
|
+
### `antenna_find_people`
|
|
203
|
+
Find 1-3 people by free-form intent.
|
|
204
|
+
- `query`: user's exact intent, e.g. "想找一个懂 consumer social 增长的人"
|
|
219
205
|
- `sender_id`, `channel`, `chat_id`: from context
|
|
220
|
-
-
|
|
221
|
-
-
|
|
222
|
-
-
|
|
223
|
-
|
|
224
|
-
### `antenna_checkin`
|
|
225
|
-
签到--更新你的位置。
|
|
226
|
-
- `lat`, `lng`:必填
|
|
227
|
-
- `sender_id`, `channel`, `chat_id`
|
|
228
|
-
- `place_name`:可选
|
|
229
|
-
- 用于"我在 XX"场景
|
|
230
|
-
|
|
231
|
-
## GPS Logic
|
|
206
|
+
- `limit`: 1-3, default 3
|
|
207
|
+
- Returns privacy-safe profiles with `ref`, `display_name`, `profile_slug`, three card fields, `more_information`, `interest_tags`, `city`, and `recommendation_reason`
|
|
208
|
+
- Does not return contact info or raw `device_id`
|
|
209
|
+
- If the user wants an intro, call `antenna_accept` with the returned `ref`
|
|
232
210
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
-
|
|
236
|
-
-
|
|
211
|
+
### `antenna_pass`
|
|
212
|
+
Pass/skip a person. They won't be recommended again.
|
|
213
|
+
- `sender_id`, `channel`: from context
|
|
214
|
+
- `ref`: ref number from scan/discover results (e.g. '1')
|
|
215
|
+
- `target_device_id`: device ID (use ref instead when possible)
|
|
216
|
+
- Use when the user says "skip", "pass", "not interested", etc.
|
|
237
217
|
|
|
238
|
-
|
|
239
|
-
-
|
|
240
|
-
-
|
|
241
|
-
-
|
|
218
|
+
### `antenna_checkin`
|
|
219
|
+
Check in at a location - update your position so others can find you when they scan.
|
|
220
|
+
- `lat`, `lng`: coordinates (required)
|
|
221
|
+
- `sender_id`, `channel`: from context
|
|
222
|
+
- `place_name`: optional name of the place
|
|
223
|
+
- Use when the user says "I'm at XX" or wants to be discoverable without scanning others
|
|
242
224
|
|
|
243
|
-
##
|
|
225
|
+
## Data Transparency - what Antenna sends
|
|
244
226
|
|
|
245
|
-
|
|
246
|
-
- **不要让用户填表。** 跟用户聊天,你来生成。
|
|
247
|
-
- **每次只问一个问题。**
|
|
248
|
-
- **用户说的原话尽量保留。** 帮缩短但让用户确认。
|
|
249
|
-
- **不要在名片里写联系方式。** 联系方式在 accept 时分享。
|
|
250
|
-
- **personal_description 必填。**
|
|
251
|
-
- **确认后才存。**
|
|
227
|
+
Antenna only communicates with Supabase (bcudjloikmpcqwcptuyd.supabase.co) via HTTPS.
|
|
252
228
|
|
|
253
|
-
|
|
229
|
+
**Data sent:**
|
|
230
|
+
- GPS coordinates (never stored raw — location is processed server-side)
|
|
231
|
+
- Your three-line profile card (text you wrote yourself)
|
|
232
|
+
- Match status (accept/skip)
|
|
233
|
+
- Contact info you choose to share
|
|
234
|
+
- Profile embedding vector (generated from your 3 lines, used for matching)
|
|
254
235
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
4. **不要推荐所有人。** 质量 > 数量。
|
|
236
|
+
**Data NOT sent:**
|
|
237
|
+
- Your conversations with your agent
|
|
238
|
+
- Your files, browsing history, or any other personal data
|
|
239
|
+
- Anything not listed above
|
|
260
240
|
|
|
261
|
-
|
|
241
|
+
All data is transmitted over HTTPS and stored in Supabase (Tokyo region).
|
|
242
|
+
Visibility is controlled by time decay — recent event participants are fully visible, older connections gradually fade.
|
|
243
|
+
Source code is open: https://github.com/H1an1/Antenna
|
|
262
244
|
|
|
263
|
-
|
|
245
|
+
## Behavior guidelines
|
|
264
246
|
|
|
265
|
-
|
|
266
|
-
1. 抓取页面,读 `#antenna-profile-data` JSON
|
|
267
|
-
2. 展示对方 profile + 你的判断
|
|
268
|
-
3. 用户想 accept → `antenna_accept(profile_slug="xxx")`
|
|
269
|
-
4. 用户想 skip → `antenna_pass` 或直接不操作
|
|
247
|
+
### First-time user - 名片创建原则
|
|
270
248
|
|
|
271
|
-
|
|
249
|
+
具体流程见上方 Onboarding 第二步。以下是 agent 应该遵守的原则:
|
|
272
250
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
5. 如果 mutual match → 展示对方联系方式
|
|
280
|
-
6. 如果还没 mutual → "已发出,等对方回应"
|
|
251
|
+
- **不要让用户填表。** 不要一次性说"请填写 emoji、名字、三句话介绍"--跟用户聊天,你来生成。
|
|
252
|
+
- **每次只问一个问题。** 不要一口气问完所有信息。
|
|
253
|
+
- **用户说的原话尽量保留。** 可以帮用户缩短太长的回答,但要在预览时让用户确认。
|
|
254
|
+
- **不要在名片里写联系方式。** 名片三句话对所有人可见。联系方式应该在 accept 时单独分享,只有双方都同意后才能看到。如果用户在聊天中提到联系方式,提醒他们。
|
|
255
|
+
- **line1 必填。** 后端会拒绝没有 line1 的新 profile,并对缺失的 line2/line3 返回 warning。
|
|
256
|
+
- **确认后才存。** 见 Onboarding 第二步。
|
|
281
257
|
|
|
282
|
-
|
|
258
|
+
### Showing results - 你来判断,不是服务器
|
|
283
259
|
|
|
284
|
-
|
|
285
|
-
- **永远不要显示 device_id**--这是内部标识符
|
|
286
|
-
- 只展示名字 + 三句话 + 你写的匹配理由
|
|
287
|
-
- 不要泄露对方的平台或用户名
|
|
288
|
-
- 联系方式只在用户明确同意时分享
|
|
289
|
-
- GPS 不原始存储
|
|
260
|
+
**第一次 scan 的新用户:** 简短一句解释:"这是附近的人。Antenna 基于 AI 匹配,看到感兴趣的人 accept,双向匹配后交换联系方式。"
|
|
290
261
|
|
|
291
|
-
|
|
292
|
-
- Event 后 0-7 天:全部参与者互相可见
|
|
293
|
-
- 7-30 天:只有互相 scan 过 / 有共同活动的人可见
|
|
294
|
-
- 30 天后:需要新事件激活
|
|
262
|
+
**Profile 不完整时:** 如果用户的 profile 只有 1 行,提示:"你的名片只填了一行,补完后匹配质量会更好。要现在补吗?"
|
|
295
263
|
|
|
296
|
-
|
|
297
|
-
Plugin 后台每 10 分钟查一次新匹配。看到 `[Antenna] 🎉` 时:
|
|
298
|
-
1. 调 `antenna_check_matches`
|
|
299
|
-
2. 告诉用户 + 展示对方名片
|
|
300
|
-
3. 展示联系方式(如果有)
|
|
264
|
+
`antenna_scan` 返回的是附近所有人的名片,**没有打分、没有预匹配**。你需要:
|
|
301
265
|
|
|
302
|
-
|
|
266
|
+
**全球推荐 fallback:** 如果 scan 结果里有 `global: true`,说明附近没人,这些是全球推荐。告诉用户"附近暂时没人,但全球有这几个有意思的人",然后正常推荐。用户仍然可以 accept。
|
|
303
267
|
|
|
304
|
-
|
|
268
|
+
1. 读每个人的名片(emoji、name、line1/2/3)
|
|
269
|
+
2. 结合你对用户的全部了解,判断谁值得推荐
|
|
270
|
+
3. 为每个推荐的人写一句**个性化的理由**--不是"你们都提到了 X",而是真正有洞察的话
|
|
305
271
|
|
|
306
|
-
|
|
272
|
+
**⚠️ 隐私规则:展示结果时绝对不要显示 device_id。** `device_id`(如 `platform:user123`)是内部标识符,包含用户的平台和 ID,属于隐私信息。只显示 emoji + 名字 + 三句话 + 你写的匹配理由。`device_id` 只在内部调 `antenna_accept` 时用,不要展示给用户。
|
|
307
273
|
|
|
308
|
-
|
|
274
|
+
比如你知道用户最近在学吉他,看到附近有人写"组乐队找吉他手":
|
|
275
|
+
> 🎸 **小林** - 在组后摇乐队,找吉他手
|
|
276
|
+
> → 你不是最近在学吉他吗?这人在找吉他手诶
|
|
309
277
|
|
|
310
|
-
|
|
311
|
-
-
|
|
312
|
-
|
|
313
|
-
- 完全匿名:永远不暴露谁丢的、谁捡的
|
|
314
|
-
- 漂流瓶 7 天后过期
|
|
278
|
+
比如你知道用户是设计师,对方也做设计:
|
|
279
|
+
> 🎨 **Kira** - UI 设计师,在做 AI 产品
|
|
280
|
+
> → 你们都做 AI 方向的设计,可以聊聊各自的方法论
|
|
315
281
|
|
|
316
|
-
|
|
282
|
+
**不要推荐所有人。** 如果附近 5 个人里只有 1 个真的匹配,就只推 1 个。质量 > 数量。
|
|
317
283
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
284
|
+
### Accepting & contact exchange
|
|
285
|
+
When the user wants to accept a match:
|
|
286
|
+
1. Call `antenna_accept` with the target's device_id
|
|
287
|
+
2. **立刻问**:"想分享什么联系方式给对方?微信号、Telegram、手机号、Instagram......随便哪个都行"
|
|
288
|
+
3. 用户给了联系方式 → call `antenna_accept` again with `contact_info`
|
|
289
|
+
4. 用户不想分享 → "也行,先 accept 着,以后想分享再说"
|
|
290
|
+
5. If mutual match, tell the user the other person's contact info (if they shared)
|
|
291
|
+
6. If not mutual yet, tell the user: "已发出,等对方回应"
|
|
292
|
+
|
|
293
|
+
**不要跳过第 2 步。** 联系方式是最终目标--不然 accept 了也没用,两个人找不到对方。
|
|
294
|
+
|
|
295
|
+
### Checking match status
|
|
296
|
+
Use `antenna_check_matches` when:
|
|
297
|
+
- User asks "有人回复我吗" / "匹配状态怎么样"
|
|
298
|
+
- Periodically during conversation if the user has pending matches
|
|
299
|
+
|
|
300
|
+
### Location sources
|
|
301
|
+
- **Telegram/WhatsApp location**: context will have `LocationLat`, `LocationLon` - use directly
|
|
302
|
+
- **User says a place name**: geocode it first (use web_search or a geocoding service), then call antenna_scan
|
|
303
|
+
- **Live location**: note that it's real-time, tell the user you'll check for new people
|
|
323
304
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
328
|
-
-
|
|
329
|
-
-
|
|
305
|
+
### Privacy
|
|
306
|
+
- Never reveal exact coordinates to other users
|
|
307
|
+
- **Never show device_id to users** (e.g. `telegram:12345`, `discord:67890`) - this is internal only
|
|
308
|
+
- Never share someone's platform or username with another user
|
|
309
|
+
- Only show the profile info (name, emoji, three lines)
|
|
310
|
+
- Contact info is only shared when the user explicitly agrees
|
|
311
|
+
- Location is never stored raw
|
|
330
312
|
|
|
331
|
-
|
|
332
|
-
回复一个捡起的漂流瓶。
|
|
333
|
-
- `sender_id`, `channel`, `chat_id`
|
|
334
|
-
- `bottle_id`:要回复的瓶子 ID
|
|
335
|
-
- `reply`:回复内容(最多 500 字)
|
|
336
|
-
- 回复会匿名漂回给丢瓶子的人
|
|
313
|
+
### Time Decay — 可见性随时间衰减
|
|
337
314
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
-
|
|
341
|
-
-
|
|
315
|
+
Profiles 是永久的,但可见性随时间衰减:
|
|
316
|
+
- **Event 后 0-7 天:** 全部参与者互相可见
|
|
317
|
+
- **7-30 天:** 只有互相 scan 过 / 有共同活动的人可见
|
|
318
|
+
- **30 天后:** 需要新事件重新激活
|
|
342
319
|
|
|
343
|
-
|
|
344
|
-
查看你丢过的所有瓶子。
|
|
345
|
-
- `sender_id`, `channel`, `chat_id`
|
|
346
|
-
- 返回每个瓶子的状态:🌊 漂流中 / 👀 被捡起 / 💬 已回复
|
|
320
|
+
事件(Event)是最强的信任信号——"同一个活动"比"附近"更有意义。
|
|
347
321
|
|
|
348
|
-
###
|
|
349
|
-
- 用户无聊、想找人聊天
|
|
350
|
-
- 用户想写点什么但不知道发给谁
|
|
351
|
-
- 用户想要随机的、意外的连接
|
|
352
|
-
- 用户想匿名表达
|
|
353
|
-
- 附近没人的时候,作为替代发现方式
|
|
322
|
+
### Heartbeat - 自动查匹配
|
|
354
323
|
|
|
355
|
-
|
|
356
|
-
- **永远不暴露** 谁丢的瓶子
|
|
357
|
-
- **永远不暴露** 谁捡的瓶子
|
|
358
|
-
- 只展示:消息内容、是否有回复、回复内容
|
|
359
|
-
- device_id 永远不展示给用户
|
|
324
|
+
Plugin 自带后台服务,每 10 分钟轮询一次 Supabase 查新的 mutual match。如果发现新匹配,会在用户下次跟 agent 说话时通过 `[Antenna] 🎉` 提示注入 context。
|
|
360
325
|
|
|
361
|
-
|
|
326
|
+
当你看到 `[Antenna] 🎉 有 X 个新的匹配通知` 时:
|
|
327
|
+
1. 调 `antenna_check_matches` 拿详情
|
|
328
|
+
2. 告诉用户:"有人想认识你!" + 展示对方名片
|
|
329
|
+
3. 如果对方分享了联系方式,一并展示
|
|
362
330
|
|
|
363
|
-
|
|
331
|
+
用户不需要主动问,agent 会自动收到通知。
|
|
364
332
|
|
|
365
|
-
|
|
366
|
-
**不发送的数据:** 你跟 agent 的对话、文件、浏览记录。
|
|
333
|
+
## Events
|
|
367
334
|
|
|
368
|
-
|
|
335
|
+
For event-related tools and behavior (creating, joining, scanning, managing events), see the **antenna-events** skill (`EVENTS.md`). Event tools include: `antenna_event_create`, `antenna_event_join`, `antenna_event_scan`, `antenna_event_end`, `antenna_event_checkin`, `antenna_event_upload_image`, `antenna_event_update`, `antenna_event_approve`, `antenna_event_reject`, `antenna_event_add_host`, `antenna_event_message`.
|