@indexnetwork/protocol 4.3.4-rc.312.1 → 4.3.6-rc.314.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.
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity.tools.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"opportunity.tools.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.tools.ts"],"names":[],"mappings":"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"}
@@ -1534,12 +1534,10 @@ export function createOpportunityTools(defineTool, deps) {
1534
1534
  const allUserIds = [
1535
1535
  ...new Set([...counterpartUserIds, ...introducerUserIds]),
1536
1536
  ];
1537
- const [viewerUser, profileResults, userResults] = await Promise.all([
1538
- database.getUser(context.userId),
1537
+ const [profileResults, userResults] = await Promise.all([
1539
1538
  Promise.all(allUserIds.map((id) => database.getProfile(id))),
1540
1539
  Promise.all(allUserIds.map((id) => database.getUser(id))),
1541
1540
  ]);
1542
- const viewerName = viewerUser?.name ?? undefined;
1543
1541
  const profileMap = new Map();
1544
1542
  const userMap = new Map();
1545
1543
  allUserIds.forEach((userId, i) => {
@@ -1711,73 +1709,140 @@ export function createOpportunityTools(defineTool, deps) {
1711
1709
  }
1712
1710
  }
1713
1711
  else {
1714
- // ── Chat mode: fast heuristic path (no LLM) ──
1715
- for (const opp of opportunities) {
1716
- if (seenOpportunityIds.has(opp.id))
1717
- continue;
1718
- seenOpportunityIds.add(opp.id);
1719
- try {
1720
- const counterpartActor = opp.actors.find((a) => a.userId !== context.userId && a.role !== "introducer");
1721
- const counterpartUserId = counterpartActor?.userId;
1722
- if (!counterpartUserId)
1723
- continue;
1724
- const viewerIsIntroducerHere = opp.actors.some((a) => a.role === "introducer" && a.userId === context.userId);
1725
- const secondPartyActorForHeadline = viewerIsIntroducerHere
1726
- ? opp.actors.find((a) => a.userId !== context.userId &&
1727
- a.userId !== counterpartUserId &&
1728
- a.role !== "introducer")
1729
- : undefined;
1730
- const secondPartyNameForHeadline = secondPartyActorForHeadline
1731
- ? (profileMap.get(secondPartyActorForHeadline.userId)?.identity?.name ??
1732
- userMap.get(secondPartyActorForHeadline.userId)?.name ??
1733
- undefined)
1734
- : undefined;
1735
- const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== context.userId);
1736
- const createdByName = opp.detection.createdByName;
1737
- const counterpartProfile = profileMap.get(counterpartUserId) ?? null;
1738
- const counterpartUser = userMap.get(counterpartUserId) ?? null;
1739
- const introducerProfile = introducerActor && !createdByName
1740
- ? profileMap.get(introducerActor.userId) ?? null
1741
- : null;
1742
- const counterpartName = counterpartProfile?.identity?.name ??
1743
- counterpartUser?.name ??
1744
- "Someone";
1745
- const introducerName = createdByName ??
1746
- (introducerActor ? introducerProfile?.identity?.name ?? null : null);
1747
- const introducerUser = introducerActor
1748
- ? userMap.get(introducerActor.userId) ?? null
1749
- : null;
1750
- const secondPartyUser = secondPartyActorForHeadline
1751
- ? userMap.get(secondPartyActorForHeadline.userId) ?? null
1752
- : null;
1753
- const cardData = buildMinimalOpportunityCard(opp, context.userId, counterpartUserId, counterpartName, counterpartUser?.avatar ?? null, introducerName, introducerUser?.avatar ?? null, viewerName, secondPartyNameForHeadline, secondPartyUser?.avatar ?? null, secondPartyActorForHeadline?.userId);
1754
- // For MCP callers (e.g. Edge Claw), mint a connect token and attach
1755
- // acceptUrl + profileUrl when the (status, viewerRole) is actionable
1756
- // for the viewer. Non-actionable combos (sender-on-draft,
1757
- // pending-on-introducer-waiting, rejected, etc.) deliberately get
1758
- // no link — the LLM would otherwise hallucinate `/api/.../connect`
1759
- // URLs from the exposed opportunityId.
1760
- if (context.isMcp && deps.mintConnectLink) {
1712
+ // ── Chat/list mode: use OpportunityPresenter for user-facing card copy ──
1713
+ const presenter = createOpportunityPresenter();
1714
+ const presenterDb = database;
1715
+ const PRESENTER_CONCURRENCY = 6;
1716
+ for (let i = 0; i < opportunities.length; i += PRESENTER_CONCURRENCY) {
1717
+ const chunk = opportunities.slice(i, i + PRESENTER_CONCURRENCY);
1718
+ const chunkCards = await Promise.all(chunk.map(async (opp) => {
1719
+ if (seenOpportunityIds.has(opp.id))
1720
+ return null;
1721
+ seenOpportunityIds.add(opp.id);
1722
+ try {
1723
+ const counterpartActor = opp.actors.find((a) => a.userId !== context.userId && a.role !== "introducer");
1724
+ const counterpartUserId = counterpartActor?.userId;
1725
+ if (!counterpartUserId)
1726
+ return null;
1727
+ const viewerIsIntroducerHere = opp.actors.some((a) => a.role === "introducer" && a.userId === context.userId);
1728
+ const secondPartyActorForHeadline = viewerIsIntroducerHere
1729
+ ? opp.actors.find((a) => a.userId !== context.userId &&
1730
+ a.userId !== counterpartUserId &&
1731
+ a.role !== "introducer")
1732
+ : undefined;
1733
+ const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== context.userId);
1734
+ const createdByName = opp.detection.createdByName;
1735
+ const counterpartProfile = profileMap.get(counterpartUserId) ?? null;
1736
+ const counterpartUser = userMap.get(counterpartUserId) ?? null;
1737
+ const introducerProfile = introducerActor && !createdByName
1738
+ ? profileMap.get(introducerActor.userId) ?? null
1739
+ : null;
1740
+ const counterpartName = counterpartProfile?.identity?.name ??
1741
+ counterpartUser?.name ??
1742
+ "Someone";
1743
+ const introducerName = createdByName ??
1744
+ (introducerActor ? introducerProfile?.identity?.name ?? null : null);
1745
+ const introducerUser = introducerActor
1746
+ ? userMap.get(introducerActor.userId) ?? null
1747
+ : null;
1748
+ const secondPartyUser = secondPartyActorForHeadline
1749
+ ? userMap.get(secondPartyActorForHeadline.userId) ?? null
1750
+ : null;
1751
+ const secondPartyNameForHeadline = secondPartyActorForHeadline
1752
+ ? (profileMap.get(secondPartyActorForHeadline.userId)?.identity?.name ??
1753
+ secondPartyUser?.name ??
1754
+ undefined)
1755
+ : undefined;
1761
1756
  const viewerActor = opp.actors.find((a) => a.userId === context.userId);
1762
- const viewerApproved = viewerActor?.role === "introducer" ? viewerActor.approved === true : undefined;
1763
- await attachActionableLinks(cardData, {
1764
- viewerId: context.userId,
1765
- viewerApproved,
1766
- counterpartUserId,
1767
- mintConnectLink: deps.mintConnectLink,
1768
- frontendUrl: deps.frontendUrl,
1769
- preferredSurface: context.clientSurface,
1757
+ const viewerRole = viewerActor?.role ?? "party";
1758
+ const isCounterpartGhost = counterpartUser?.isGhost ?? false;
1759
+ const [ctx, negotiationContext] = await Promise.all([
1760
+ gatherOpportunityPresenterContext(presenterDb, opp, context.userId, counterpartUserId),
1761
+ loadNegotiationContext(deps.negotiationDatabase, opp.id, opp.status),
1762
+ ]);
1763
+ const presentation = await presenter.presentHomeCard({
1764
+ ...ctx,
1765
+ opportunityStatus: opp.status,
1766
+ ...(negotiationContext ? { negotiationContext } : {}),
1767
+ });
1768
+ let narratorChip;
1769
+ const introducerIsCounterpart = introducerActor && counterpartActor && introducerActor.userId === counterpartActor.userId;
1770
+ if (introducerActor && introducerActor.userId !== context.userId && !introducerIsCounterpart) {
1771
+ const narratorName = introducerName?.trim() || "Someone";
1772
+ narratorChip = {
1773
+ name: narratorName,
1774
+ text: stripLeadingNarratorName(presentation.narratorRemark, narratorName),
1775
+ avatar: introducerUser?.avatar ?? null,
1776
+ userId: introducerActor.userId,
1777
+ };
1778
+ }
1779
+ else if (introducerActor?.userId === context.userId) {
1780
+ narratorChip = { name: "You", text: presentation.narratorRemark, userId: context.userId };
1781
+ }
1782
+ else {
1783
+ narratorChip = { name: "Index", text: presentation.narratorRemark };
1784
+ }
1785
+ const cardData = {
1786
+ opportunityId: opp.id,
1787
+ userId: counterpartUserId,
1788
+ name: counterpartName,
1789
+ avatar: counterpartUser?.avatar ?? null,
1790
+ mainText: stripUuids(presentation.personalizedSummary),
1791
+ cta: presentation.suggestedAction,
1792
+ headline: viewerIsIntroducerHere && secondPartyNameForHeadline
1793
+ ? `${counterpartName} → ${secondPartyNameForHeadline}`
1794
+ : presentation.headline,
1795
+ primaryActionLabel: getPrimaryActionLabel(viewerRole),
1796
+ secondaryActionLabel: SECONDARY_ACTION_LABEL,
1797
+ mutualIntentsLabel: presentation.mutualIntentsLabel,
1798
+ narratorChip,
1799
+ viewerRole,
1800
+ score: typeof opp.interpretation?.confidence === "number"
1801
+ ? opp.interpretation.confidence
1802
+ : undefined,
1803
+ status: opp.status,
1804
+ isGhost: isCounterpartGhost,
1805
+ ...(viewerIsIntroducerHere && secondPartyNameForHeadline
1806
+ ? {
1807
+ secondParty: {
1808
+ name: secondPartyNameForHeadline,
1809
+ ...(secondPartyUser?.avatar != null ? { avatar: secondPartyUser.avatar } : {}),
1810
+ ...(secondPartyActorForHeadline?.userId ? { userId: secondPartyActorForHeadline.userId } : {}),
1811
+ },
1812
+ }
1813
+ : {}),
1814
+ };
1815
+ // For MCP callers (e.g. Edge Claw), mint a connect token and attach
1816
+ // acceptUrl + profileUrl when the (status, viewerRole) is actionable
1817
+ // for the viewer. Non-actionable combos (sender-on-draft,
1818
+ // pending-on-introducer-waiting, rejected, etc.) deliberately get
1819
+ // no link — the LLM would otherwise hallucinate `/api/.../connect`
1820
+ // URLs from the exposed opportunityId.
1821
+ if (context.isMcp && deps.mintConnectLink) {
1822
+ const viewerApproved = viewerActor?.role === "introducer" ? viewerActor.approved === true : undefined;
1823
+ await attachActionableLinks(cardData, {
1824
+ viewerId: context.userId,
1825
+ viewerApproved,
1826
+ counterpartUserId,
1827
+ mintConnectLink: deps.mintConnectLink,
1828
+ frontendUrl: deps.frontendUrl,
1829
+ preferredSurface: context.clientSurface,
1830
+ });
1831
+ }
1832
+ return cardData;
1833
+ }
1834
+ catch (err) {
1835
+ logger.warn("Skipping opportunity that failed to build presenter card", {
1836
+ opportunityId: opp.id,
1837
+ err,
1770
1838
  });
1839
+ skippedIds.push(opp.id);
1840
+ return null;
1771
1841
  }
1772
- cardDataList.push(cardData);
1773
- }
1774
- catch (err) {
1775
- logger.warn("Skipping opportunity that failed to build minimal card", {
1776
- opportunityId: opp.id,
1777
- err,
1778
- });
1779
- skippedIds.push(opp.id);
1780
- continue;
1842
+ }));
1843
+ for (const card of chunkCards) {
1844
+ if (card)
1845
+ cardDataList.push(card);
1781
1846
  }
1782
1847
  }
1783
1848
  }