@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,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `list_opportunities` — the persisted opportunity feed for chat and MCP.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `opportunity.tools.ts`: the listing is by far the largest of the
|
|
5
|
+
* three opportunity tools, and it is the only one that renders cards.
|
|
6
|
+
*/
|
|
7
|
+
import type { DefineTool } from "../../shared/agent/tool.helpers.js";
|
|
8
|
+
import type { OpportunityToolDeps } from "../ports/index.js";
|
|
9
|
+
/** Builds the `list_opportunities` tool against the host's capabilities. */
|
|
10
|
+
export declare function createListOpportunitiesTool(defineTool: DefineTool, deps: OpportunityToolDeps): any;
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `list_opportunities` — the persisted opportunity feed for chat and MCP.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `opportunity.tools.ts`: the listing is by far the largest of the
|
|
5
|
+
* three opportunity tools, and it is the only one that renders cards.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { success, error, UUID_REGEX } from "../../shared/agent/tool.helpers.js";
|
|
9
|
+
import { focusedIntentId, focusedNetworkId, focusedNetworkLabel } from "../../shared/agent/tool.scope.js";
|
|
10
|
+
import { getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from "../domain/opportunity.labels.js";
|
|
11
|
+
import { OpportunityPresenter, gatherPresenterContext, stripUuids } from "./opportunity.presentation.js";
|
|
12
|
+
import { buildOpportunityPresentation } from "./opportunity.presentation.js";
|
|
13
|
+
import { loadNegotiationContext } from "./negotiation-context.loader.js";
|
|
14
|
+
import { selectOpportunityFeed } from './opportunity.feed-selection.js';
|
|
15
|
+
import { CHAT_DISPLAY_LIMIT, attachOpportunityAppLink, attachProfileLink, buildNegotiationUrl } from "./opportunity.tools.cards.js";
|
|
16
|
+
import { logger, stripLeadingNarratorName } from "./opportunity.tools.cards.js";
|
|
17
|
+
/** Builds the `list_opportunities` tool against the host's capabilities. */
|
|
18
|
+
export function createListOpportunitiesTool(defineTool, deps) {
|
|
19
|
+
const { database, userDb, systemDb, graphs, cache } = deps;
|
|
20
|
+
const createOpportunityPresenter = deps.opportunityPresentation?.createPresenter ??
|
|
21
|
+
(() => new OpportunityPresenter());
|
|
22
|
+
const gatherOpportunityPresenterContext = deps.opportunityPresentation?.gatherPresenterContext ??
|
|
23
|
+
gatherPresenterContext;
|
|
24
|
+
const listOpportunities = defineTool({
|
|
25
|
+
name: "list_opportunities",
|
|
26
|
+
description: "Lists the authenticated user's actionable opportunities (discovered connections). Returns opportunity cards ready for display.\n\n" +
|
|
27
|
+
"**What are opportunities?** Matches between users whose intents complement each other within shared networkes. " +
|
|
28
|
+
"Each opportunity has a status: draft (not yet sent), pending (sent, awaiting response), accepted, rejected, or expired.\n\n" +
|
|
29
|
+
"**What this returns:** Only draft and pending opportunities — the ones the user can still act on. " +
|
|
30
|
+
"Accepted, rejected, and expired ones are not surfaced through this tool.\n\n" +
|
|
31
|
+
"**When to use:** When the user wants to see their current matches or review what's waiting for their response.\n\n" +
|
|
32
|
+
"**Returns:** Up to 3 opportunity code blocks (interactive cards) with counterpart name, match reasoning, confidence score, " +
|
|
33
|
+
"and current status. Use update_opportunity to act on them (send, accept, reject).",
|
|
34
|
+
querySchema: z.object({
|
|
35
|
+
networkId: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Network UUID to filter opportunities to a specific community. Get from read_networks. Defaults to the scoped network in network-scoped chats. Omit to see opportunities across all networks."),
|
|
39
|
+
scopeType: z
|
|
40
|
+
.enum(['intent'])
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Optional selected scope type. Use 'intent' to narrow listed opportunities to a selected intent."),
|
|
43
|
+
scopeId: z
|
|
44
|
+
.string()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Selected intent UUID when scopeType is 'intent'. Ignored only when absent."),
|
|
47
|
+
includeDigestMarkers: z
|
|
48
|
+
.boolean()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe("Internal scheduled-digest mode only. When true, includes hidden delivery markers so the digest send pass can confirm only edited-in opportunities."),
|
|
51
|
+
}),
|
|
52
|
+
handler: async ({ context, query }) => {
|
|
53
|
+
const scopedNetworkId = focusedNetworkId(context) ?? context.networkId?.trim();
|
|
54
|
+
const scopedIndexLabel = focusedNetworkLabel(context);
|
|
55
|
+
// Strict scope enforcement: when chat is network-scoped, only allow that index
|
|
56
|
+
if (scopedNetworkId &&
|
|
57
|
+
query.networkId?.trim() &&
|
|
58
|
+
query.networkId.trim() !== scopedNetworkId) {
|
|
59
|
+
return error(`This chat is scoped to ${scopedIndexLabel}. You can only list opportunities from this community.`);
|
|
60
|
+
}
|
|
61
|
+
const effectiveIndexId = (scopedNetworkId || query.networkId?.trim()) ?? undefined;
|
|
62
|
+
if (effectiveIndexId && !UUID_REGEX.test(effectiveIndexId)) {
|
|
63
|
+
return error("Invalid network ID format.");
|
|
64
|
+
}
|
|
65
|
+
const contextIntentId = focusedIntentId(context);
|
|
66
|
+
const rawScopeId = query.scopeId?.trim() || undefined;
|
|
67
|
+
if (query.scopeType === 'intent' && !rawScopeId) {
|
|
68
|
+
return error("scopeId required when scopeType is intent.");
|
|
69
|
+
}
|
|
70
|
+
if (!query.scopeType && rawScopeId) {
|
|
71
|
+
return error("scopeType=intent required when scopeId is provided.");
|
|
72
|
+
}
|
|
73
|
+
if (rawScopeId && !UUID_REGEX.test(rawScopeId)) {
|
|
74
|
+
return error("Invalid scope ID format.");
|
|
75
|
+
}
|
|
76
|
+
if (contextIntentId && rawScopeId && contextIntentId !== rawScopeId) {
|
|
77
|
+
return error("This chat is scoped to a different intent.");
|
|
78
|
+
}
|
|
79
|
+
const effectiveIntentScope = contextIntentId
|
|
80
|
+
? { scopeType: 'intent', scopeId: contextIntentId }
|
|
81
|
+
: query.scopeType === 'intent' && rawScopeId
|
|
82
|
+
? { scopeType: 'intent', scopeId: rawScopeId }
|
|
83
|
+
: {};
|
|
84
|
+
const selection = await selectOpportunityFeed({
|
|
85
|
+
reader: database,
|
|
86
|
+
deliveryLedger: deps.deliveryLedger,
|
|
87
|
+
viewerId: context.userId,
|
|
88
|
+
networkId: effectiveIndexId,
|
|
89
|
+
intentScope: effectiveIntentScope,
|
|
90
|
+
isMcp: context.isMcp === true,
|
|
91
|
+
includeDigestMarkers: query.includeDigestMarkers,
|
|
92
|
+
displayLimit: CHAT_DISPLAY_LIMIT,
|
|
93
|
+
warn: (message, data) => logger.warn(message, data),
|
|
94
|
+
});
|
|
95
|
+
const { opportunities, dedupedCount, skippedIds, redeliveryIds, fetchedCount, isDigestMode } = selection;
|
|
96
|
+
const buildListDebugSteps = () => {
|
|
97
|
+
const steps = [];
|
|
98
|
+
if (skippedIds.length > 0) {
|
|
99
|
+
steps.push({
|
|
100
|
+
step: "opportunity_display_skips",
|
|
101
|
+
detail: `${skippedIds.length} opportunity card(s) couldn't be displayed`,
|
|
102
|
+
data: {
|
|
103
|
+
skippedCount: skippedIds.length,
|
|
104
|
+
totalOpportunities: fetchedCount,
|
|
105
|
+
skippedOpportunityIds: skippedIds,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return steps;
|
|
110
|
+
};
|
|
111
|
+
if (!opportunities || opportunities.length === 0) {
|
|
112
|
+
if (skippedIds.length > 0) {
|
|
113
|
+
const listDebugSteps = buildListDebugSteps();
|
|
114
|
+
return success({
|
|
115
|
+
found: false,
|
|
116
|
+
count: 0,
|
|
117
|
+
summary: "Some opportunities couldn't be displayed",
|
|
118
|
+
message: "I found opportunities, but couldn't render them. Please try again.",
|
|
119
|
+
...(listDebugSteps.length ? { debugSteps: listDebugSteps } : {}),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// Digest mode: distinguish "everything was already shown" from "nothing
|
|
123
|
+
// exists" so the brief omits the people section instead of prompting
|
|
124
|
+
// the user to run discovery.
|
|
125
|
+
if (isDigestMode && dedupedCount > 0) {
|
|
126
|
+
return success({
|
|
127
|
+
found: false,
|
|
128
|
+
count: 0,
|
|
129
|
+
summary: "No new opportunities to show",
|
|
130
|
+
message: "No new opportunities today — everything actionable has already been shown recently. Omit the people section from the digest.",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return success({
|
|
134
|
+
found: false,
|
|
135
|
+
count: 0,
|
|
136
|
+
summary: "No opportunities yet",
|
|
137
|
+
message: "You have no opportunities yet. Create or refine an approved signal with create_intent or update_intent; matches are created in the background. Use list_opportunities later to review persisted results.",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// Batch-fetch profiles and users for all counterpart and introducer userIds to avoid N+1
|
|
141
|
+
const counterpartUserIds = new Set();
|
|
142
|
+
const introducerUserIds = new Set();
|
|
143
|
+
for (const opp of opportunities) {
|
|
144
|
+
const counterpartActor = opp.actors.find((a) => a.userId !== context.userId && a.role !== "introducer");
|
|
145
|
+
if (counterpartActor?.userId)
|
|
146
|
+
counterpartUserIds.add(counterpartActor.userId);
|
|
147
|
+
const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== context.userId);
|
|
148
|
+
if (introducerActor?.userId)
|
|
149
|
+
introducerUserIds.add(introducerActor.userId);
|
|
150
|
+
}
|
|
151
|
+
const allUserIds = [
|
|
152
|
+
...new Set([...counterpartUserIds, ...introducerUserIds]),
|
|
153
|
+
];
|
|
154
|
+
const [profileResults, userResults] = await Promise.all([
|
|
155
|
+
Promise.all(allUserIds.map((id) => database.getProfile(id))),
|
|
156
|
+
Promise.all(allUserIds.map((id) => database.getUser(id))),
|
|
157
|
+
]);
|
|
158
|
+
const profileMap = new Map();
|
|
159
|
+
const userMap = new Map();
|
|
160
|
+
allUserIds.forEach((userId, i) => {
|
|
161
|
+
const profile = profileResults[i] ?? null;
|
|
162
|
+
const user = userResults[i] ?? null;
|
|
163
|
+
if (profile)
|
|
164
|
+
profileMap.set(userId, profile);
|
|
165
|
+
if (user)
|
|
166
|
+
userMap.set(userId, user);
|
|
167
|
+
});
|
|
168
|
+
const cardDataList = [];
|
|
169
|
+
const seenOpportunityIds = new Set();
|
|
170
|
+
if (isDigestMode) {
|
|
171
|
+
// ── Digest mode: use LLM presenter for rich, second-person card text ──
|
|
172
|
+
const presenter = createOpportunityPresenter();
|
|
173
|
+
const presenterDb = database;
|
|
174
|
+
const PRESENTER_CONCURRENCY = 6;
|
|
175
|
+
for (let i = 0; i < opportunities.length; i += PRESENTER_CONCURRENCY) {
|
|
176
|
+
const chunk = opportunities.slice(i, i + PRESENTER_CONCURRENCY);
|
|
177
|
+
const chunkCards = await Promise.all(chunk.map(async (opp) => {
|
|
178
|
+
if (seenOpportunityIds.has(opp.id))
|
|
179
|
+
return null;
|
|
180
|
+
seenOpportunityIds.add(opp.id);
|
|
181
|
+
try {
|
|
182
|
+
const counterpartActor = opp.actors.find((a) => a.userId !== context.userId && a.role !== "introducer");
|
|
183
|
+
const counterpartUserId = counterpartActor?.userId;
|
|
184
|
+
if (!counterpartUserId)
|
|
185
|
+
return null;
|
|
186
|
+
const viewerIsIntroducerHere = opp.actors.some((a) => a.role === "introducer" && a.userId === context.userId);
|
|
187
|
+
const secondPartyActorForHeadline = viewerIsIntroducerHere
|
|
188
|
+
? opp.actors.find((a) => a.userId !== context.userId &&
|
|
189
|
+
a.userId !== counterpartUserId &&
|
|
190
|
+
a.role !== "introducer")
|
|
191
|
+
: undefined;
|
|
192
|
+
const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== context.userId);
|
|
193
|
+
const createdByName = opp.detection.createdByName;
|
|
194
|
+
const counterpartUser = userMap.get(counterpartUserId) ?? null;
|
|
195
|
+
const counterpartName = profileMap.get(counterpartUserId)?.identity?.name ??
|
|
196
|
+
counterpartUser?.name ??
|
|
197
|
+
"Someone";
|
|
198
|
+
const introducerName = createdByName ??
|
|
199
|
+
(introducerActor
|
|
200
|
+
? (profileMap.get(introducerActor.userId)?.identity?.name ?? null)
|
|
201
|
+
: null);
|
|
202
|
+
const introducerUser = introducerActor
|
|
203
|
+
? userMap.get(introducerActor.userId) ?? null
|
|
204
|
+
: null;
|
|
205
|
+
const secondPartyUser = secondPartyActorForHeadline
|
|
206
|
+
? userMap.get(secondPartyActorForHeadline.userId) ?? null
|
|
207
|
+
: null;
|
|
208
|
+
const secondPartyNameForHeadline = secondPartyActorForHeadline
|
|
209
|
+
? (profileMap.get(secondPartyActorForHeadline.userId)?.identity?.name ??
|
|
210
|
+
secondPartyUser?.name ??
|
|
211
|
+
undefined)
|
|
212
|
+
: undefined;
|
|
213
|
+
const viewerActor = opp.actors.find((a) => a.userId === context.userId);
|
|
214
|
+
const viewerRole = viewerActor?.role ?? "party";
|
|
215
|
+
const isCounterpartGhost = counterpartUser?.isGhost ?? false;
|
|
216
|
+
try {
|
|
217
|
+
// Load the negotiation context alongside presenter context so
|
|
218
|
+
// the digest copy can explain *why* the opportunity surfaced
|
|
219
|
+
// (EDG-50) — the presenter grounds `digestSummary` in concrete
|
|
220
|
+
// negotiation turns when this is present. The same context
|
|
221
|
+
// yields the conversationId for the negotiation-trace link
|
|
222
|
+
// (EDG-51).
|
|
223
|
+
const [ctx, negotiationContext] = await Promise.all([
|
|
224
|
+
gatherOpportunityPresenterContext(presenterDb, opp, context.userId, counterpartUserId),
|
|
225
|
+
loadNegotiationContext(deps.negotiationDatabase, opp.id, opp.status),
|
|
226
|
+
]);
|
|
227
|
+
const presentation = await presenter.presentCard({
|
|
228
|
+
...ctx,
|
|
229
|
+
opportunityStatus: opp.status,
|
|
230
|
+
...(negotiationContext ? { negotiationContext } : {}),
|
|
231
|
+
});
|
|
232
|
+
const negotiationUrl = buildNegotiationUrl(negotiationContext?.conversationId, deps.frontendUrl);
|
|
233
|
+
// Build narrator chip from presenter output
|
|
234
|
+
let narratorChip;
|
|
235
|
+
const introducerIsCounterpart = introducerActor && counterpartActor && introducerActor.userId === counterpartActor.userId;
|
|
236
|
+
if (introducerActor && introducerActor.userId !== context.userId && !introducerIsCounterpart) {
|
|
237
|
+
const narratorName = introducerName?.trim() || "Someone";
|
|
238
|
+
narratorChip = {
|
|
239
|
+
name: narratorName,
|
|
240
|
+
text: stripLeadingNarratorName(presentation.narratorRemark, narratorName),
|
|
241
|
+
avatar: introducerUser?.avatar ?? null,
|
|
242
|
+
userId: introducerActor.userId,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
else if (introducerActor?.userId === context.userId) {
|
|
246
|
+
narratorChip = { name: "You", text: presentation.narratorRemark, userId: context.userId };
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
narratorChip = { name: "Index", text: presentation.narratorRemark };
|
|
250
|
+
}
|
|
251
|
+
const card = {
|
|
252
|
+
opportunityId: opp.id,
|
|
253
|
+
userId: counterpartUserId,
|
|
254
|
+
name: counterpartName,
|
|
255
|
+
avatar: counterpartUser?.avatar ?? null,
|
|
256
|
+
mainText: stripUuids(presentation.personalizedSummary),
|
|
257
|
+
digestSummary: stripUuids(presentation.digestSummary),
|
|
258
|
+
// Deep-link to the negotiation trace that produced this card
|
|
259
|
+
// (EDG-51). Only present when a negotiation conversation exists.
|
|
260
|
+
...(negotiationUrl ? { negotiationUrl } : {}),
|
|
261
|
+
cta: presentation.suggestedAction,
|
|
262
|
+
headline: viewerIsIntroducerHere && secondPartyNameForHeadline
|
|
263
|
+
? `${counterpartName} → ${secondPartyNameForHeadline}`
|
|
264
|
+
: presentation.headline,
|
|
265
|
+
primaryActionLabel: getPrimaryActionLabel(viewerRole),
|
|
266
|
+
secondaryActionLabel: SECONDARY_ACTION_LABEL,
|
|
267
|
+
mutualIntentsLabel: presentation.mutualIntentsLabel,
|
|
268
|
+
narratorChip,
|
|
269
|
+
viewerRole,
|
|
270
|
+
score: typeof opp.interpretation?.confidence === "number"
|
|
271
|
+
? opp.interpretation.confidence
|
|
272
|
+
: undefined,
|
|
273
|
+
status: opp.status,
|
|
274
|
+
isGhost: isCounterpartGhost,
|
|
275
|
+
...(redeliveryIds.has(opp.id) ? { redelivery: true } : {}),
|
|
276
|
+
...(viewerIsIntroducerHere && secondPartyNameForHeadline
|
|
277
|
+
? {
|
|
278
|
+
secondParty: {
|
|
279
|
+
name: secondPartyNameForHeadline,
|
|
280
|
+
...(secondPartyUser?.avatar != null ? { avatar: secondPartyUser.avatar } : {}),
|
|
281
|
+
...(secondPartyActorForHeadline?.userId ? { userId: secondPartyActorForHeadline.userId } : {}),
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
: {}),
|
|
285
|
+
};
|
|
286
|
+
// Attach the agent-facing profile and opportunity links for
|
|
287
|
+
// MCP callers
|
|
288
|
+
if (context.isMcp) {
|
|
289
|
+
attachProfileLink(card, {
|
|
290
|
+
counterpartUserId,
|
|
291
|
+
frontendUrl: deps.frontendUrl,
|
|
292
|
+
});
|
|
293
|
+
attachOpportunityAppLink(card, {
|
|
294
|
+
frontendUrl: deps.frontendUrl,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return card;
|
|
298
|
+
}
|
|
299
|
+
catch (presenterErr) {
|
|
300
|
+
logger.warn("LLM presenter failed for list_opportunities digest card, skipping raw fallback", {
|
|
301
|
+
opportunityId: opp.id,
|
|
302
|
+
err: presenterErr,
|
|
303
|
+
});
|
|
304
|
+
// Scheduled digests should only surface OpportunityPresenter-rendered
|
|
305
|
+
// copy. The minimal fallback reuses evaluator reasoning, which can
|
|
306
|
+
// contain raw narrator phrasing (for example "The discoverer...")
|
|
307
|
+
// and is not suitable for AgentVillage morning briefs.
|
|
308
|
+
skippedIds.push(opp.id);
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
logger.warn("Skipping opportunity that failed to build card", {
|
|
314
|
+
opportunityId: opp.id,
|
|
315
|
+
err,
|
|
316
|
+
});
|
|
317
|
+
skippedIds.push(opp.id);
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
}));
|
|
321
|
+
for (const card of chunkCards) {
|
|
322
|
+
if (card)
|
|
323
|
+
cardDataList.push(card);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
// ── Chat/list mode: use OpportunityPresenter for user-facing card copy ──
|
|
329
|
+
const presenter = createOpportunityPresenter();
|
|
330
|
+
const presenterDb = database;
|
|
331
|
+
const PRESENTER_CONCURRENCY = 6;
|
|
332
|
+
for (let i = 0; i < opportunities.length; i += PRESENTER_CONCURRENCY) {
|
|
333
|
+
const chunk = opportunities.slice(i, i + PRESENTER_CONCURRENCY);
|
|
334
|
+
const chunkCards = await Promise.all(chunk.map(async (opp) => {
|
|
335
|
+
if (seenOpportunityIds.has(opp.id))
|
|
336
|
+
return null;
|
|
337
|
+
seenOpportunityIds.add(opp.id);
|
|
338
|
+
try {
|
|
339
|
+
const counterpartActor = opp.actors.find((a) => a.userId !== context.userId && a.role !== "introducer");
|
|
340
|
+
const counterpartUserId = counterpartActor?.userId;
|
|
341
|
+
if (!counterpartUserId)
|
|
342
|
+
return null;
|
|
343
|
+
const viewerIsIntroducerHere = opp.actors.some((a) => a.role === "introducer" && a.userId === context.userId);
|
|
344
|
+
const secondPartyActorForHeadline = viewerIsIntroducerHere
|
|
345
|
+
? opp.actors.find((a) => a.userId !== context.userId &&
|
|
346
|
+
a.userId !== counterpartUserId &&
|
|
347
|
+
a.role !== "introducer")
|
|
348
|
+
: undefined;
|
|
349
|
+
const introducerActor = opp.actors.find((a) => a.role === "introducer" && a.userId !== context.userId);
|
|
350
|
+
const createdByName = opp.detection.createdByName;
|
|
351
|
+
const counterpartProfile = profileMap.get(counterpartUserId) ?? null;
|
|
352
|
+
const counterpartUser = userMap.get(counterpartUserId) ?? null;
|
|
353
|
+
const introducerProfile = introducerActor && !createdByName
|
|
354
|
+
? profileMap.get(introducerActor.userId) ?? null
|
|
355
|
+
: null;
|
|
356
|
+
const counterpartName = counterpartProfile?.identity?.name ??
|
|
357
|
+
counterpartUser?.name ??
|
|
358
|
+
"Someone";
|
|
359
|
+
const introducerName = createdByName ??
|
|
360
|
+
(introducerActor ? introducerProfile?.identity?.name ?? null : null);
|
|
361
|
+
const introducerUser = introducerActor
|
|
362
|
+
? userMap.get(introducerActor.userId) ?? null
|
|
363
|
+
: null;
|
|
364
|
+
const secondPartyUser = secondPartyActorForHeadline
|
|
365
|
+
? userMap.get(secondPartyActorForHeadline.userId) ?? null
|
|
366
|
+
: null;
|
|
367
|
+
const secondPartyNameForHeadline = secondPartyActorForHeadline
|
|
368
|
+
? (profileMap.get(secondPartyActorForHeadline.userId)?.identity?.name ??
|
|
369
|
+
secondPartyUser?.name ??
|
|
370
|
+
undefined)
|
|
371
|
+
: undefined;
|
|
372
|
+
const viewerActor = opp.actors.find((a) => a.userId === context.userId);
|
|
373
|
+
const viewerRole = viewerActor?.role ?? "party";
|
|
374
|
+
const isCounterpartGhost = counterpartUser?.isGhost ?? false;
|
|
375
|
+
const [ctx, negotiationContext] = await Promise.all([
|
|
376
|
+
gatherOpportunityPresenterContext(presenterDb, opp, context.userId, counterpartUserId),
|
|
377
|
+
loadNegotiationContext(deps.negotiationDatabase, opp.id, opp.status),
|
|
378
|
+
]);
|
|
379
|
+
const presentation = await presenter.presentCard({
|
|
380
|
+
...ctx,
|
|
381
|
+
opportunityStatus: opp.status,
|
|
382
|
+
...(negotiationContext ? { negotiationContext } : {}),
|
|
383
|
+
});
|
|
384
|
+
let narratorChip;
|
|
385
|
+
const introducerIsCounterpart = introducerActor && counterpartActor && introducerActor.userId === counterpartActor.userId;
|
|
386
|
+
if (introducerActor && introducerActor.userId !== context.userId && !introducerIsCounterpart) {
|
|
387
|
+
const narratorName = introducerName?.trim() || "Someone";
|
|
388
|
+
narratorChip = {
|
|
389
|
+
name: narratorName,
|
|
390
|
+
text: stripLeadingNarratorName(presentation.narratorRemark, narratorName),
|
|
391
|
+
avatar: introducerUser?.avatar ?? null,
|
|
392
|
+
userId: introducerActor.userId,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
else if (introducerActor?.userId === context.userId) {
|
|
396
|
+
narratorChip = { name: "You", text: presentation.narratorRemark, userId: context.userId };
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
narratorChip = { name: "Index", text: presentation.narratorRemark };
|
|
400
|
+
}
|
|
401
|
+
const cardData = {
|
|
402
|
+
opportunityId: opp.id,
|
|
403
|
+
userId: counterpartUserId,
|
|
404
|
+
name: counterpartName,
|
|
405
|
+
avatar: counterpartUser?.avatar ?? null,
|
|
406
|
+
mainText: stripUuids(presentation.personalizedSummary),
|
|
407
|
+
cta: presentation.suggestedAction,
|
|
408
|
+
headline: viewerIsIntroducerHere && secondPartyNameForHeadline
|
|
409
|
+
? `${counterpartName} → ${secondPartyNameForHeadline}`
|
|
410
|
+
: presentation.headline,
|
|
411
|
+
primaryActionLabel: getPrimaryActionLabel(viewerRole),
|
|
412
|
+
secondaryActionLabel: SECONDARY_ACTION_LABEL,
|
|
413
|
+
mutualIntentsLabel: presentation.mutualIntentsLabel,
|
|
414
|
+
narratorChip,
|
|
415
|
+
viewerRole,
|
|
416
|
+
score: typeof opp.interpretation?.confidence === "number"
|
|
417
|
+
? opp.interpretation.confidence
|
|
418
|
+
: undefined,
|
|
419
|
+
status: opp.status,
|
|
420
|
+
isGhost: isCounterpartGhost,
|
|
421
|
+
...(viewerIsIntroducerHere && secondPartyNameForHeadline
|
|
422
|
+
? {
|
|
423
|
+
secondParty: {
|
|
424
|
+
name: secondPartyNameForHeadline,
|
|
425
|
+
...(secondPartyUser?.avatar != null ? { avatar: secondPartyUser.avatar } : {}),
|
|
426
|
+
...(secondPartyActorForHeadline?.userId ? { userId: secondPartyActorForHeadline.userId } : {}),
|
|
427
|
+
},
|
|
428
|
+
}
|
|
429
|
+
: {}),
|
|
430
|
+
};
|
|
431
|
+
// For MCP callers, attach the agent-facing profile link and the
|
|
432
|
+
// opportunity deep link so the agent never has to fabricate
|
|
433
|
+
// either. Accepting still happens in the Index app behind an
|
|
434
|
+
// authenticated call — the deep link only opens the card.
|
|
435
|
+
if (context.isMcp) {
|
|
436
|
+
attachProfileLink(cardData, {
|
|
437
|
+
counterpartUserId,
|
|
438
|
+
frontendUrl: deps.frontendUrl,
|
|
439
|
+
});
|
|
440
|
+
attachOpportunityAppLink(cardData, {
|
|
441
|
+
frontendUrl: deps.frontendUrl,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
return cardData;
|
|
445
|
+
}
|
|
446
|
+
catch (err) {
|
|
447
|
+
logger.warn("Skipping opportunity that failed to build presenter card", {
|
|
448
|
+
opportunityId: opp.id,
|
|
449
|
+
err,
|
|
450
|
+
});
|
|
451
|
+
skippedIds.push(opp.id);
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
}));
|
|
455
|
+
for (const card of chunkCards) {
|
|
456
|
+
if (card)
|
|
457
|
+
cardDataList.push(card);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const listDebugSteps = buildListDebugSteps();
|
|
462
|
+
if (cardDataList.length === 0) {
|
|
463
|
+
if (skippedIds.length > 0) {
|
|
464
|
+
return success({
|
|
465
|
+
found: false,
|
|
466
|
+
count: 0,
|
|
467
|
+
summary: "Some opportunities couldn't be displayed",
|
|
468
|
+
message: "I found opportunities, but couldn't render them. Please try again.",
|
|
469
|
+
...(listDebugSteps.length ? { debugSteps: listDebugSteps } : {}),
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
return success({
|
|
473
|
+
found: false,
|
|
474
|
+
count: 0,
|
|
475
|
+
summary: "No opportunities yet",
|
|
476
|
+
message: "You have no opportunities yet. Create or refine an approved signal with create_intent or update_intent; matches are created in the background. Use list_opportunities later to review persisted results.",
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
return success({
|
|
480
|
+
found: true,
|
|
481
|
+
count: cardDataList.length,
|
|
482
|
+
summary: `You have ${cardDataList.length} opportunity(ies)`,
|
|
483
|
+
message: buildOpportunityPresentation(cardDataList, {
|
|
484
|
+
isMcp: context.isMcp ?? false,
|
|
485
|
+
leadIn: `You have ${cardDataList.length} opportunity(ies).`,
|
|
486
|
+
includeDigestMarkers: context.isMcp === true && query.includeDigestMarkers === true,
|
|
487
|
+
}),
|
|
488
|
+
...(listDebugSteps.length ? { debugSteps: listDebugSteps } : {}),
|
|
489
|
+
});
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
return listOpportunities;
|
|
493
|
+
}
|
|
@@ -29,9 +29,9 @@ export * from "./opportunity.utils.js";
|
|
|
29
29
|
export * from "./opportunity.actor.js";
|
|
30
30
|
export * from "./opportunity.evidence.js";
|
|
31
31
|
export * from "../../shared/utils/claim-safety.js";
|
|
32
|
-
export * from "
|
|
33
|
-
export * from "
|
|
34
|
-
export * from "
|
|
32
|
+
export * from "../application/opportunity.presentation.js";
|
|
33
|
+
export * from "../application/opportunity.presentation.js";
|
|
34
|
+
export * from "../application/opportunity.presentation.js";
|
|
35
35
|
export * from "./negotiation-summary.builder.js";
|
|
36
36
|
export type { PoolCandidate, DiscriminatorMiningInput, MinedDiscriminator, ScoredDiscriminator, VerifiedAssignment, DiscriminatorShadowResult, } from "../discriminator/discriminator.types.js";
|
|
37
37
|
export { poolQuestionsMiningMode, poolQuestionsMode, poolQuestionsPushMode, poolQuestionsStampNewborn, POOL_DISCRIMINATOR_MIN_POOL_SIZE, POOL_DISCRIMINATOR_MAX_CANDIDATES, POOL_DISCRIMINATOR_MAX_PUBLIC_CONTEXT_CHARS, POOL_QUESTION_MIN_VOI, POOL_QUESTION_MAX_PENDING_PER_INTENT, poolQuestionsRanking, POOL_RERUN_DEBOUNCE_MS, poolQuestionsVisitTrigger, POOL_VISIT_MINING_DEBOUNCE_MS, } from "../discriminator/discriminator.env.js";
|
|
@@ -30,9 +30,9 @@ export * from "./opportunity.utils.js";
|
|
|
30
30
|
export * from "./opportunity.actor.js";
|
|
31
31
|
export * from "./opportunity.evidence.js";
|
|
32
32
|
export * from "../../shared/utils/claim-safety.js";
|
|
33
|
-
export * from "
|
|
34
|
-
export * from "
|
|
35
|
-
export * from "
|
|
33
|
+
export * from "../application/opportunity.presentation.js";
|
|
34
|
+
export * from "../application/opportunity.presentation.js";
|
|
35
|
+
export * from "../application/opportunity.presentation.js";
|
|
36
36
|
export * from "./negotiation-summary.builder.js";
|
|
37
37
|
export { poolQuestionsMiningMode, poolQuestionsMode, poolQuestionsPushMode, poolQuestionsStampNewborn, POOL_DISCRIMINATOR_MIN_POOL_SIZE, POOL_DISCRIMINATOR_MAX_CANDIDATES, POOL_DISCRIMINATOR_MAX_PUBLIC_CONTEXT_CHARS, POOL_QUESTION_MIN_VOI, POOL_QUESTION_MAX_PENDING_PER_INTENT, poolQuestionsRanking, POOL_RERUN_DEBOUNCE_MS, poolQuestionsVisitTrigger, POOL_VISIT_MINING_DEBOUNCE_MS, } from "../discriminator/discriminator.env.js";
|
|
38
38
|
export { buildPoolAdjustment, planPoolAdjustments, mergePoolAdjustment, readActivePoolAdjustments, adjustedConfidence, } from "../discriminator/discriminator.adjustments.js";
|
|
@@ -176,7 +176,7 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
176
176
|
*
|
|
177
177
|
* Defaults to 'create' for backward compatibility.
|
|
178
178
|
*/
|
|
179
|
-
operationMode: import("@langchain/langgraph").BaseChannel<"
|
|
179
|
+
operationMode: import("@langchain/langgraph").BaseChannel<"send" | "update" | "create" | "delete" | "read" | "create_introduction" | "continue_discovery" | "negotiate_existing" | "approve_introduction", "send" | "update" | "create" | "delete" | "read" | "create_introduction" | "continue_discovery" | "negotiate_existing" | "approve_introduction" | import("@langchain/langgraph").OverwriteValue<"send" | "update" | "create" | "delete" | "read" | "create_introduction" | "continue_discovery" | "negotiate_existing" | "approve_introduction">, unknown>;
|
|
180
180
|
/** Introduction mode: pre-gathered entities (profiles + intents per party). */
|
|
181
181
|
introductionEntities: import("@langchain/langgraph").BaseChannel<EvaluatorEntity[], EvaluatorEntity[] | import("@langchain/langgraph").OverwriteValue<EvaluatorEntity[]>, unknown>;
|
|
182
182
|
/** Introduction mode: optional hint from the introducer. */
|
|
@@ -380,17 +380,7 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
380
380
|
* negotiate).
|
|
381
381
|
*/
|
|
382
382
|
discoveryNegotiations: import("@langchain/langgraph").BaseChannel<{
|
|
383
|
-
counterpartyId: string;
|
|
384
|
-
counterpartyHint: string;
|
|
385
383
|
indexContext: string;
|
|
386
|
-
turns: {
|
|
387
|
-
reasoning: string;
|
|
388
|
-
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
389
|
-
suggestedRoles: {
|
|
390
|
-
ownUser: "agent" | "patient" | "peer";
|
|
391
|
-
otherUser: "agent" | "patient" | "peer";
|
|
392
|
-
};
|
|
393
|
-
}[];
|
|
394
384
|
outcome: {
|
|
395
385
|
reasoning: string;
|
|
396
386
|
hasOpportunity: boolean;
|
|
@@ -400,11 +390,8 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
400
390
|
role: "agent" | "patient" | "peer";
|
|
401
391
|
}[] | undefined;
|
|
402
392
|
};
|
|
403
|
-
seedAssessmentScore?: number | undefined;
|
|
404
|
-
}[], {
|
|
405
|
-
counterpartyId: string;
|
|
406
393
|
counterpartyHint: string;
|
|
407
|
-
|
|
394
|
+
counterpartyId: string;
|
|
408
395
|
turns: {
|
|
409
396
|
reasoning: string;
|
|
410
397
|
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
@@ -413,6 +400,9 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
413
400
|
otherUser: "agent" | "patient" | "peer";
|
|
414
401
|
};
|
|
415
402
|
}[];
|
|
403
|
+
seedAssessmentScore?: number | undefined;
|
|
404
|
+
}[], {
|
|
405
|
+
indexContext: string;
|
|
416
406
|
outcome: {
|
|
417
407
|
reasoning: string;
|
|
418
408
|
hasOpportunity: boolean;
|
|
@@ -422,11 +412,8 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
422
412
|
role: "agent" | "patient" | "peer";
|
|
423
413
|
}[] | undefined;
|
|
424
414
|
};
|
|
425
|
-
seedAssessmentScore?: number | undefined;
|
|
426
|
-
}[] | import("@langchain/langgraph").OverwriteValue<{
|
|
427
|
-
counterpartyId: string;
|
|
428
415
|
counterpartyHint: string;
|
|
429
|
-
|
|
416
|
+
counterpartyId: string;
|
|
430
417
|
turns: {
|
|
431
418
|
reasoning: string;
|
|
432
419
|
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
@@ -435,6 +422,9 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
435
422
|
otherUser: "agent" | "patient" | "peer";
|
|
436
423
|
};
|
|
437
424
|
}[];
|
|
425
|
+
seedAssessmentScore?: number | undefined;
|
|
426
|
+
}[] | import("@langchain/langgraph").OverwriteValue<{
|
|
427
|
+
indexContext: string;
|
|
438
428
|
outcome: {
|
|
439
429
|
reasoning: string;
|
|
440
430
|
hasOpportunity: boolean;
|
|
@@ -444,6 +434,16 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
|
|
|
444
434
|
role: "agent" | "patient" | "peer";
|
|
445
435
|
}[] | undefined;
|
|
446
436
|
};
|
|
437
|
+
counterpartyHint: string;
|
|
438
|
+
counterpartyId: string;
|
|
439
|
+
turns: {
|
|
440
|
+
reasoning: string;
|
|
441
|
+
action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
|
|
442
|
+
suggestedRoles: {
|
|
443
|
+
ownUser: "agent" | "patient" | "peer";
|
|
444
|
+
otherUser: "agent" | "patient" | "peer";
|
|
445
|
+
};
|
|
446
|
+
}[];
|
|
447
447
|
seedAssessmentScore?: number | undefined;
|
|
448
448
|
}[]>, unknown>;
|
|
449
449
|
/** Aggregate counters across `discoveryNegotiations`. Built in the negotiate node. */
|