@indexnetwork/protocol 4.3.6 → 4.3.7-rc.317.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.
@@ -3,7 +3,8 @@ import { requestContext } from "../shared/observability/request-context.js";
3
3
  import { success, error, UUID_REGEX } from "../shared/agent/tool.helpers.js";
4
4
  import { deriveDiscoveryNetworkIds, focusedIntentId, focusedNetworkId, focusedNetworkLabel } from "../shared/agent/tool.scope.js";
5
5
  import { MINIMAL_MAIN_TEXT_MAX_CHARS, getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from "./opportunity.labels.js";
6
- import { viewerCentricCardSummary, narratorRemarkFromReasoning, stripUuids } from "./opportunity.presentation.js";
6
+ import { narratorRemarkFromReasoning, stripUuids } from "./opportunity.presentation.js";
7
+ import { safeFallbackSummary, getSafePresentationOrSkip } from "./opportunity.safe-presentation.js";
7
8
  import { runDiscoverFromQuery, continueDiscovery } from "./opportunity.discover.js";
8
9
  import { OpportunityPresenter, gatherPresenterContext } from "./opportunity.presenter.js";
9
10
  import { loadNegotiationContext } from "./negotiation-context.loader.js";
@@ -61,17 +62,18 @@ const logger = protocolLogger("ChatTools:Opportunity");
61
62
  * accepted opp and can engage or ignore.
62
63
  */
63
64
  export function resolveActionableLinkKind(input) {
64
- const { status, viewerRole, viewerApproved } = input;
65
+ const { status, viewerRole, viewerApproved, viewerActedAt } = input;
65
66
  const isIntroducer = viewerRole === "introducer";
67
+ const hasViewerActed = !!viewerActedAt;
66
68
  if (status === "accepted") {
67
69
  return isIntroducer ? null : "outreach";
68
70
  }
69
71
  if (status === "pending") {
70
- return isIntroducer ? null : "connect";
72
+ return isIntroducer || hasViewerActed ? null : "connect";
71
73
  }
72
74
  if (status === "draft" || status === "latent") {
73
75
  if (!isIntroducer)
74
- return "send_direct";
76
+ return hasViewerActed ? null : "send_direct";
75
77
  return viewerApproved === true ? null : "approve_introduction";
76
78
  }
77
79
  return null;
@@ -136,12 +138,14 @@ export async function attachActionableLinks(card, opts) {
136
138
  status: card.status,
137
139
  viewerRole: card.viewerRole,
138
140
  viewerApproved: opts.viewerApproved,
141
+ viewerActedAt: opts.viewerActedAt,
139
142
  });
140
143
  logger.info("Opportunity actionability decision", {
141
144
  opportunityId: card.opportunityId,
142
145
  status: card.status,
143
146
  viewerRole: card.viewerRole,
144
147
  viewerApproved: opts.viewerApproved,
148
+ viewerActedAt: opts.viewerActedAt,
145
149
  kind: kind ?? "none",
146
150
  });
147
151
  if (kind === null)
@@ -229,7 +233,14 @@ export function buildMinimalOpportunityCard(opp, viewerId, counterpartUserId, co
229
233
  const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== viewerId);
230
234
  const viewerIsIntroducer = opp.actors.some((a) => a.role === "introducer" && a.userId === viewerId);
231
235
  const reasoning = opp.interpretation?.reasoning ?? "";
232
- const mainText = viewerCentricCardSummary(reasoning, counterpartName, MINIMAL_MAIN_TEXT_MAX_CHARS, viewerName, introducerName ?? undefined);
236
+ // Shared sanitization standard see opportunity.safe-presentation.ts.
237
+ const mainText = safeFallbackSummary(reasoning, {
238
+ counterpartName,
239
+ viewerName,
240
+ introducerName: introducerName ?? undefined,
241
+ maxChars: MINIMAL_MAIN_TEXT_MAX_CHARS,
242
+ emptyText: "A suggested connection.",
243
+ });
233
244
  const score = typeof opp.interpretation?.confidence === "number"
234
245
  ? opp.interpretation.confidence
235
246
  : undefined;
@@ -647,7 +658,7 @@ export function createOpportunityTools(defineTool, deps) {
647
658
  userId: opp.userId,
648
659
  name: opp.name,
649
660
  avatar: opp.avatar,
650
- mainText: opp.homeCardPresentation?.personalizedSummary ?? opp.matchReason ?? "",
661
+ mainText: getSafePresentationOrSkip(opp, { counterpartName: opp.name })?.summary ?? "",
651
662
  cta: opp.homeCardPresentation?.suggestedAction,
652
663
  headline: opp.homeCardPresentation?.headline,
653
664
  primaryActionLabel: opp.homeCardPresentation?.primaryActionLabel,
@@ -658,6 +669,7 @@ export function createOpportunityTools(defineTool, deps) {
658
669
  isGhost: opp.isGhost ?? false,
659
670
  score: opp.score,
660
671
  status: opp.status,
672
+ viewerActedAt: opp.viewerActedAt,
661
673
  }));
