@indexnetwork/protocol 1.26.2 → 1.26.3-rc.224.1
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/dist/intent/intent.graph.d.ts +3 -0
- package/dist/intent/intent.graph.d.ts.map +1 -1
- package/dist/intent/intent.graph.js +18 -1
- package/dist/intent/intent.graph.js.map +1 -1
- package/dist/intent/intent.specificity.d.ts +3 -0
- package/dist/intent/intent.specificity.d.ts.map +1 -0
- package/dist/intent/intent.specificity.js +3 -0
- package/dist/intent/intent.specificity.js.map +1 -0
- package/dist/intent/intent.tools.d.ts.map +1 -1
- package/dist/intent/intent.tools.js +24 -0
- package/dist/intent/intent.tools.js.map +1 -1
- package/dist/intent/intent.verifier.d.ts +19 -0
- package/dist/intent/intent.verifier.d.ts.map +1 -1
- package/dist/intent/intent.verifier.js +34 -1
- package/dist/intent/intent.verifier.js.map +1 -1
- package/dist/opportunity/opportunity.tools.d.ts.map +1 -1
- package/dist/opportunity/opportunity.tools.js +221 -65
- package/dist/opportunity/opportunity.tools.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,9 +2,10 @@ import { z } from "zod";
|
|
|
2
2
|
import { requestContext } from "../shared/observability/request-context.js";
|
|
3
3
|
import { success, error, UUID_REGEX } from "../shared/agent/tool.helpers.js";
|
|
4
4
|
import { MINIMAL_MAIN_TEXT_MAX_CHARS, getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from "./opportunity.labels.js";
|
|
5
|
-
import { viewerCentricCardSummary, narratorRemarkFromReasoning } from "./opportunity.presentation.js";
|
|
5
|
+
import { viewerCentricCardSummary, narratorRemarkFromReasoning, stripUuids } from "./opportunity.presentation.js";
|
|
6
6
|
import { runDiscoverFromQuery, continueDiscovery } from "./opportunity.discover.js";
|
|
7
|
-
import { OpportunityPresenter } from "./opportunity.presenter.js";
|
|
7
|
+
import { OpportunityPresenter, gatherPresenterContext } from "./opportunity.presenter.js";
|
|
8
|
+
import { stripLeadingNarratorName } from "./feed/feed.graph.js";
|
|
8
9
|
import { protocolLogger } from "../shared/observability/protocol.logger.js";
|
|
9
10
|
import { selectByComposition, deduplicateByPerson } from "./opportunity.utils.js";
|
|
10
11
|
import { mergePendingQuestions } from "./opportunity.pending-questions.js";
|
|
@@ -1230,75 +1231,230 @@ export function createOpportunityTools(defineTool, deps) {
|
|
|
1230
1231
|
if (user)
|
|
1231
1232
|
userMap.set(userId, user);
|
|
1232
1233
|
});
|
|
1234
|
+
const isDigestMode = context.isMcp === true && query.includeDigestMarkers === true;
|
|
1233
1235
|
const cardDataList = [];
|
|
1234
1236
|
const seenOpportunityIds = new Set();
|
|
1235
1237
|
const skippedIds = [];
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1238
|
+
if (isDigestMode) {
|
|
1239
|
+
// ── Digest mode: use LLM presenter for rich, second-person card text ──
|
|
1240
|
+
const presenter = new OpportunityPresenter();
|
|
1241
|
+
const presenterDb = database;
|
|
1242
|
+
const PRESENTER_CONCURRENCY = 6;
|
|
1243
|
+
for (let i = 0; i < opportunities.length; i += PRESENTER_CONCURRENCY) {
|
|
1244
|
+
const chunk = opportunities.slice(i, i + PRESENTER_CONCURRENCY);
|
|
1245
|
+
const chunkCards = await Promise.all(chunk.map(async (opp) => {
|
|
1246
|
+
if (seenOpportunityIds.has(opp.id))
|
|
1247
|
+
return null;
|
|
1248
|
+
seenOpportunityIds.add(opp.id);
|
|
1249
|
+
try {
|
|
1250
|
+
const counterpartActor = opp.actors.find((a) => a.userId !== context.userId && a.role !== "introducer");
|
|
1251
|
+
const counterpartUserId = counterpartActor?.userId;
|
|
1252
|
+
if (!counterpartUserId)
|
|
1253
|
+
return null;
|
|
1254
|
+
const viewerIsIntroducerHere = opp.actors.some((a) => a.role === "introducer" && a.userId === context.userId);
|
|
1255
|
+
const secondPartyActorForHeadline = viewerIsIntroducerHere
|
|
1256
|
+
? opp.actors.find((a) => a.userId !== context.userId &&
|
|
1257
|
+
a.userId !== counterpartUserId &&
|
|
1258
|
+
a.role !== "introducer")
|
|
1259
|
+
: undefined;
|
|
1260
|
+
const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== context.userId);
|
|
1261
|
+
const createdByName = opp.detection.createdByName;
|
|
1262
|
+
const counterpartUser = userMap.get(counterpartUserId) ?? null;
|
|
1263
|
+
const counterpartName = profileMap.get(counterpartUserId)?.identity?.name ??
|
|
1264
|
+
counterpartUser?.name ??
|
|
1265
|
+
"Someone";
|
|
1266
|
+
const introducerName = createdByName ??
|
|
1267
|
+
(introducerActor
|
|
1268
|
+
? (profileMap.get(introducerActor.userId)?.identity?.name ?? null)
|
|
1269
|
+
: null);
|
|
1270
|
+
const introducerUser = introducerActor
|
|
1271
|
+
? userMap.get(introducerActor.userId) ?? null
|
|
1272
|
+
: null;
|
|
1273
|
+
const secondPartyUser = secondPartyActorForHeadline
|
|
1274
|
+
? userMap.get(secondPartyActorForHeadline.userId) ?? null
|
|
1275
|
+
: null;
|
|
1276
|
+
const secondPartyNameForHeadline = secondPartyActorForHeadline
|
|
1277
|
+
? (profileMap.get(secondPartyActorForHeadline.userId)?.identity?.name ??
|
|
1278
|
+
secondPartyUser?.name ??
|
|
1279
|
+
undefined)
|
|
1280
|
+
: undefined;
|
|
1281
|
+
const viewerActor = opp.actors.find((a) => a.userId === context.userId);
|
|
1282
|
+
const viewerRole = viewerActor?.role ?? "party";
|
|
1283
|
+
const isCounterpartGhost = counterpartUser?.isGhost ?? false;
|
|
1284
|
+
// Build fallback card in case LLM presenter fails
|
|
1285
|
+
const fallbackCard = buildMinimalOpportunityCard(opp, context.userId, counterpartUserId, counterpartName, counterpartUser?.avatar ?? null, introducerName, introducerUser?.avatar ?? null, viewerName, secondPartyNameForHeadline, secondPartyUser?.avatar ?? null, secondPartyActorForHeadline?.userId, isCounterpartGhost);
|
|
1286
|
+
try {
|
|
1287
|
+
const ctx = await gatherPresenterContext(presenterDb, opp, context.userId, counterpartUserId);
|
|
1288
|
+
const presentation = await presenter.presentHomeCard({
|
|
1289
|
+
...ctx,
|
|
1290
|
+
opportunityStatus: opp.status,
|
|
1291
|
+
});
|
|
1292
|
+
// Build narrator chip from presenter output
|
|
1293
|
+
let narratorChip;
|
|
1294
|
+
const introducerIsCounterpart = introducerActor && counterpartActor && introducerActor.userId === counterpartActor.userId;
|
|
1295
|
+
if (introducerActor && introducerActor.userId !== context.userId && !introducerIsCounterpart) {
|
|
1296
|
+
const narratorName = introducerName ?? "Someone";
|
|
1297
|
+
narratorChip = {
|
|
1298
|
+
name: narratorName,
|
|
1299
|
+
text: stripLeadingNarratorName(presentation.narratorRemark, narratorName),
|
|
1300
|
+
avatar: introducerUser?.avatar ?? null,
|
|
1301
|
+
userId: introducerActor.userId,
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
else if (introducerActor?.userId === context.userId) {
|
|
1305
|
+
narratorChip = { name: "You", text: presentation.narratorRemark, userId: context.userId };
|
|
1306
|
+
}
|
|
1307
|
+
else {
|
|
1308
|
+
narratorChip = { name: "Index", text: presentation.narratorRemark };
|
|
1309
|
+
}
|
|
1310
|
+
const card = {
|
|
1311
|
+
opportunityId: opp.id,
|
|
1312
|
+
userId: counterpartUserId,
|
|
1313
|
+
name: counterpartName,
|
|
1314
|
+
avatar: counterpartUser?.avatar ?? null,
|
|
1315
|
+
mainText: stripUuids(presentation.personalizedSummary),
|
|
1316
|
+
cta: presentation.suggestedAction,
|
|
1317
|
+
headline: viewerIsIntroducerHere && secondPartyNameForHeadline
|
|
1318
|
+
? `${counterpartName} → ${secondPartyNameForHeadline}`
|
|
1319
|
+
: presentation.headline,
|
|
1320
|
+
primaryActionLabel: getPrimaryActionLabel(viewerRole),
|
|
1321
|
+
secondaryActionLabel: SECONDARY_ACTION_LABEL,
|
|
1322
|
+
mutualIntentsLabel: presentation.mutualIntentsLabel,
|
|
1323
|
+
narratorChip,
|
|
1324
|
+
viewerRole,
|
|
1325
|
+
score: typeof opp.interpretation?.confidence === "number"
|
|
1326
|
+
? opp.interpretation.confidence
|
|
1327
|
+
: undefined,
|
|
1328
|
+
status: opp.status,
|
|
1329
|
+
isGhost: isCounterpartGhost,
|
|
1330
|
+
...(viewerIsIntroducerHere && secondPartyNameForHeadline
|
|
1331
|
+
? {
|
|
1332
|
+
secondParty: {
|
|
1333
|
+
name: secondPartyNameForHeadline,
|
|
1334
|
+
...(secondPartyUser?.avatar != null ? { avatar: secondPartyUser.avatar } : {}),
|
|
1335
|
+
...(secondPartyActorForHeadline?.userId ? { userId: secondPartyActorForHeadline.userId } : {}),
|
|
1336
|
+
},
|
|
1337
|
+
}
|
|
1338
|
+
: {}),
|
|
1339
|
+
};
|
|
1340
|
+
// Attach actionable links for MCP callers
|
|
1341
|
+
if (context.isMcp && deps.mintConnectLink) {
|
|
1342
|
+
const viewerApproved = viewerActor?.role === "introducer" ? viewerActor.approved === true : undefined;
|
|
1343
|
+
await attachActionableLinks(card, {
|
|
1344
|
+
viewerId: context.userId,
|
|
1345
|
+
viewerApproved,
|
|
1346
|
+
counterpartUserId,
|
|
1347
|
+
mintConnectLink: deps.mintConnectLink,
|
|
1348
|
+
frontendUrl: deps.frontendUrl,
|
|
1349
|
+
preferredSurface: context.clientSurface,
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
return card;
|
|
1353
|
+
}
|
|
1354
|
+
catch (presenterErr) {
|
|
1355
|
+
logger.warn("LLM presenter failed for list_opportunities digest card, using fallback", {
|
|
1356
|
+
opportunityId: opp.id,
|
|
1357
|
+
err: presenterErr,
|
|
1358
|
+
});
|
|
1359
|
+
// Attach links to fallback card too
|
|
1360
|
+
if (context.isMcp && deps.mintConnectLink) {
|
|
1361
|
+
const viewerApproved = viewerActor?.role === "introducer" ? viewerActor.approved === true : undefined;
|
|
1362
|
+
await attachActionableLinks(fallbackCard, {
|
|
1363
|
+
viewerId: context.userId,
|
|
1364
|
+
viewerApproved,
|
|
1365
|
+
counterpartUserId,
|
|
1366
|
+
mintConnectLink: deps.mintConnectLink,
|
|
1367
|
+
frontendUrl: deps.frontendUrl,
|
|
1368
|
+
preferredSurface: context.clientSurface,
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
return fallbackCard;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
catch (err) {
|
|
1375
|
+
logger.warn("Skipping opportunity that failed to build card", {
|
|
1376
|
+
opportunityId: opp.id,
|
|
1377
|
+
err,
|
|
1378
|
+
});
|
|
1379
|
+
skippedIds.push(opp.id);
|
|
1380
|
+
return null;
|
|
1381
|
+
}
|
|
1382
|
+
}));
|
|
1383
|
+
for (const card of chunkCards) {
|
|
1384
|
+
if (card)
|
|
1385
|
+
cardDataList.push(card);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
else {
|
|
1390
|
+
// ── Chat mode: fast heuristic path (no LLM) ──
|
|
1391
|
+
for (const opp of opportunities) {
|
|
1392
|
+
if (seenOpportunityIds.has(opp.id))
|
|
1244
1393
|
continue;
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1394
|
+
seenOpportunityIds.add(opp.id);
|
|
1395
|
+
try {
|
|
1396
|
+
const counterpartActor = opp.actors.find((a) => a.userId !== context.userId && a.role !== "introducer");
|
|
1397
|
+
const counterpartUserId = counterpartActor?.userId;
|
|
1398
|
+
if (!counterpartUserId)
|
|
1399
|
+
continue;
|
|
1400
|
+
const viewerIsIntroducerHere = opp.actors.some((a) => a.role === "introducer" && a.userId === context.userId);
|
|
1401
|
+
const secondPartyActorForHeadline = viewerIsIntroducerHere
|
|
1402
|
+
? opp.actors.find((a) => a.userId !== context.userId &&
|
|
1403
|
+
a.userId !== counterpartUserId &&
|
|
1404
|
+
a.role !== "introducer")
|
|
1405
|
+
: undefined;
|
|
1406
|
+
const secondPartyNameForHeadline = secondPartyActorForHeadline
|
|
1407
|
+
? (profileMap.get(secondPartyActorForHeadline.userId)?.identity?.name ??
|
|
1408
|
+
userMap.get(secondPartyActorForHeadline.userId)?.name ??
|
|
1409
|
+
undefined)
|
|
1410
|
+
: undefined;
|
|
1411
|
+
const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== context.userId);
|
|
1412
|
+
const createdByName = opp.detection.createdByName;
|
|
1413
|
+
const counterpartProfile = profileMap.get(counterpartUserId) ?? null;
|
|
1414
|
+
const counterpartUser = userMap.get(counterpartUserId) ?? null;
|
|
1415
|
+
const introducerProfile = introducerActor && !createdByName
|
|
1416
|
+
? profileMap.get(introducerActor.userId) ?? null
|
|
1417
|
+
: null;
|
|
1418
|
+
const counterpartName = counterpartProfile?.identity?.name ??
|
|
1419
|
+
counterpartUser?.name ??
|
|
1420
|
+
"Someone";
|
|
1421
|
+
const introducerName = createdByName ??
|
|
1422
|
+
(introducerActor ? introducerProfile?.identity?.name ?? null : null);
|
|
1423
|
+
const introducerUser = introducerActor
|
|
1424
|
+
? userMap.get(introducerActor.userId) ?? null
|
|
1425
|
+
: null;
|
|
1426
|
+
const secondPartyUser = secondPartyActorForHeadline
|
|
1427
|
+
? userMap.get(secondPartyActorForHeadline.userId) ?? null
|
|
1428
|
+
: null;
|
|
1429
|
+
const cardData = buildMinimalOpportunityCard(opp, context.userId, counterpartUserId, counterpartName, counterpartUser?.avatar ?? null, introducerName, introducerUser?.avatar ?? null, viewerName, secondPartyNameForHeadline, secondPartyUser?.avatar ?? null, secondPartyActorForHeadline?.userId);
|
|
1430
|
+
// For MCP callers (e.g. Edge Claw), mint a connect token and attach
|
|
1431
|
+
// acceptUrl + profileUrl when the (status, viewerRole) is actionable
|
|
1432
|
+
// for the viewer. Non-actionable combos (sender-on-draft,
|
|
1433
|
+
// pending-on-introducer-waiting, rejected, etc.) deliberately get
|
|
1434
|
+
// no link — the LLM would otherwise hallucinate `/api/.../connect`
|
|
1435
|
+
// URLs from the exposed opportunityId.
|
|
1436
|
+
if (context.isMcp && deps.mintConnectLink) {
|
|
1437
|
+
const viewerActor = opp.actors.find((a) => a.userId === context.userId);
|
|
1438
|
+
const viewerApproved = viewerActor?.role === "introducer" ? viewerActor.approved === true : undefined;
|
|
1439
|
+
await attachActionableLinks(cardData, {
|
|
1440
|
+
viewerId: context.userId,
|
|
1441
|
+
viewerApproved,
|
|
1442
|
+
counterpartUserId,
|
|
1443
|
+
mintConnectLink: deps.mintConnectLink,
|
|
1444
|
+
frontendUrl: deps.frontendUrl,
|
|
1445
|
+
preferredSurface: context.clientSurface,
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
cardDataList.push(cardData);
|
|
1449
|
+
}
|
|
1450
|
+
catch (err) {
|
|
1451
|
+
logger.warn("Skipping opportunity that failed to build minimal card", {
|
|
1452
|
+
opportunityId: opp.id,
|
|
1453
|
+
err,
|
|
1291
1454
|
});
|
|
1455
|
+
skippedIds.push(opp.id);
|
|
1456
|
+
continue;
|
|
1292
1457
|
}
|
|
1293
|
-
cardDataList.push(cardData);
|
|
1294
|
-
}
|
|
1295
|
-
catch (err) {
|
|
1296
|
-
logger.warn("Skipping opportunity that failed to build minimal card", {
|
|
1297
|
-
opportunityId: opp.id,
|
|
1298
|
-
err,
|
|
1299
|
-
});
|
|
1300
|
-
skippedIds.push(opp.id);
|
|
1301
|
-
continue;
|
|
1302
1458
|
}
|
|
1303
1459
|
}
|
|
1304
1460
|
const listDebugSteps = [];
|