@indexnetwork/protocol 14.3.2-rc.477.1 → 16.1.1-rc.478.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/CHANGELOG.md +107 -0
- package/IMPLEMENTATION.md +50 -52
- package/STABILITY.md +3 -3
- package/dist/chat/chat.agent.js +2 -2
- package/dist/chat/chat.graph.d.ts +41 -1
- package/dist/chat/chat.graph.js +108 -127
- package/dist/discovery/hyde.frame.d.ts +4 -4
- package/dist/discovery/hyde.graph.d.ts +71 -12
- package/dist/discovery/hyde.graph.js +337 -335
- package/dist/discovery/lens.inferrer.d.ts +6 -6
- package/dist/enrichment/enrichment.graph.d.ts +127 -9
- package/dist/enrichment/enrichment.graph.js +633 -655
- package/dist/enrichment/enrichment.state.d.ts +1 -1
- package/dist/enrichment/enrichment.tools.context-read.d.ts +10 -0
- package/dist/enrichment/enrichment.tools.context-read.js +353 -0
- package/dist/enrichment/enrichment.tools.context-write.d.ts +9 -0
- package/dist/enrichment/enrichment.tools.context-write.js +417 -0
- package/dist/enrichment/enrichment.tools.d.ts +11 -1
- package/dist/enrichment/enrichment.tools.helpers.d.ts +139 -0
- package/dist/enrichment/enrichment.tools.helpers.js +234 -0
- package/dist/enrichment/enrichment.tools.js +16 -975
- package/dist/index.d.ts +27 -48
- package/dist/index.js +17 -27
- package/dist/intents/application/intent.graph.d.ts +71 -67
- package/dist/intents/application/intent.graph.execute.d.ts +59 -0
- package/dist/intents/application/intent.graph.execute.js +301 -0
- package/dist/intents/application/intent.graph.infer.d.ts +44 -0
- package/dist/intents/application/intent.graph.infer.js +97 -0
- package/dist/intents/application/intent.graph.js +96 -888
- package/dist/intents/application/intent.graph.reconcile.d.ts +71 -0
- package/dist/intents/application/intent.graph.reconcile.js +274 -0
- package/dist/intents/application/intent.graph.shared.d.ts +70 -0
- package/dist/intents/application/intent.graph.shared.js +153 -0
- package/dist/intents/domain/intent.state.d.ts +1 -1
- package/dist/maintenance/maintenance.graph.d.ts +66 -3
- package/dist/maintenance/maintenance.graph.js +155 -156
- package/dist/mcp/mcp.authorization-policy.d.ts +24 -28
- package/dist/mcp/mcp.authorization-policy.js +14 -34
- package/dist/mcp/mcp.server.d.ts +3 -3
- package/dist/mcp/mcp.server.js +12 -16
- package/dist/negotiations/application/negotiation.candidates.d.ts +83 -0
- package/dist/negotiations/application/negotiation.candidates.js +162 -0
- package/dist/negotiations/application/negotiation.graph.d.ts +91 -157
- package/dist/negotiations/application/negotiation.graph.finalize.d.ts +5 -0
- package/dist/negotiations/application/negotiation.graph.finalize.js +280 -0
- package/dist/negotiations/application/negotiation.graph.init.d.ts +54 -0
- package/dist/negotiations/application/negotiation.graph.init.js +227 -0
- package/dist/negotiations/application/negotiation.graph.js +69 -1388
- package/dist/negotiations/application/negotiation.graph.screen.d.ts +23 -0
- package/dist/negotiations/application/negotiation.graph.screen.js +108 -0
- package/dist/negotiations/application/negotiation.graph.shared.d.ts +75 -0
- package/dist/negotiations/application/negotiation.graph.shared.js +125 -0
- package/dist/negotiations/application/negotiation.graph.turn.d.ts +105 -0
- package/dist/negotiations/application/negotiation.graph.turn.js +484 -0
- package/dist/negotiations/domain/negotiation.state.d.ts +1 -1
- package/dist/negotiations/domain/negotiation.state.js +0 -1
- package/dist/networks/application/indexer.graph.d.ts +165 -7
- package/dist/networks/application/indexer.graph.js +339 -388
- package/dist/networks/application/indexer.state.d.ts +1 -1
- package/dist/networks/application/membership.graph.d.ts +83 -5
- package/dist/networks/application/membership.graph.js +177 -207
- package/dist/networks/application/network.graph.d.ts +148 -5
- package/dist/networks/application/network.graph.js +249 -278
- package/dist/networks/domain/membership.state.d.ts +1 -1
- package/dist/networks/domain/network.state.d.ts +1 -1
- package/dist/opportunities/application/delivery-card.cache.d.ts +1 -1
- package/dist/opportunities/application/delivery-card.cache.js +2 -2
- package/dist/opportunities/application/index.d.ts +2 -2
- package/dist/opportunities/application/index.js +2 -2
- package/dist/opportunities/application/opportunity.evaluator.js +1 -1
- package/dist/opportunities/application/opportunity.graph.d.ts +686 -473
- package/dist/opportunities/application/opportunity.graph.discovery-strategies.d.ts +109 -0
- package/dist/opportunities/application/opportunity.graph.discovery-strategies.js +451 -0
- package/dist/opportunities/application/opportunity.graph.discovery.d.ts +69 -0
- package/dist/opportunities/application/opportunity.graph.discovery.js +397 -0
- package/dist/opportunities/application/opportunity.graph.evaluation.d.ts +82 -0
- package/dist/opportunities/application/opportunity.graph.evaluation.js +608 -0
- package/dist/opportunities/application/opportunity.graph.js +120 -3690
- package/dist/opportunities/application/opportunity.graph.modes.d.ts +538 -0
- package/dist/opportunities/application/opportunity.graph.modes.js +538 -0
- package/dist/opportunities/application/opportunity.graph.negotiate.d.ts +109 -0
- package/dist/opportunities/application/opportunity.graph.negotiate.js +392 -0
- package/dist/opportunities/application/opportunity.graph.persist-node.d.ts +93 -0
- package/dist/opportunities/application/opportunity.graph.persist-node.js +765 -0
- package/dist/opportunities/application/opportunity.graph.prep.d.ts +150 -0
- package/dist/opportunities/application/opportunity.graph.prep.js +381 -0
- package/dist/opportunities/application/opportunity.graph.shared.d.ts +173 -0
- package/dist/opportunities/application/opportunity.graph.shared.js +199 -0
- package/dist/opportunities/application/opportunity.presentation.d.ts +399 -0
- package/dist/opportunities/application/{opportunity.presenter.js → opportunity.presentation.js} +735 -9
- package/dist/opportunities/application/opportunity.tools.cards.d.ts +152 -0
- package/dist/opportunities/application/opportunity.tools.cards.js +235 -0
- package/dist/opportunities/application/opportunity.tools.d.ts +8 -114
- package/dist/opportunities/application/opportunity.tools.js +28 -711
- package/dist/opportunities/application/opportunity.tools.list.d.ts +10 -0
- package/dist/opportunities/application/opportunity.tools.list.js +493 -0
- package/dist/opportunities/domain/index.d.ts +3 -3
- package/dist/opportunities/domain/index.js +3 -3
- package/dist/opportunities/domain/opportunity.state.d.ts +19 -19
- package/dist/opportunities/index.d.ts +6 -6
- package/dist/opportunities/index.js +4 -4
- package/dist/opportunities/ports/opportunity.tools.port.d.ts +1 -1
- package/dist/opportunities/radar/radar.graph.d.ts +57 -13
- package/dist/opportunities/radar/radar.graph.js +470 -471
- package/dist/premises/premise.graph.d.ts +88 -20
- package/dist/premises/premise.graph.js +207 -218
- package/dist/questions/domain/question.schema.d.ts +40 -40
- package/dist/shared/agent/tool.helpers.d.ts +21 -0
- package/dist/shared/agent/tool.registry.d.ts +4 -3
- package/dist/shared/agent/tool.registry.js +1 -1
- package/dist/shared/interfaces/database.capabilities.d.ts +100 -0
- package/dist/shared/interfaces/database.capabilities.js +7 -0
- package/dist/shared/interfaces/database.entities.d.ts +533 -0
- package/dist/shared/interfaces/database.entities.js +10 -0
- package/dist/shared/interfaces/database.identity-queries.d.ts +294 -0
- package/dist/shared/interfaces/database.identity-queries.js +4 -0
- package/dist/shared/interfaces/database.interface.d.ts +15 -2277
- package/dist/shared/interfaces/database.interface.js +8 -0
- package/dist/shared/interfaces/database.member-queries.d.ts +228 -0
- package/dist/shared/interfaces/database.member-queries.js +4 -0
- package/dist/shared/interfaces/database.negotiation.d.ts +305 -0
- package/dist/shared/interfaces/database.negotiation.js +26 -0
- package/dist/shared/interfaces/database.network-queries.d.ts +277 -0
- package/dist/shared/interfaces/database.network-queries.js +4 -0
- package/dist/shared/interfaces/database.opportunity-queries.d.ts +285 -0
- package/dist/shared/interfaces/database.opportunity-queries.js +4 -0
- package/dist/shared/interfaces/database.port.d.ts +322 -0
- package/dist/shared/interfaces/database.port.js +29 -0
- package/dist/shared/schemas/discovery-question.schema.d.ts +14 -14
- package/dist/shared/schemas/negotiation-digest.schema.d.ts +2 -2
- package/package.json +2 -15
- package/dist/opportunities/application/opportunity.card-presentation.d.ts +0 -44
- package/dist/opportunities/application/opportunity.card-presentation.js +0 -93
- package/dist/opportunities/application/opportunity.presenter.d.ts +0 -156
- package/dist/opportunities/domain/opportunity.presentation-cache.d.ts +0 -5
- package/dist/opportunities/domain/opportunity.presentation-cache.js +0 -11
- package/dist/opportunities/domain/opportunity.presentation.d.ts +0 -76
- package/dist/opportunities/domain/opportunity.presentation.js +0 -516
- package/dist/opportunities/domain/opportunity.safe-presentation.d.ts +0 -104
- package/dist/opportunities/domain/opportunity.safe-presentation.js +0 -102
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The database port itself, plus the two access-scoped views over it.
|
|
3
|
+
*
|
|
4
|
+
* `Database` is the union of the four query groups; splitting it into composed
|
|
5
|
+
* interfaces keeps each group readable without changing the type one bit —
|
|
6
|
+
* every `Pick<Database, ...>` alias still resolves exactly as before.
|
|
7
|
+
*/
|
|
8
|
+
import type { UserIdentity } from '../schemas/identity.schema.js';
|
|
9
|
+
import type { NetworkAssignmentMetadata } from '../schemas/network-assignment.schema.js';
|
|
10
|
+
import type { ActiveIntent, ArchiveResult, CreateHydeDocumentData, CreateIntentData, CreateOpportunityData, CreatedIntent, HydeDocument, HydeSourceType, Id, IndexMemberDetails, IndexedIntentDetails, IntentRecord, NetworkAssignmentContext, NetworkMembership, OnboardingState, Opportunity, OpportunityQueryOptions, OpportunityStatus, OwnedIndex, SimilarIntent, SimilarIntentSearchOptions, UpdateIndexSettingsData, UpdateIntentData, UserRecord, UserSocial } from './database.entities.js';
|
|
11
|
+
import type { DatabaseIdentityQueries } from './database.identity-queries.js';
|
|
12
|
+
import type { DatabaseMemberQueries } from './database.member-queries.js';
|
|
13
|
+
import type { DatabaseNetworkQueries } from './database.network-queries.js';
|
|
14
|
+
import type { DatabaseOpportunityQueries } from './database.opportunity-queries.js';
|
|
15
|
+
/**
|
|
16
|
+
* Abstract database interface for performing specific domain operations.
|
|
17
|
+
* Decouples the protocol layer from the infrastructure layer.
|
|
18
|
+
*/
|
|
19
|
+
export interface Database extends DatabaseIdentityQueries, DatabaseNetworkQueries, DatabaseOpportunityQueries, DatabaseMemberQueries {
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Context-bound database for accessing the authenticated user's own resources.
|
|
23
|
+
* Created with authUserId bound at construction; no userId parameter needed on methods.
|
|
24
|
+
*
|
|
25
|
+
* **NOT network-scoped**: Returns ALL of the user's own resources regardless of index.
|
|
26
|
+
* This is critical for the IntentReconciler which needs the full picture for deduplication.
|
|
27
|
+
*
|
|
28
|
+
* Use via `createUserDatabase(db, authUserId)` factory function.
|
|
29
|
+
*/
|
|
30
|
+
export interface AgentActivitySummary {
|
|
31
|
+
/** The requested reporting window, in hours. */
|
|
32
|
+
sinceHours: number;
|
|
33
|
+
/** Number of the user's own non-archived ACTIVE intents. */
|
|
34
|
+
liveSignalsWatched: number;
|
|
35
|
+
/** Opportunities created in the window and linked to one of the user's intents. */
|
|
36
|
+
opportunitiesSurfaced: number;
|
|
37
|
+
/** Opportunity counts grouped by the user's own signal. */
|
|
38
|
+
opportunitiesBySignal: Array<{
|
|
39
|
+
intentId: string;
|
|
40
|
+
title: string;
|
|
41
|
+
count: number;
|
|
42
|
+
}>;
|
|
43
|
+
/** Current, non-expired questions waiting for the user, grouped by affected mode (QuestionMode values). Meta-network. */
|
|
44
|
+
pendingQuestionsByMode: Record<string, number>;
|
|
45
|
+
/** Questions answered by the user during the window, grouped by affected mode (QuestionMode values). Meta-network. */
|
|
46
|
+
answeredQuestionsByMode: Record<string, number>;
|
|
47
|
+
/** Distinct opportunity negotiations started during the window. */
|
|
48
|
+
negotiationsStarted: number;
|
|
49
|
+
/** Distinct opportunity negotiations completed during the window. */
|
|
50
|
+
negotiationsCompleted: number;
|
|
51
|
+
}
|
|
52
|
+
export interface UserDatabase {
|
|
53
|
+
/** The bound authenticated user ID */
|
|
54
|
+
readonly authUserId: string;
|
|
55
|
+
/** Get the authenticated user's profile. */
|
|
56
|
+
getProfile(): Promise<UserIdentity | null>;
|
|
57
|
+
/** Get the authenticated user's profile with row ID. */
|
|
58
|
+
getProfileByUserId(): Promise<(UserIdentity & {
|
|
59
|
+
id: string;
|
|
60
|
+
}) | null>;
|
|
61
|
+
/** Save/update the authenticated user's profile. */
|
|
62
|
+
saveProfile(profile: UserIdentity): Promise<void>;
|
|
63
|
+
/** Delete the authenticated user's profile. */
|
|
64
|
+
deleteProfile(): Promise<void>;
|
|
65
|
+
/** Get the authenticated user's basic record (name, email, socials). */
|
|
66
|
+
getUser(): Promise<UserRecord | null>;
|
|
67
|
+
/** Update the authenticated user's account fields. */
|
|
68
|
+
updateUser(data: {
|
|
69
|
+
name?: string;
|
|
70
|
+
intro?: string;
|
|
71
|
+
location?: string;
|
|
72
|
+
onboarding?: OnboardingState;
|
|
73
|
+
}): Promise<UserRecord | null>;
|
|
74
|
+
getUserSocials(): Promise<UserSocial[]>;
|
|
75
|
+
setUserSocials(socials: {
|
|
76
|
+
label: string;
|
|
77
|
+
value: string;
|
|
78
|
+
}[]): Promise<void>;
|
|
79
|
+
/** Get ALL active intents for the authenticated user (not index-filtered). */
|
|
80
|
+
getActiveIntents(): Promise<ActiveIntent[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Case-insensitive substring search over the authenticated user's own
|
|
83
|
+
* active intents. Matches against `payload` and `summary`. Most recent first.
|
|
84
|
+
*/
|
|
85
|
+
searchOwnIntents(q: string, limit: number): Promise<Array<{
|
|
86
|
+
id: string;
|
|
87
|
+
payload: string;
|
|
88
|
+
summary: string | null;
|
|
89
|
+
createdAt: Date;
|
|
90
|
+
}>>;
|
|
91
|
+
/** Get a single intent by ID (ownership enforced). */
|
|
92
|
+
getIntent(intentId: string): Promise<IntentRecord | null>;
|
|
93
|
+
/** Create a new intent for the authenticated user. */
|
|
94
|
+
createIntent(data: Omit<CreateIntentData, 'userId'>): Promise<CreatedIntent>;
|
|
95
|
+
/** Update an intent owned by the authenticated user. */
|
|
96
|
+
updateIntent(intentId: string, data: UpdateIntentData): Promise<CreatedIntent | null>;
|
|
97
|
+
/** Archive an intent owned by the authenticated user. */
|
|
98
|
+
archiveIntent(intentId: string): Promise<ArchiveResult>;
|
|
99
|
+
/** Find similar intents among the user's own intents (for deduplication). */
|
|
100
|
+
findSimilarIntents(embedding: number[], options?: SimilarIntentSearchOptions): Promise<SimilarIntent[]>;
|
|
101
|
+
/** Get intent fields for indexing (own intent). */
|
|
102
|
+
getIntentForIndexing(intentId: string): Promise<{
|
|
103
|
+
id: string;
|
|
104
|
+
payload: string;
|
|
105
|
+
userId: string;
|
|
106
|
+
sourceType: string | null;
|
|
107
|
+
sourceId: string | null;
|
|
108
|
+
} | null>;
|
|
109
|
+
/** Associate an intent with networks. */
|
|
110
|
+
associateIntentWithNetworks(intentId: string, networkIds: string[]): Promise<void>;
|
|
111
|
+
/** Assign an intent to an index. */
|
|
112
|
+
assignIntentToNetwork(intentId: string, networkId: string, relevancyScore?: number, assignmentMetadata?: NetworkAssignmentMetadata): Promise<void>;
|
|
113
|
+
/** Unassign an intent from an index. */
|
|
114
|
+
unassignIntentFromIndex(intentId: string, networkId: string): Promise<void>;
|
|
115
|
+
/** Get network IDs for an intent. */
|
|
116
|
+
getNetworkIdsForIntent(intentId: string): Promise<string[]>;
|
|
117
|
+
/** Check if intent is assigned to index. */
|
|
118
|
+
isIntentAssignedToIndex(intentId: string, networkId: string): Promise<boolean>;
|
|
119
|
+
/** Get all network memberships for the authenticated user. */
|
|
120
|
+
getNetworkMemberships(): Promise<NetworkMembership[]>;
|
|
121
|
+
/** Get network IDs with auto-assign enabled for the authenticated user. */
|
|
122
|
+
getUserIndexIds(): Promise<string[]>;
|
|
123
|
+
/** Get indexes owned by the authenticated user. */
|
|
124
|
+
getOwnedIndexes(): Promise<OwnedIndex[]>;
|
|
125
|
+
/** Get a specific network membership for the authenticated user. */
|
|
126
|
+
getNetworkMembership(networkId: string): Promise<NetworkMembership | null>;
|
|
127
|
+
/** Get index + member context for the authenticated user (for auto-assign). */
|
|
128
|
+
getNetworkMemberContext(networkId: string): Promise<NetworkAssignmentContext | null>;
|
|
129
|
+
/** Get index + member context for the authenticated user without auto-assign gating. */
|
|
130
|
+
getNetworkAssignmentContext?(networkId: string): Promise<NetworkAssignmentContext | null>;
|
|
131
|
+
/** Create a new index (user becomes owner). */
|
|
132
|
+
createNetwork(data: {
|
|
133
|
+
title: string;
|
|
134
|
+
prompt?: string | null;
|
|
135
|
+
imageUrl?: string | null;
|
|
136
|
+
joinPolicy?: 'anyone' | 'invite_only';
|
|
137
|
+
}): Promise<{
|
|
138
|
+
id: string;
|
|
139
|
+
title: string;
|
|
140
|
+
prompt: string | null;
|
|
141
|
+
imageUrl: string | null;
|
|
142
|
+
permissions: {
|
|
143
|
+
joinPolicy: 'anyone' | 'invite_only';
|
|
144
|
+
invitationLink: {
|
|
145
|
+
code: string;
|
|
146
|
+
} | null;
|
|
147
|
+
};
|
|
148
|
+
}>;
|
|
149
|
+
/** Update index settings (owner only). */
|
|
150
|
+
updateIndexSettings(networkId: string, data: UpdateIndexSettingsData): Promise<OwnedIndex>;
|
|
151
|
+
/** Soft-delete a network (owner only). */
|
|
152
|
+
softDeleteNetwork(networkId: string): Promise<void>;
|
|
153
|
+
/** Get public networks (joinPolicy 'anyone') that the user has not joined. */
|
|
154
|
+
getPublicIndexesNotJoined(): Promise<{
|
|
155
|
+
networks: Array<{
|
|
156
|
+
id: string;
|
|
157
|
+
title: string;
|
|
158
|
+
prompt: string | null;
|
|
159
|
+
memberCount: number;
|
|
160
|
+
owner: {
|
|
161
|
+
id: string;
|
|
162
|
+
name: string;
|
|
163
|
+
avatar: string | null;
|
|
164
|
+
} | null;
|
|
165
|
+
}>;
|
|
166
|
+
}>;
|
|
167
|
+
/** Join a public network (validates joinPolicy === 'anyone'). */
|
|
168
|
+
joinPublicNetwork(networkId: string): Promise<{
|
|
169
|
+
success: boolean;
|
|
170
|
+
alreadyMember?: boolean;
|
|
171
|
+
}>;
|
|
172
|
+
/**
|
|
173
|
+
* Summarize the authenticated user's own agent activity without counterparty rows.
|
|
174
|
+
* When `networkId` is present (a network agent's bound community), the
|
|
175
|
+
* network-bound aggregates (opportunity and negotiation counts) are narrowed
|
|
176
|
+
* to that community inside the query; own-signal and question aggregates are
|
|
177
|
+
* meta-network and stay global.
|
|
178
|
+
*/
|
|
179
|
+
getAgentActivitySummary(input: {
|
|
180
|
+
sinceHours: number;
|
|
181
|
+
networkId?: string;
|
|
182
|
+
}): Promise<AgentActivitySummary>;
|
|
183
|
+
/** Get opportunities where the authenticated user is an actor. */
|
|
184
|
+
getOpportunitiesForUser(options?: OpportunityQueryOptions): Promise<Opportunity[]>;
|
|
185
|
+
/** Get a specific opportunity (if user is an actor). */
|
|
186
|
+
getOpportunity(id: string): Promise<Opportunity | null>;
|
|
187
|
+
/** Update an opportunity's status (if user is an actor). acceptedBy is derived from the auth context. */
|
|
188
|
+
updateOpportunityStatus(id: string, status: OpportunityStatus): Promise<Opportunity | null>;
|
|
189
|
+
/** Accept sibling opportunities between the authenticated user and another actor. */
|
|
190
|
+
acceptSiblingOpportunities(counterpartUserId: string, excludeOpportunityId: string): Promise<string[]>;
|
|
191
|
+
/** Get a HyDE document for the user's own source. */
|
|
192
|
+
getHydeDocument(sourceType: HydeSourceType, sourceId: string, strategy: string): Promise<HydeDocument | null>;
|
|
193
|
+
/** Get all HyDE documents for the user's own source. */
|
|
194
|
+
getHydeDocumentsForSource(sourceType: HydeSourceType, sourceId: string): Promise<HydeDocument[]>;
|
|
195
|
+
/** Save a HyDE document for the user's own source. */
|
|
196
|
+
saveHydeDocument(data: CreateHydeDocumentData): Promise<HydeDocument>;
|
|
197
|
+
/** Delete HyDE documents for the user's own source. */
|
|
198
|
+
deleteHydeDocumentsForSource(sourceType: HydeSourceType, sourceId: string): Promise<number>;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Context-bound database for LLM/system operations that access cross-user resources.
|
|
202
|
+
* Created with authUserId + indexScope[]; validates membership before access.
|
|
203
|
+
*
|
|
204
|
+
* **Network-scoped**: All cross-user operations are restricted to users/resources
|
|
205
|
+
* within the bound indexScope[]. This prevents the LLM from accessing arbitrary users' data.
|
|
206
|
+
*
|
|
207
|
+
* Use via `createSystemDatabase(db, authUserId, indexScope)` factory function.
|
|
208
|
+
*/
|
|
209
|
+
export interface SystemDatabase {
|
|
210
|
+
/** The bound authenticated user ID */
|
|
211
|
+
readonly authUserId: string;
|
|
212
|
+
/** The indexes the authenticated user has access to (determines cross-user scope) */
|
|
213
|
+
readonly indexScope: string[];
|
|
214
|
+
/** Get a user's profile (requires shared network membership). */
|
|
215
|
+
getProfile(userId: string): Promise<UserIdentity | null>;
|
|
216
|
+
/** Get a user's basic record (requires shared network membership). */
|
|
217
|
+
getUser(userId: string): Promise<UserRecord | null>;
|
|
218
|
+
/** Get all intents in an index (cross-user, requires membership). */
|
|
219
|
+
getIntentsInIndex(networkId: string, options?: {
|
|
220
|
+
limit?: number;
|
|
221
|
+
offset?: number;
|
|
222
|
+
}): Promise<IndexedIntentDetails[]>;
|
|
223
|
+
/** Get a specific user's intents in an index (requires shared membership). */
|
|
224
|
+
getUserIntentsInIndex(userId: string, networkId: string): Promise<ActiveIntent[]>;
|
|
225
|
+
/**
|
|
226
|
+
* Get the caller's own active intents across a set of indexes.
|
|
227
|
+
* Returns intents owned by `userId` that are linked (via intent_networks)
|
|
228
|
+
* to at least one of `indexIds`. Used by network-scoped agents to honor
|
|
229
|
+
* indexScope without falling back to global getActiveIntents (which would
|
|
230
|
+
* include intents in indexes outside scope).
|
|
231
|
+
*
|
|
232
|
+
* @param userId - The intent owner (always the caller).
|
|
233
|
+
* @param indexIds - The set of network IDs to filter on. Empty → empty result.
|
|
234
|
+
* @returns Active intents owned by userId in any of indexIds, deduped by intent id.
|
|
235
|
+
*/
|
|
236
|
+
getActiveIntentsAcrossIndexes(userId: string, indexIds: string[]): Promise<ActiveIntent[]>;
|
|
237
|
+
/** Get a single intent by ID (if in scope). */
|
|
238
|
+
getIntent(intentId: string): Promise<IntentRecord | null>;
|
|
239
|
+
/** Find similar intents across users within the network scope. */
|
|
240
|
+
findSimilarIntentsInScope(embedding: number[], options?: SimilarIntentSearchOptions): Promise<SimilarIntent[]>;
|
|
241
|
+
/** Check if a user is a member of an index. */
|
|
242
|
+
isNetworkMember(networkId: string, userId: string): Promise<boolean>;
|
|
243
|
+
/** Check if a user is an owner of an index. */
|
|
244
|
+
isIndexOwner(networkId: string, userId: string): Promise<boolean>;
|
|
245
|
+
/** Get all members of an index (requires membership). */
|
|
246
|
+
getNetworkMembers(networkId: string): Promise<IndexMemberDetails[]>;
|
|
247
|
+
/** Get all members across all networks in scope (deduplicated). */
|
|
248
|
+
getMembersFromScope(): Promise<{
|
|
249
|
+
userId: Id<'users'>;
|
|
250
|
+
name: string;
|
|
251
|
+
avatar: string | null;
|
|
252
|
+
}[]>;
|
|
253
|
+
/** Add a user to an index (requires ownership or 'anyone' policy). */
|
|
254
|
+
addMemberToNetwork(networkId: string, userId: string, role: 'owner' | 'member'): Promise<{
|
|
255
|
+
success: boolean;
|
|
256
|
+
alreadyMember?: boolean;
|
|
257
|
+
}>;
|
|
258
|
+
/** Remove a user from an index (requires ownership). Cannot remove the owner. */
|
|
259
|
+
removeMemberFromIndex(networkId: string, userId: string): Promise<{
|
|
260
|
+
success: boolean;
|
|
261
|
+
wasOwner?: boolean;
|
|
262
|
+
notMember?: boolean;
|
|
263
|
+
}>;
|
|
264
|
+
/** Get index info by ID with core fields (requires scope). */
|
|
265
|
+
getNetwork(networkId: string): Promise<{
|
|
266
|
+
id: string;
|
|
267
|
+
title: string;
|
|
268
|
+
prompt?: string | null;
|
|
269
|
+
type?: string;
|
|
270
|
+
metadata?: Record<string, unknown> | null;
|
|
271
|
+
permissions?: Record<string, unknown> | null;
|
|
272
|
+
} | null>;
|
|
273
|
+
/** Get index with permissions (requires scope). */
|
|
274
|
+
getNetworkWithPermissions(networkId: string): Promise<{
|
|
275
|
+
id: string;
|
|
276
|
+
title: string;
|
|
277
|
+
permissions: {
|
|
278
|
+
joinPolicy: 'anyone' | 'invite_only';
|
|
279
|
+
};
|
|
280
|
+
} | null>;
|
|
281
|
+
/** Get member count for an index (requires scope). */
|
|
282
|
+
getNetworkMemberCount(networkId: string): Promise<number>;
|
|
283
|
+
/** Create an opportunity (cross-user). */
|
|
284
|
+
createOpportunity(data: CreateOpportunityData): Promise<Opportunity>;
|
|
285
|
+
/** Create opportunity and expire overlapping ones atomically. */
|
|
286
|
+
createOpportunityAndExpireIds(data: CreateOpportunityData, expireIds: string[]): Promise<{
|
|
287
|
+
created: Opportunity;
|
|
288
|
+
expired: Opportunity[];
|
|
289
|
+
}>;
|
|
290
|
+
/** Get an opportunity by ID (for system processing). */
|
|
291
|
+
getOpportunity(id: string): Promise<Opportunity | null>;
|
|
292
|
+
/** Get opportunities for an index (requires membership). */
|
|
293
|
+
getOpportunitiesForNetwork(networkId: string, options?: OpportunityQueryOptions): Promise<Opportunity[]>;
|
|
294
|
+
/** Update an opportunity's status (system-level). */
|
|
295
|
+
updateOpportunityStatus(id: string, status: OpportunityStatus, acceptedBy?: string): Promise<Opportunity | null>;
|
|
296
|
+
/** Stamp actor `actedAt` + update status atomically (system-level). */
|
|
297
|
+
stampOpportunityActorAction(id: string, actorUserId: string, status: OpportunityStatus, acceptedBy?: string): Promise<Opportunity | null>;
|
|
298
|
+
/** Check if opportunity exists between actors in an index. */
|
|
299
|
+
opportunityExistsBetweenActors(actorIds: string[], networkId: string): Promise<boolean>;
|
|
300
|
+
/** Find opportunities by actor IDs with optional include/exclude status filters. */
|
|
301
|
+
findOpportunitiesByActors(actorIds: string[], options?: {
|
|
302
|
+
includeIntroducers?: boolean;
|
|
303
|
+
statuses?: OpportunityStatus[];
|
|
304
|
+
excludeStatuses?: OpportunityStatus[];
|
|
305
|
+
}): Promise<Opportunity[]>;
|
|
306
|
+
/** Expire opportunities referencing an intent. */
|
|
307
|
+
expireOpportunitiesByIntent(intentId: string): Promise<number>;
|
|
308
|
+
/** Expire opportunities for a removed member. */
|
|
309
|
+
expireOpportunitiesForRemovedMember(networkId: string, userId: string): Promise<number>;
|
|
310
|
+
/** Expire stale opportunities (maintenance). */
|
|
311
|
+
expireStaleOpportunities(): Promise<number>;
|
|
312
|
+
/** Get a HyDE document (cross-user for matching). */
|
|
313
|
+
getHydeDocument(sourceType: HydeSourceType, sourceId: string, strategy: string): Promise<HydeDocument | null>;
|
|
314
|
+
/** Get all HyDE documents for a source (cross-user). */
|
|
315
|
+
getHydeDocumentsForSource(sourceType: HydeSourceType, sourceId: string): Promise<HydeDocument[]>;
|
|
316
|
+
/** Save a HyDE document (system-level). */
|
|
317
|
+
saveHydeDocument(data: CreateHydeDocumentData): Promise<HydeDocument>;
|
|
318
|
+
/** Delete expired HyDE documents (maintenance). */
|
|
319
|
+
deleteExpiredHydeDocuments(): Promise<number>;
|
|
320
|
+
/** Get stale HyDE documents for refresh (maintenance). */
|
|
321
|
+
getStaleHydeDocuments(threshold: Date): Promise<HydeDocument[]>;
|
|
322
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The database port itself, plus the two access-scoped views over it.
|
|
3
|
+
*
|
|
4
|
+
* `Database` is the union of the four query groups; splitting it into composed
|
|
5
|
+
* interfaces keeps each group readable without changing the type one bit —
|
|
6
|
+
* every `Pick<Database, ...>` alias still resolves exactly as before.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
10
|
+
// NARROWED DATABASE INTERFACES (Interface Segregation)
|
|
11
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
12
|
+
//
|
|
13
|
+
// These narrowed types are Pick types from the raw Database interface.
|
|
14
|
+
// They are used by graph factories to enforce interface segregation at compile time.
|
|
15
|
+
//
|
|
16
|
+
// Access control relationship to UserDatabase/SystemDatabase:
|
|
17
|
+
// - EnrichmentGraphDatabase → maps to UserDatabase (user's own profile operations)
|
|
18
|
+
// - IntentGraphDatabase → maps to UserDatabase (mutations) + SystemDatabase (reads)
|
|
19
|
+
// - OpportunityGraphDatabase → maps to SystemDatabase (cross-user operations)
|
|
20
|
+
// - NetworkGraphDatabase → maps to UserDatabase (own indexes)
|
|
21
|
+
// - IntentNetworkGraphDatabase → maps to both (own intent ↔ shared network)
|
|
22
|
+
// - NetworkMembershipGraphDatabase → maps to SystemDatabase (cross-user)
|
|
23
|
+
// - HydeGraphDatabase → maps to both (own HyDE vs cross-user matching)
|
|
24
|
+
//
|
|
25
|
+
// Graphs continue to use these narrowed types because:
|
|
26
|
+
// 1. They receive the raw database adapter with userId passed per method
|
|
27
|
+
// 2. Access control is enforced at the tool/factory layer via createUserDatabase/createSystemDatabase
|
|
28
|
+
// 3. These types ensure graphs only depend on methods they actually use
|
|
29
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -131,17 +131,7 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
131
131
|
}>;
|
|
132
132
|
seedAssessmentScore: z.ZodOptional<z.ZodNumber>;
|
|
133
133
|
}, "strip", z.ZodTypeAny, {
|
|
134
|
-
counterpartyId: string;
|
|
135
|
-
counterpartyHint: string;
|
|
136
134
|
indexContext: string;
|
|
137
|
-
turns: {
|
|
138
|
-
reasoning: string;
|
|
139
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
140
|
-
suggestedRoles: {
|
|
141
|
-
ownUser: "agent" | "patient" | "peer";
|
|
142
|
-
otherUser: "agent" | "patient" | "peer";
|
|
143
|
-
};
|
|
144
|
-
}[];
|
|
145
135
|
outcome: {
|
|
146
136
|
reasoning: string;
|
|
147
137
|
hasOpportunity: boolean;
|
|
@@ -151,11 +141,8 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
151
141
|
role: "agent" | "patient" | "peer";
|
|
152
142
|
}[] | undefined;
|
|
153
143
|
};
|
|
154
|
-
seedAssessmentScore?: number | undefined;
|
|
155
|
-
}, {
|
|
156
|
-
counterpartyId: string;
|
|
157
144
|
counterpartyHint: string;
|
|
158
|
-
|
|
145
|
+
counterpartyId: string;
|
|
159
146
|
turns: {
|
|
160
147
|
reasoning: string;
|
|
161
148
|
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
@@ -164,6 +151,9 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
164
151
|
otherUser: "agent" | "patient" | "peer";
|
|
165
152
|
};
|
|
166
153
|
}[];
|
|
154
|
+
seedAssessmentScore?: number | undefined;
|
|
155
|
+
}, {
|
|
156
|
+
indexContext: string;
|
|
167
157
|
outcome: {
|
|
168
158
|
reasoning: string;
|
|
169
159
|
hasOpportunity: boolean;
|
|
@@ -173,6 +163,16 @@ export declare const DiscoveryNegotiationSchema: z.ZodObject<{
|
|
|
173
163
|
role: "agent" | "patient" | "peer";
|
|
174
164
|
}[] | undefined;
|
|
175
165
|
};
|
|
166
|
+
counterpartyHint: string;
|
|
167
|
+
counterpartyId: string;
|
|
168
|
+
turns: {
|
|
169
|
+
reasoning: string;
|
|
170
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
171
|
+
suggestedRoles: {
|
|
172
|
+
ownUser: "agent" | "patient" | "peer";
|
|
173
|
+
otherUser: "agent" | "patient" | "peer";
|
|
174
|
+
};
|
|
175
|
+
}[];
|
|
176
176
|
seedAssessmentScore?: number | undefined;
|
|
177
177
|
}>;
|
|
178
178
|
export type DiscoveryNegotiation = z.infer<typeof DiscoveryNegotiationSchema>;
|
|
@@ -39,8 +39,8 @@ export declare const DiscoveryNegotiationDigestSchema: z.ZodObject<{
|
|
|
39
39
|
ownUser: "agent" | "patient" | "peer";
|
|
40
40
|
otherUser: "agent" | "patient" | "peer";
|
|
41
41
|
} | null;
|
|
42
|
-
counterpartyHint: string;
|
|
43
42
|
indexContext: string;
|
|
43
|
+
counterpartyHint: string;
|
|
44
44
|
outcomeRole: "opportunity" | "no-opportunity";
|
|
45
45
|
outcomeReason: "timeout" | "stalled" | "rejected" | "turn_cap" | "screened_out" | null;
|
|
46
46
|
keyTake: string;
|
|
@@ -51,8 +51,8 @@ export declare const DiscoveryNegotiationDigestSchema: z.ZodObject<{
|
|
|
51
51
|
} | null;
|
|
52
52
|
outcomeRole: "opportunity" | "no-opportunity";
|
|
53
53
|
outcomeReason: "timeout" | "stalled" | "rejected" | "turn_cap" | "screened_out" | null;
|
|
54
|
-
counterpartyHint?: unknown;
|
|
55
54
|
indexContext?: unknown;
|
|
55
|
+
counterpartyHint?: unknown;
|
|
56
56
|
keyTake?: unknown;
|
|
57
57
|
}>;
|
|
58
58
|
export type DiscoveryNegotiationDigest = z.infer<typeof DiscoveryNegotiationDigestSchema>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indexnetwork/protocol",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.1.1-rc.478.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -28,20 +28,7 @@
|
|
|
28
28
|
"architecture:capabilities": "bun scripts/architecture/capability-boundaries.ts",
|
|
29
29
|
"architecture:check": "bun run architecture:host-isolation && bun run architecture:capabilities && bun run test:architecture",
|
|
30
30
|
"prepublishOnly": "bun run build",
|
|
31
|
-
"prepack": "bun run build:package"
|
|
32
|
-
"eval:matching": "bun --env-file=../../.env.test ./eval/matching/matching.eval.ts",
|
|
33
|
-
"eval:hyde": "bun --env-file=../../.env.test ./eval/hyde/hyde.eval.ts",
|
|
34
|
-
"eval:premise": "bun --env-file=../../.env.test ./eval/premise/premise.eval.ts",
|
|
35
|
-
"eval:profile": "bun --env-file=../../.env.test ./eval/profile/profile.eval.ts",
|
|
36
|
-
"eval:opportunity": "bun --env-file=../../.env.test ./eval/opportunity/opportunity.eval.ts",
|
|
37
|
-
"eval:clarification": "bun --env-file=../../.env.test ./eval/clarification/clarification.eval.ts",
|
|
38
|
-
"eval:intake": "bun --env-file=../../.env.test ./eval/intake/intake.eval.ts",
|
|
39
|
-
"eval:discovery-retrieval": "bun --env-file=../../.env.test ./eval/discovery-retrieval/discovery-retrieval.eval.ts",
|
|
40
|
-
"eval:canary": "bun --env-file=../../.env.test ./eval/canary/canary.eval.ts",
|
|
41
|
-
"eval:stance": "bun --env-file=../../.env.test ./eval/stance/stance.eval.ts",
|
|
42
|
-
"eval:view": "bun ./eval/viewer/viewer.eval.ts",
|
|
43
|
-
"eval:web": "bun --env-file=../../.env.test ./eval/ops/ops.serve.ts",
|
|
44
|
-
"eval:verify": "bun ./eval/verify.ts"
|
|
31
|
+
"prepack": "bun run build:package"
|
|
45
32
|
},
|
|
46
33
|
"dependencies": {
|
|
47
34
|
"@langchain/core": "1.1.48",
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal shape consumed by buildOpportunityPresentation for prose rendering.
|
|
3
|
-
* Card data objects in the codebase carry additional frontend-only fields;
|
|
4
|
-
* only these are surfaced to MCP agents.
|
|
5
|
-
*/
|
|
6
|
-
export type OpportunityCardLike = Record<string, unknown> & {
|
|
7
|
-
opportunityId: string;
|
|
8
|
-
userId?: string | undefined;
|
|
9
|
-
name?: string | undefined;
|
|
10
|
-
mainText?: string | undefined;
|
|
11
|
-
digestSummary?: string | undefined;
|
|
12
|
-
status?: string | undefined;
|
|
13
|
-
feedCategory?: string | undefined;
|
|
14
|
-
profileUrl?: string | undefined;
|
|
15
|
-
/** Universal link that opens this opportunity's card (`/o/<id>`). */
|
|
16
|
-
appUrl?: string | undefined;
|
|
17
|
-
/** Deep-link to the A2A negotiation trace that produced this opportunity. */
|
|
18
|
-
negotiationUrl?: string | undefined;
|
|
19
|
-
score?: number | undefined;
|
|
20
|
-
/** Digest-mode cooldown re-show — the user has seen this card before. */
|
|
21
|
-
redelivery?: boolean | undefined;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Format opportunity cards into the "opportunities" portion of a tool response.
|
|
25
|
-
*
|
|
26
|
-
* Web chat (`isMcp=false`): emits ```opportunity``` code fences with an
|
|
27
|
-
* "include EXACTLY as-is" directive so the frontend card renderer can parse
|
|
28
|
-
* and render interactive cards.
|
|
29
|
-
*
|
|
30
|
-
* MCP (`isMcp=true`): emits prose (name, reason, status, appUrl and profileUrl
|
|
31
|
-
* when present, feedCategory when present) and includes `opportunityId` for
|
|
32
|
-
* every card so the agent can act via the tools. The trailing instruction
|
|
33
|
-
* reminds the agent to synthesize in natural language, to surface the `appUrl`
|
|
34
|
-
* verbatim as the one link that opens the card, and to fabricate no other URL.
|
|
35
|
-
* MCP clients have no card renderer, so code fences would surface as raw JSON
|
|
36
|
-
* to end users.
|
|
37
|
-
*/
|
|
38
|
-
export declare function buildOpportunityPresentation(inputCards: OpportunityCardLike[], opts: {
|
|
39
|
-
isMcp: boolean;
|
|
40
|
-
leadIn: string;
|
|
41
|
-
label?: 'opportunity' | 'opportunities';
|
|
42
|
-
/** Include hidden digest metadata markers so scheduled brief tooling can confirm delivery. */
|
|
43
|
-
includeDigestMarkers?: boolean;
|
|
44
|
-
}): string;
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { stripUnsupportedOpportunityClaims } from '../../shared/utils/claim-safety.js';
|
|
2
|
-
import { stripUuids } from '../domain/opportunity.presentation.js';
|
|
3
|
-
const CODE_FENCE = String.fromCharCode(96, 96, 96);
|
|
4
|
-
function sanitizeJsonForCodeFence(json) {
|
|
5
|
-
return json.replace(/`/g, '\\u0060');
|
|
6
|
-
}
|
|
7
|
-
function sanitizeOpportunityCardProse(card) {
|
|
8
|
-
const sanitized = { ...card };
|
|
9
|
-
for (const key of ['mainText', 'digestSummary', 'headline', 'cta', 'mutualIntentsLabel']) {
|
|
10
|
-
const value = card[key];
|
|
11
|
-
if (typeof value === 'string') {
|
|
12
|
-
sanitized[key] = stripUnsupportedOpportunityClaims(stripUuids(value)) || 'A suggested connection.';
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
const narratorChip = card.narratorChip;
|
|
16
|
-
if (narratorChip && typeof narratorChip === 'object' && !Array.isArray(narratorChip)) {
|
|
17
|
-
const narrator = narratorChip;
|
|
18
|
-
if (typeof narrator.text === 'string') {
|
|
19
|
-
sanitized.narratorChip = {
|
|
20
|
-
...narrator,
|
|
21
|
-
text: stripUnsupportedOpportunityClaims(stripUuids(narrator.text)) || 'A potential connection worth exploring.',
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return sanitized;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Format opportunity cards into the "opportunities" portion of a tool response.
|
|
29
|
-
*
|
|
30
|
-
* Web chat (`isMcp=false`): emits ```opportunity``` code fences with an
|
|
31
|
-
* "include EXACTLY as-is" directive so the frontend card renderer can parse
|
|
32
|
-
* and render interactive cards.
|
|
33
|
-
*
|
|
34
|
-
* MCP (`isMcp=true`): emits prose (name, reason, status, appUrl and profileUrl
|
|
35
|
-
* when present, feedCategory when present) and includes `opportunityId` for
|
|
36
|
-
* every card so the agent can act via the tools. The trailing instruction
|
|
37
|
-
* reminds the agent to synthesize in natural language, to surface the `appUrl`
|
|
38
|
-
* verbatim as the one link that opens the card, and to fabricate no other URL.
|
|
39
|
-
* MCP clients have no card renderer, so code fences would surface as raw JSON
|
|
40
|
-
* to end users.
|
|
41
|
-
*/
|
|
42
|
-
export function buildOpportunityPresentation(inputCards, opts) {
|
|
43
|
-
const cards = inputCards.map(sanitizeOpportunityCardProse);
|
|
44
|
-
if (cards.length === 0)
|
|
45
|
-
return opts.leadIn;
|
|
46
|
-
if (opts.isMcp) {
|
|
47
|
-
const prose = cards
|
|
48
|
-
.map((card, i) => {
|
|
49
|
-
const lines = [`${i + 1}. ${card.name ?? "Unknown"}`];
|
|
50
|
-
if (opts.includeDigestMarkers) {
|
|
51
|
-
const markerId = String(card.opportunityId).replace(/[\s>]/g, "");
|
|
52
|
-
if (markerId)
|
|
53
|
-
lines.push(` <!-- digest-opportunity:id=${markerId} -->`);
|
|
54
|
-
}
|
|
55
|
-
if (opts.includeDigestMarkers && card.digestSummary) {
|
|
56
|
-
lines.push(` ${card.digestSummary}`);
|
|
57
|
-
}
|
|
58
|
-
else if (card.mainText) {
|
|
59
|
-
lines.push(` ${card.mainText}`);
|
|
60
|
-
}
|
|
61
|
-
if (card.status)
|
|
62
|
-
lines.push(` status: ${card.status}`);
|
|
63
|
-
if (card.appUrl)
|
|
64
|
-
lines.push(` appUrl: ${card.appUrl}`);
|
|
65
|
-
if (card.profileUrl)
|
|
66
|
-
lines.push(` profileUrl: ${card.profileUrl}`);
|
|
67
|
-
if (opts.includeDigestMarkers && card.negotiationUrl)
|
|
68
|
-
lines.push(` negotiationUrl: ${card.negotiationUrl}`);
|
|
69
|
-
if (card.feedCategory)
|
|
70
|
-
lines.push(` feedCategory: ${card.feedCategory}`);
|
|
71
|
-
if (opts.includeDigestMarkers && card.score != null)
|
|
72
|
-
lines.push(` confidence: ${Math.round(card.score * 100)}`);
|
|
73
|
-
if (opts.includeDigestMarkers && card.redelivery)
|
|
74
|
-
lines.push(` redelivery: true`);
|
|
75
|
-
lines.push(` opportunityId: ${card.opportunityId}`);
|
|
76
|
-
return lines.join("\n");
|
|
77
|
-
})
|
|
78
|
-
.join("\n\n");
|
|
79
|
-
const idInstructions = `Use opportunityId values only when calling update_opportunity (send/accept/reject) or confirm_opportunity_delivery.`;
|
|
80
|
-
return (`${opts.leadIn}\n\n${prose}\n\n` +
|
|
81
|
-
`Summarize these for the user in natural prose — mention first names and a brief match reason per connection. ` +
|
|
82
|
-
`For each card that has a profileUrl, link the person's name to it. Some cards may have no URL — render those as plain text and never fabricate URLs for them. ` +
|
|
83
|
-
`For each card that has an appUrl, show that link so the user can open the opportunity: it opens the card in the Index app when installed, and an Index web page otherwise. Show only an appUrl a tool returned — never assemble one from an opportunityId. ` +
|
|
84
|
-
`No link accepts on the user's behalf: accepting happens in the Index app (or via update_opportunity) — never invent an accept URL. ` +
|
|
85
|
-
`Do NOT print raw JSON, field labels, or opportunityIds. ` +
|
|
86
|
-
`${idInstructions}`);
|
|
87
|
-
}
|
|
88
|
-
const label = opts.label ?? (cards.length === 1 ? "opportunity" : "opportunities");
|
|
89
|
-
const blocks = cards
|
|
90
|
-
.map((card) => CODE_FENCE + "opportunity\n" + sanitizeJsonForCodeFence(JSON.stringify(card)) + "\n" + CODE_FENCE)
|
|
91
|
-
.join("\n\n");
|
|
92
|
-
return (`${opts.leadIn} IMPORTANT: Include the following ${CODE_FENCE}${label} code blocks EXACTLY as-is in your response (they render as interactive cards):\n\n${blocks}`);
|
|
93
|
-
}
|