@indexnetwork/protocol 66.0.0-rc.611.1 → 66.0.0-rc.613.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.
|
@@ -47,13 +47,14 @@ export interface OpportunityCardsDeps {
|
|
|
47
47
|
* @param deps - Database, cache, and presenter.
|
|
48
48
|
* @param opportunity - The opportunity to present.
|
|
49
49
|
* @param viewerId - The viewing user.
|
|
50
|
-
* @param options - `intentId` focuses viewer context on one intent; `skeleton` skips the presenter.
|
|
50
|
+
* @param options - `intentId` focuses viewer context on one intent; `skeleton` skips the presenter; `noCache` skips the stored-card read.
|
|
51
51
|
* @returns The card, or null when the counterpart's name cannot be resolved.
|
|
52
52
|
* @throws When the presenter fails.
|
|
53
53
|
*/
|
|
54
54
|
export declare function presentOpportunityCard(deps: OpportunityCardsDeps, opportunity: Opportunity, viewerId: string, options?: {
|
|
55
55
|
intentId?: string;
|
|
56
56
|
skeleton?: boolean;
|
|
57
|
+
noCache?: boolean;
|
|
57
58
|
}): Promise<OpportunityCard | null>;
|
|
58
59
|
/**
|
|
59
60
|
* List the viewer's opportunities in the given statuses as presented cards,
|
|
@@ -10,7 +10,6 @@ import { canUserSeeOpportunity, isActionableForViewer } from './opportunity.util
|
|
|
10
10
|
import { getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from './opportunity.labels.js';
|
|
11
11
|
const logger = protocolLogger('OpportunityCards');
|
|
12
12
|
const PRESENTATION_CONCURRENCY = 50;
|
|
13
|
-
const CARD_CACHE_TTL = 24 * 60 * 60;
|
|
14
13
|
const ROLE_PRIORITY = new Map([
|
|
15
14
|
['patient', 0],
|
|
16
15
|
['party', 1],
|
|
@@ -37,7 +36,7 @@ function counterpartUserIds(opportunity, viewerId) {
|
|
|
37
36
|
* @param deps - Database, cache, and presenter.
|
|
38
37
|
* @param opportunity - The opportunity to present.
|
|
39
38
|
* @param viewerId - The viewing user.
|
|
40
|
-
* @param options - `intentId` focuses viewer context on one intent; `skeleton` skips the presenter.
|
|
39
|
+
* @param options - `intentId` focuses viewer context on one intent; `skeleton` skips the presenter; `noCache` skips the stored-card read.
|
|
41
40
|
* @returns The card, or null when the counterpart's name cannot be resolved.
|
|
42
41
|
* @throws When the presenter fails.
|
|
43
42
|
*/
|
|
@@ -47,6 +46,18 @@ export async function presentOpportunityCard(deps, opportunity, viewerId, option
|
|
|
47
46
|
const counterpart = pickDisplayCounterpartActor(opportunity, viewerId);
|
|
48
47
|
if (!counterpart)
|
|
49
48
|
return null;
|
|
49
|
+
const cacheable = opportunity.status !== 'negotiating';
|
|
50
|
+
const cacheKey = buildOpportunityCardCacheKey(opportunity.id, viewerId, options.intentId);
|
|
51
|
+
if (cacheable && !options.skeleton && !options.noCache) {
|
|
52
|
+
try {
|
|
53
|
+
const hit = await deps.cache.get(cacheKey);
|
|
54
|
+
if (hit)
|
|
55
|
+
return { ...hit, status: opportunity.status };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
logger.warn('card cache read failed, presenting', { opportunityId: opportunity.id, error });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
50
61
|
const user = await database.getUser(counterpart.userId).catch(() => null);
|
|
51
62
|
let name = user?.name?.trim();
|
|
52
63
|
if (!name) {
|
|
@@ -78,7 +89,7 @@ export async function presentOpportunityCard(deps, opportunity, viewerId, option
|
|
|
78
89
|
opportunityStatus: opportunity.status,
|
|
79
90
|
...(negotiationContext ? { negotiationContext } : {}),
|
|
80
91
|
});
|
|
81
|
-
|
|
92
|
+
const card = {
|
|
82
93
|
...identity,
|
|
83
94
|
mainText: presentation.personalizedSummary,
|
|
84
95
|
cta: presentation.suggestedAction,
|
|
@@ -86,6 +97,12 @@ export async function presentOpportunityCard(deps, opportunity, viewerId, option
|
|
|
86
97
|
mutualIntentsLabel: presentation.mutualIntentsLabel,
|
|
87
98
|
narratorChip: { name: 'Index', text: presentation.narratorRemark },
|
|
88
99
|
};
|
|
100
|
+
if (cacheable) {
|
|
101
|
+
await deps.cache.set(cacheKey, card).catch((error) => {
|
|
102
|
+
logger.warn('card cache write failed', { opportunityId: opportunity.id, error });
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return card;
|
|
89
106
|
}
|
|
90
107
|
/**
|
|
91
108
|
* List the viewer's opportunities in the given statuses as presented cards,
|
|
@@ -120,7 +137,7 @@ export async function listOpportunityCards(deps, input) {
|
|
|
120
137
|
return true;
|
|
121
138
|
}).slice(0, input.limit);
|
|
122
139
|
const cacheable = (opp) => opp.status !== 'negotiating';
|
|
123
|
-
const keyFor = (opp) => buildOpportunityCardCacheKey(opp.id,
|
|
140
|
+
const keyFor = (opp) => buildOpportunityCardCacheKey(opp.id, viewerId, intentId);
|
|
124
141
|
const cacheableOpps = input.noCache ? [] : opportunities.filter(cacheable);
|
|
125
142
|
const cached = new Map();
|
|
126
143
|
if (cacheableOpps.length > 0) {
|
|
@@ -144,9 +161,13 @@ export async function listOpportunityCards(deps, input) {
|
|
|
144
161
|
if (hit)
|
|
145
162
|
return hit;
|
|
146
163
|
try {
|
|
147
|
-
const card = await presentOpportunityCard(deps, opp, viewerId, {
|
|
164
|
+
const card = await presentOpportunityCard(deps, opp, viewerId, {
|
|
165
|
+
intentId,
|
|
166
|
+
skeleton: input.skeleton,
|
|
167
|
+
noCache: input.noCache,
|
|
168
|
+
});
|
|
148
169
|
if (card && !card.presentationPending && cacheable(opp)) {
|
|
149
|
-
await deps.cache.set(keyFor(opp), card
|
|
170
|
+
await deps.cache.set(keyFor(opp), card).catch((error) => {
|
|
150
171
|
logger.warn('card cache write failed', { opportunityId: opp.id, error });
|
|
151
172
|
});
|
|
152
173
|
}
|
|
@@ -20,7 +20,7 @@ export interface UserInfo {
|
|
|
20
20
|
}
|
|
21
21
|
/** Cache namespace for opportunity presentation copy. Bump to invalidate copy safety changes. */
|
|
22
22
|
export declare const OPPORTUNITY_PRESENTATION_CACHE_VERSION = "v2";
|
|
23
|
-
export declare function buildOpportunityCardCacheKey(opportunityId: string,
|
|
23
|
+
export declare function buildOpportunityCardCacheKey(opportunityId: string, viewerId: string, focusedViewerIntentId?: string): string;
|
|
24
24
|
export declare function buildApiChatCardPresentationCacheKey(opportunityId: string, viewerId: string): string;
|
|
25
25
|
/**
|
|
26
26
|
* Opportunity Presenter Agent
|
|
@@ -27,9 +27,9 @@ import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
|
27
27
|
// ──────────────────────────────────────────────────────────────────────
|
|
28
28
|
/** Cache namespace for opportunity presentation copy. Bump to invalidate copy safety changes. */
|
|
29
29
|
export const OPPORTUNITY_PRESENTATION_CACHE_VERSION = "v2";
|
|
30
|
-
export function buildOpportunityCardCacheKey(opportunityId,
|
|
30
|
+
export function buildOpportunityCardCacheKey(opportunityId, viewerId, focusedViewerIntentId) {
|
|
31
31
|
const scope = focusedViewerIntentId ? `:intent:${focusedViewerIntentId}` : "";
|
|
32
|
-
return `card:${
|
|
32
|
+
return `card:${opportunityId}:${viewerId}${scope}`;
|
|
33
33
|
}
|
|
34
34
|
export function buildApiChatCardPresentationCacheKey(opportunityId, viewerId) {
|
|
35
35
|
return `chat:${OPPORTUNITY_PRESENTATION_CACHE_VERSION}:card:${opportunityId}:${viewerId}`;
|