662
674
  const displayedCards = allCardData.slice(0, CHAT_DISPLAY_LIMIT);
663
675
  const extraFromCap = allCardData.length - displayedCards.length;
@@ -791,8 +803,13 @@ export function createOpportunityTools(defineTool, deps) {
791
803
  firstEntity?.profile
792
804
  ?.avatar ??
793
805
  null,
794
- mainText: viewerCentricCardSummary(reasoning, counterpartName, MINIMAL_MAIN_TEXT_MAX_CHARS, undefined, // viewerName not available in this context; introducer name passed separately
795
- introducerUser?.name ?? undefined),
806
+ mainText: safeFallbackSummary(reasoning, {
807
+ counterpartName,
808
+ // viewerName not available in this context; introducer name passed separately
809
+ introducerName: introducerUser?.name ?? undefined,
810
+ maxChars: MINIMAL_MAIN_TEXT_MAX_CHARS,
811
+ emptyText: "A suggested connection.",
812
+ }),
796
813
  cta: "Start a conversation to connect.",
797
814
  headline,
798
815
  primaryActionLabel,
@@ -1111,9 +1128,7 @@ export function createOpportunityTools(defineTool, deps) {
1111
1128
  userId: opp.userId,
1112
1129
  name: opp.name,
1113
1130
  avatar: opp.avatar,
1114
- mainText: opp.homeCardPresentation?.personalizedSummary ??
1115
- opp.matchReason ??
1116
- "",
1131
+ mainText: getSafePresentationOrSkip(opp, { counterpartName: opp.name })?.summary ?? "",
1117
1132
  cta: opp.homeCardPresentation?.suggestedAction,
1118
1133
  headline: opp.homeCardPresentation?.headline,
1119
1134
  primaryActionLabel: opp.homeCardPresentation?.primaryActionLabel,
@@ -1135,6 +1150,7 @@ export function createOpportunityTools(defineTool, deps) {
1135
1150
  await attachActionableLinks(card, {
1136
1151
  viewerId: context.userId,
1137
1152
  viewerApproved: source?.viewerApproved,
1153
+ viewerActedAt: source?.viewerActedAt,
1138
1154
  counterpartUserId: source?.userId ?? card.userId,
1139
1155
  mintConnectLink,
1140
1156
  frontendUrl: deps.frontendUrl,
@@ -1672,6 +1688,7 @@ export function createOpportunityTools(defineTool, deps) {
1672
1688
  await attachActionableLinks(card, {
1673
1689
  viewerId: context.userId,
1674
1690
  viewerApproved,
1691
+ viewerActedAt: viewerActor?.actedAt ?? null,
1675
1692
  counterpartUserId,
1676
1693
  mintConnectLink: deps.mintConnectLink,
1677
1694
  frontendUrl: deps.frontendUrl,
@@ -1823,6 +1840,7 @@ export function createOpportunityTools(defineTool, deps) {
1823
1840
  await attachActionableLinks(cardData, {
1824
1841
  viewerId: context.userId,
1825
1842
  viewerApproved,
1843
+ viewerActedAt: viewerActor?.actedAt ?? null,
1826
1844
  counterpartUserId,
1827
1845
  mintConnectLink: deps.mintConnectLink,
1828
1846
  frontendUrl: deps.frontendUrl,