antenna-fyi 1.3.12 → 1.3.13
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/lib/core.js +52 -2
- package/lib/mcp.js +6 -2
- package/package.json +1 -1
package/lib/core.js
CHANGED
|
@@ -189,6 +189,10 @@ export const PROFILE_FIELDS = {
|
|
|
189
189
|
line2: { label: "想认识的人", description: "The kind of people you want to meet", maxLength: 140 },
|
|
190
190
|
line3: { label: "想要的交流方式", description: "The type of conversations you want", maxLength: 160 },
|
|
191
191
|
matching_context: { label: "匹配上下文", description: "Agent-generated rich context for better matching (not shown to others)", maxLength: 1000 },
|
|
192
|
+
interest_tags: { label: "兴趣标签", description: "Interest/topic tags shown on the card (up to 8)", maxItems: 8 },
|
|
193
|
+
city: { label: "国家/地区", description: "Country or region" },
|
|
194
|
+
links: { label: "社交链接", description: "Social links shown on the card footer (up to 3)", maxItems: 3 },
|
|
195
|
+
is_active: { label: "状态", description: "Whether the profile is active or quiet" },
|
|
192
196
|
};
|
|
193
197
|
|
|
194
198
|
// ─── getProfile ──────────────────────────────────────────────────────
|
|
@@ -197,7 +201,21 @@ export async function getProfile({ device_id, supabaseUrl, supabaseKey }) {
|
|
|
197
201
|
const sb = getClient(supabaseUrl, supabaseKey);
|
|
198
202
|
const { data, error } = await sb.rpc("get_profile", { p_device_id: device_id });
|
|
199
203
|
if (error) throw new Error(error.message);
|
|
200
|
-
|
|
204
|
+
if (!data) return null;
|
|
205
|
+
|
|
206
|
+
// Unpack matching_context JSON into top-level fields for easier agent consumption
|
|
207
|
+
if (data.matching_context) {
|
|
208
|
+
try {
|
|
209
|
+
const ctx = JSON.parse(data.matching_context);
|
|
210
|
+
data.interest_tags = ctx.interestTags || [];
|
|
211
|
+
data.city = ctx.city || null;
|
|
212
|
+
data.links = ctx.links || [];
|
|
213
|
+
data.is_active = typeof ctx.isActive === "boolean" ? ctx.isActive : true;
|
|
214
|
+
data.archetype_override = ctx.archetypeOverride || null;
|
|
215
|
+
data.context = ctx.context || null;
|
|
216
|
+
} catch {}
|
|
217
|
+
}
|
|
218
|
+
return data;
|
|
201
219
|
}
|
|
202
220
|
|
|
203
221
|
// ─── setProfile ──────────────────────────────────────────────────────
|
|
@@ -211,10 +229,42 @@ export async function setProfile({
|
|
|
211
229
|
line3,
|
|
212
230
|
matching_context,
|
|
213
231
|
visible = true,
|
|
232
|
+
interest_tags,
|
|
233
|
+
city,
|
|
234
|
+
links,
|
|
235
|
+
profile_slug,
|
|
236
|
+
is_active,
|
|
237
|
+
archetype_override,
|
|
214
238
|
supabaseUrl,
|
|
215
239
|
supabaseKey,
|
|
216
240
|
}) {
|
|
217
241
|
const sb = getClient(supabaseUrl, supabaseKey);
|
|
242
|
+
|
|
243
|
+
// Pack structured fields into matching_context JSON
|
|
244
|
+
let contextJson = matching_context;
|
|
245
|
+
if (interest_tags || city || links || is_active !== undefined || archetype_override !== undefined) {
|
|
246
|
+
let existing = {};
|
|
247
|
+
// If matching_context is already JSON, parse and merge
|
|
248
|
+
if (matching_context) {
|
|
249
|
+
try { existing = JSON.parse(matching_context); } catch { existing = { context: matching_context }; }
|
|
250
|
+
} else {
|
|
251
|
+
// Read existing matching_context from DB to merge
|
|
252
|
+
try {
|
|
253
|
+
const current = await getProfile({ device_id, supabaseUrl, supabaseKey });
|
|
254
|
+
if (current?.matching_context) {
|
|
255
|
+
try { existing = JSON.parse(current.matching_context); } catch { existing = {}; }
|
|
256
|
+
}
|
|
257
|
+
} catch {}
|
|
258
|
+
}
|
|
259
|
+
if (interest_tags) existing.interestTags = interest_tags;
|
|
260
|
+
if (city) existing.city = city;
|
|
261
|
+
if (links) existing.links = links;
|
|
262
|
+
if (is_active !== undefined) existing.isActive = is_active;
|
|
263
|
+
if (archetype_override !== undefined) existing.archetypeOverride = archetype_override;
|
|
264
|
+
existing.version = existing.version || 1;
|
|
265
|
+
contextJson = JSON.stringify(existing);
|
|
266
|
+
}
|
|
267
|
+
|
|
218
268
|
const { data, error } = await sb.rpc("upsert_profile", {
|
|
219
269
|
p_device_id: device_id,
|
|
220
270
|
p_display_name: display_name || null,
|
|
@@ -223,7 +273,7 @@ export async function setProfile({
|
|
|
223
273
|
p_line2: line2 || null,
|
|
224
274
|
p_line3: line3 || null,
|
|
225
275
|
p_visible: visible,
|
|
226
|
-
p_matching_context:
|
|
276
|
+
p_matching_context: contextJson || null,
|
|
227
277
|
});
|
|
228
278
|
if (error) throw new Error(error.message);
|
|
229
279
|
|
package/lib/mcp.js
CHANGED
|
@@ -116,9 +116,13 @@ export async function startMcpServer() {
|
|
|
116
116
|
line2: z.string().optional().describe("Looking for — the kind of people you want to meet (max 140 chars)"),
|
|
117
117
|
line3: z.string().optional().describe("Conversation style — the type of conversations you want (max 160 chars)"),
|
|
118
118
|
matching_context: z.string().optional().describe("Agent-generated rich context for embedding-based matching (not shown to others, max 1000 chars). Generate this FIRST, then derive the three descriptions from it."),
|
|
119
|
+
interest_tags: z.array(z.string()).optional().describe("Interest/topic tags shown on the card (up to 8)"),
|
|
120
|
+
city: z.string().optional().describe("Country or region (e.g. 'United States', 'Beijing')"),
|
|
121
|
+
links: z.array(z.string()).optional().describe("Social links shown on the card footer (up to 3)"),
|
|
122
|
+
is_active: z.boolean().optional().describe("Whether the profile is active or quiet"),
|
|
119
123
|
visible: z.boolean().optional().default(true),
|
|
120
124
|
},
|
|
121
|
-
async ({ action, sender_id, channel, display_name, emoji, line1, line2, line3, matching_context, visible }) => {
|
|
125
|
+
async ({ action, sender_id, channel, display_name, emoji, line1, line2, line3, matching_context, interest_tags, city, links, is_active, visible }) => {
|
|
122
126
|
const deviceId = deriveDeviceId(sender_id, channel);
|
|
123
127
|
try {
|
|
124
128
|
if (action === "get") {
|
|
@@ -128,7 +132,7 @@ export async function startMcpServer() {
|
|
|
128
132
|
: { profile: null, message: "还没有名片。跟用户聊聊他们是谁、做什么、想认识什么人,然后帮他们创建。", fields: PROFILE_FIELDS };
|
|
129
133
|
return jsonResult(await withMatchNotifications(deviceId, result));
|
|
130
134
|
}
|
|
131
|
-
const data = await setProfile({ device_id: deviceId, display_name, emoji, line1, line2, line3, matching_context, visible });
|
|
135
|
+
const data = await setProfile({ device_id: deviceId, display_name, emoji, line1, line2, line3, matching_context, interest_tags, city, links, is_active, visible });
|
|
132
136
|
return jsonResult(await withMatchNotifications(deviceId, { saved: true, profile: data }));
|
|
133
137
|
} catch (e) {
|
|
134
138
|
return jsonResult({ error: e.message });
|