@indexnetwork/protocol 14.3.2-rc.477.1 → 17.0.0-rc.479.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 +141 -0
- package/IMPLEMENTATION.md +50 -52
- package/STABILITY.md +3 -3
- package/dist/chat/chat.agent.js +2 -3
- package/dist/chat/chat.graph.d.ts +41 -1
- package/dist/chat/chat.graph.js +108 -127
- package/dist/chat/negotiator.persona.d.ts +1 -1
- package/dist/chat/negotiator.persona.js +1 -4
- package/dist/chat/negotiator.prompt.js +1 -2
- package/dist/chat/onboarding.persona.js +0 -1
- package/dist/chat/reporter.persona.js +0 -1
- package/dist/chat/signal.persona.js +0 -1
- package/dist/contacts/application/contact.tools.d.ts +6 -9
- package/dist/contacts/application/contact.tools.js +11 -92
- package/dist/contacts/application/index.d.ts +2 -14
- package/dist/contacts/application/index.js +2 -13
- package/dist/contacts/domain/contact.types.d.ts +0 -23
- package/dist/contacts/domain/index.d.ts +2 -6
- package/dist/contacts/index.d.ts +1 -1
- package/dist/contacts/index.js +1 -1
- package/dist/contacts/ports/contact.repository.port.d.ts +5 -12
- package/dist/contacts/ports/contact.repository.port.js +4 -6
- package/dist/contacts/ports/contact.tools.port.d.ts +1 -3
- package/dist/contacts/ports/contact.tools.port.js +1 -2
- package/dist/contacts/ports/index.d.ts +1 -1
- package/dist/contacts/ports/index.js +1 -1
- 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 -50
- package/dist/index.js +17 -28
- 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 +14 -20
- 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.factory.js +0 -8
- package/dist/shared/agent/tool.helpers.d.ts +21 -45
- package/dist/shared/agent/tool.helpers.js +1 -2
- package/dist/shared/agent/tool.registry.d.ts +4 -3
- package/dist/shared/agent/tool.registry.js +2 -4
- package/dist/shared/agent/tool.runtime.js +0 -2
- package/dist/shared/agent/utility.tools.js +9 -13
- 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 +221 -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/contacts/application/contact.inviter.d.ts +0 -49
- package/dist/contacts/application/contact.inviter.js +0 -64
- package/dist/integrations/application/index.d.ts +0 -14
- package/dist/integrations/application/index.js +0 -14
- package/dist/integrations/application/integration.tools.d.ts +0 -27
- package/dist/integrations/application/integration.tools.js +0 -98
- package/dist/integrations/domain/index.d.ts +0 -16
- package/dist/integrations/domain/index.js +0 -1
- package/dist/integrations/domain/integration.types.d.ts +0 -51
- package/dist/integrations/domain/integration.types.js +0 -9
- package/dist/integrations/index.d.ts +0 -10
- package/dist/integrations/index.js +0 -8
- package/dist/integrations/ports/index.d.ts +0 -25
- package/dist/integrations/ports/index.js +0 -23
- package/dist/integrations/ports/integration.adapter.port.d.ts +0 -62
- package/dist/integrations/ports/integration.adapter.port.js +0 -15
- package/dist/integrations/ports/integration.importer.port.d.ts +0 -31
- package/dist/integrations/ports/integration.importer.port.js +0 -15
- package/dist/integrations/ports/integration.tools.port.d.ts +0 -25
- package/dist/integrations/ports/integration.tools.port.js +0 -18
- 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
package/dist/mcp/mcp.server.js
CHANGED
|
@@ -23,9 +23,8 @@ const mcpToolMetadataCache = new Map();
|
|
|
23
23
|
* the cached metadata set is automatically invalidated.
|
|
24
24
|
*/
|
|
25
25
|
export function getMcpToolMetadataCacheKey(deps) {
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// the flag can never change the MCP tool set.
|
|
26
|
+
// Contact tools are omitted from the MCP surface entirely (IND-596), so no
|
|
27
|
+
// contacts-related input can change the MCP tool set.
|
|
29
28
|
return [
|
|
30
29
|
`chat:${deps.chatSession ? '1' : '0'}`,
|
|
31
30
|
`agent:${deps.agentDatabase ? '1' : '0'}`,
|
|
@@ -226,9 +225,9 @@ export const applyNetworkScopeToContext = (context, networkScopeId) => {
|
|
|
226
225
|
};
|
|
227
226
|
export { ONBOARDING_ALLOWED } from './mcp.authorization-policy.js';
|
|
228
227
|
/**
|
|
229
|
-
* Builds the onboarding gate message for
|
|
230
|
-
* chat
|
|
231
|
-
*
|
|
228
|
+
* Builds the onboarding gate message for REST Tool API callers. Condensed
|
|
229
|
+
* from the chat onboarding flow into a 6-step tool-error guide. MCP does
|
|
230
|
+
* not use this gate.
|
|
232
231
|
*/
|
|
233
232
|
export function buildMcpOnboardingMessage(ctx) {
|
|
234
233
|
const nameStep = ctx.hasName
|
|
@@ -335,10 +334,10 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
335
334
|
});
|
|
336
335
|
}
|
|
337
336
|
};
|
|
338
|
-
// Both snapshots are scoped to this MCP server/connection. Permission
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
//
|
|
337
|
+
// Both snapshots are scoped to this MCP server/connection. Permission
|
|
338
|
+
// changes therefore apply only after the caller reconnects or refreshes
|
|
339
|
+
// its session. They are never shared with the static tool metadata cache,
|
|
340
|
+
// so a different server/principal cannot inherit decisions.
|
|
342
341
|
let authenticatedRequest;
|
|
343
342
|
let resolvedRequest;
|
|
344
343
|
const extractAuthInput = (httpReq) => ({
|
|
@@ -373,11 +372,10 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
373
372
|
return {
|
|
374
373
|
identity,
|
|
375
374
|
agent,
|
|
376
|
-
//
|
|
377
|
-
//
|
|
375
|
+
// This snapshot is sufficient to reject forged/hidden calls before
|
|
376
|
+
// resolving chat context.
|
|
378
377
|
preliminarySubject: resolveMcpCapabilitySubject({
|
|
379
378
|
identity,
|
|
380
|
-
isOnboarding: false,
|
|
381
379
|
agent,
|
|
382
380
|
}),
|
|
383
381
|
};
|
|
@@ -392,7 +390,6 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
392
390
|
const context = await resolveChatContext({
|
|
393
391
|
database: deps.database,
|
|
394
392
|
userId: authenticated.identity.userId,
|
|
395
|
-
contactsEnabled: deps.contactsEnabled,
|
|
396
393
|
});
|
|
397
394
|
context.isMcp = true;
|
|
398
395
|
if (authenticated.identity.agentId) {
|
|
@@ -410,7 +407,6 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
410
407
|
applyNetworkScopeToContext(context, authenticated.identity.networkScopeId);
|
|
411
408
|
const subject = resolveMcpCapabilitySubject({
|
|
412
409
|
identity: authenticated.identity,
|
|
413
|
-
isOnboarding: context.isOnboarding,
|
|
414
410
|
agent: authenticated.agent,
|
|
415
411
|
});
|
|
416
412
|
// Bind the typed resolved caller context so tools with
|
|
@@ -425,10 +421,8 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
425
421
|
})();
|
|
426
422
|
return resolvedRequest;
|
|
427
423
|
};
|
|
428
|
-
const capabilityDeniedResult = (
|
|
429
|
-
const message =
|
|
430
|
-
? buildMcpOnboardingMessage(context)
|
|
431
|
-
: 'This capability is not available to the authenticated principal. Reconnect or refresh the session after an administrator changes permissions.';
|
|
424
|
+
const capabilityDeniedResult = (_decision) => {
|
|
425
|
+
const message = 'This capability is not available to the authenticated principal. Reconnect or refresh the session after an administrator changes permissions.';
|
|
432
426
|
return {
|
|
433
427
|
content: [{
|
|
434
428
|
type: 'text',
|
|
@@ -482,7 +476,7 @@ export function createMcpServer(deps, authResolver, scopedDepsFactory, policyOpt
|
|
|
482
476
|
subject: resolved.subject,
|
|
483
477
|
decision,
|
|
484
478
|
});
|
|
485
|
-
return capabilityDeniedResult(decision
|
|
479
|
+
return capabilityDeniedResult(decision);
|
|
486
480
|
}
|
|
487
481
|
const { identity, context } = resolved;
|
|
488
482
|
const { userId, agentId } = identity;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan-out driver: run one bilateral negotiation per candidate.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `negotiation.graph.ts`, which held the graph, its four nodes and
|
|
5
|
+
* this driver in one file. Import from `negotiation.graph.js` — it re-exports
|
|
6
|
+
* everything here.
|
|
7
|
+
*/
|
|
8
|
+
import type { TraceEmitter } from "../../shared/observability/request-context.js";
|
|
9
|
+
import type { OpportunityStatus } from "../../shared/interfaces/database.interface.js";
|
|
10
|
+
import { type NegotiationTurn, type NegotiationOutcome, type UserNegotiationContext, type NegotiationGraphLike } from "../domain/negotiation.state.js";
|
|
11
|
+
export interface NegotiationCandidate {
|
|
12
|
+
userId: string;
|
|
13
|
+
/** Exact opportunity-bound source and candidate intent IDs. */
|
|
14
|
+
sourceIntentId?: string;
|
|
15
|
+
candidateIntentId?: string;
|
|
16
|
+
/** Per-opportunity source context when its exact actor intent differs across a fan-out. */
|
|
17
|
+
sourceUser?: UserNegotiationContext;
|
|
18
|
+
reasoning: string;
|
|
19
|
+
valencyRole: string;
|
|
20
|
+
networkId?: string;
|
|
21
|
+
candidateUser: UserNegotiationContext;
|
|
22
|
+
/** The explicit search query that triggered discovery (if any). */
|
|
23
|
+
discoveryQuery?: string;
|
|
24
|
+
/**
|
|
25
|
+
* ID of the opportunity this negotiation is for. When set, the negotiation
|
|
26
|
+
* graph's finalize node updates the opportunity's status based on the outcome
|
|
27
|
+
* (`accept` → 'pending', `reject` → 'rejected', otherwise → 'stalled').
|
|
28
|
+
*/
|
|
29
|
+
opportunityId?: string;
|
|
30
|
+
/** Exact persisted lifecycle state claimed by this negotiation attempt. */
|
|
31
|
+
opportunityStatus?: OpportunityStatus;
|
|
32
|
+
opportunityUpdatedAt?: Date;
|
|
33
|
+
}
|
|
34
|
+
export interface NegotiationResult {
|
|
35
|
+
userId: string;
|
|
36
|
+
agreedRoles: NegotiationOutcome["agreedRoles"];
|
|
37
|
+
reasoning: string;
|
|
38
|
+
turnCount: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Per-candidate resolution hook — fires as each negotiation settles, before
|
|
42
|
+
* Promise.all aggregates. Awaited so the caller can run async work before the
|
|
43
|
+
* next settle.
|
|
44
|
+
*
|
|
45
|
+
* `turns` and `outcome` are passed through from the underlying negotiation
|
|
46
|
+
* graph so consumers can build per-candidate decision-question inputs without
|
|
47
|
+
* re-walking trace events or DB artifacts. Both are present on every
|
|
48
|
+
* resolution (accepted, rejected, stalled, error); error paths receive a
|
|
49
|
+
* synthesized `outcome` with `hasOpportunity: false`.
|
|
50
|
+
*/
|
|
51
|
+
export type OnNegotiationResolved = (entry: {
|
|
52
|
+
candidate: NegotiationCandidate;
|
|
53
|
+
accepted: NegotiationResult | null;
|
|
54
|
+
turns: NegotiationTurn[];
|
|
55
|
+
outcome: NegotiationOutcome;
|
|
56
|
+
continuationReceipt?: import('../../shared/interfaces/database.interface.js').NegotiationContinuationReceipt;
|
|
57
|
+
}) => Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Runs bilateral negotiation for each candidate in parallel.
|
|
60
|
+
* @returns Only candidates that produced an opportunity
|
|
61
|
+
*/
|
|
62
|
+
export declare function negotiateCandidates(negotiationGraph: NegotiationGraphLike, sourceUser: UserNegotiationContext, candidates: NegotiationCandidate[], indexContext: {
|
|
63
|
+
networkId: string;
|
|
64
|
+
prompt: string;
|
|
65
|
+
}, opts?: {
|
|
66
|
+
maxTurns?: number;
|
|
67
|
+
traceEmitter?: TraceEmitter;
|
|
68
|
+
indexContextOverrides?: Map<string, string>;
|
|
69
|
+
timeoutMs?: number;
|
|
70
|
+
onCandidateResolved?: OnNegotiationResolved;
|
|
71
|
+
/**
|
|
72
|
+
* Initiator seat for every candidate session in this fan-out (v2 stamp).
|
|
73
|
+
* Passed through to the negotiation graph, which may still override it by
|
|
74
|
+
* inheriting from a prior task on the same opportunities/conversation.
|
|
75
|
+
*/
|
|
76
|
+
initiatorUserId?: string;
|
|
77
|
+
/** Exact settled task to resume; only the durable run-existing path sets this. */
|
|
78
|
+
resumeFromTaskId?: string;
|
|
79
|
+
/** Deterministic settlement key paired with resumeFromTaskId. */
|
|
80
|
+
continuationSettlementId?: string;
|
|
81
|
+
/** Current durable lease/fence for this exact continuation successor. */
|
|
82
|
+
continuationExecution?: import('../../shared/interfaces/database.interface.js').NegotiationContinuationExecution;
|
|
83
|
+
}): Promise<NegotiationResult[]>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan-out driver: run one bilateral negotiation per candidate.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `negotiation.graph.ts`, which held the graph, its four nodes and
|
|
5
|
+
* this driver in one file. Import from `negotiation.graph.js` — it re-exports
|
|
6
|
+
* everything here.
|
|
7
|
+
*/
|
|
8
|
+
import { invokeWithAbortSignal } from "../../shared/agent/model-signal.js";
|
|
9
|
+
import { negotiateCandidatesLog, turnsFromMessages } from "./negotiation.graph.shared.js";
|
|
10
|
+
/**
|
|
11
|
+
* Runs bilateral negotiation for each candidate in parallel.
|
|
12
|
+
* @returns Only candidates that produced an opportunity
|
|
13
|
+
*/
|
|
14
|
+
export async function negotiateCandidates(negotiationGraph, sourceUser, candidates, indexContext, opts) {
|
|
15
|
+
const { maxTurns, traceEmitter, indexContextOverrides, timeoutMs, onCandidateResolved, initiatorUserId, resumeFromTaskId, continuationSettlementId, continuationExecution, } = opts ?? {};
|
|
16
|
+
// Local helper to emit events whose shape is wider than the declared
|
|
17
|
+
// `TraceEmitter` union (mirrors the cast used in chat.agent at the relay sink
|
|
18
|
+
// and inside turn/finalize nodes above).
|
|
19
|
+
const emitWide = (event) => traceEmitter?.(event);
|
|
20
|
+
const results = await Promise.all(candidates.map(async (candidate) => {
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
const candidateSourceUser = candidate.sourceUser ?? sourceUser;
|
|
23
|
+
if (candidate.opportunityId) {
|
|
24
|
+
const candidateName = candidate.candidateUser?.profile?.name;
|
|
25
|
+
emitWide({
|
|
26
|
+
type: "negotiation_session_start",
|
|
27
|
+
opportunityId: candidate.opportunityId,
|
|
28
|
+
negotiationConversationId: "", // filled in on session_end
|
|
29
|
+
sourceUserId: candidateSourceUser.id,
|
|
30
|
+
candidateUserId: candidate.userId,
|
|
31
|
+
initiatorUserId: initiatorUserId ?? candidateSourceUser.id,
|
|
32
|
+
...(candidateName && { candidateName }),
|
|
33
|
+
startedAt: start,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
traceEmitter?.({ type: "agent_start", name: "Negotiating candidate" });
|
|
37
|
+
try {
|
|
38
|
+
const candidateIndexContext = candidate.networkId
|
|
39
|
+
? { networkId: candidate.networkId, prompt: indexContextOverrides?.get(candidate.networkId) ?? '' }
|
|
40
|
+
: indexContext;
|
|
41
|
+
const result = await invokeWithAbortSignal(negotiationGraph, {
|
|
42
|
+
sourceUser: candidateSourceUser,
|
|
43
|
+
candidateUser: candidate.candidateUser,
|
|
44
|
+
...(candidate.sourceIntentId && { sourceIntentId: candidate.sourceIntentId }),
|
|
45
|
+
...(candidate.candidateIntentId && { candidateIntentId: candidate.candidateIntentId }),
|
|
46
|
+
indexContext: candidateIndexContext,
|
|
47
|
+
seedAssessment: {
|
|
48
|
+
reasoning: candidate.reasoning,
|
|
49
|
+
valencyRole: candidate.valencyRole,
|
|
50
|
+
},
|
|
51
|
+
...(candidate.discoveryQuery && { discoveryQuery: candidate.discoveryQuery }),
|
|
52
|
+
...(candidate.opportunityId && { opportunityId: candidate.opportunityId }),
|
|
53
|
+
...(candidate.opportunityStatus && { opportunityStatus: candidate.opportunityStatus }),
|
|
54
|
+
...(candidate.opportunityUpdatedAt && { opportunityUpdatedAt: candidate.opportunityUpdatedAt }),
|
|
55
|
+
...(initiatorUserId && { initiatorUserId }),
|
|
56
|
+
...(resumeFromTaskId && continuationSettlementId && continuationExecution ? {
|
|
57
|
+
resumeFromTaskId,
|
|
58
|
+
continuationSettlementId,
|
|
59
|
+
continuationExecution,
|
|
60
|
+
} : {}),
|
|
61
|
+
...(maxTurns !== undefined && { maxTurns }),
|
|
62
|
+
...(timeoutMs !== undefined && { timeoutMs }),
|
|
63
|
+
});
|
|
64
|
+
const durationMs = Date.now() - start;
|
|
65
|
+
const outcome = result.outcome;
|
|
66
|
+
const hasOpportunity = outcome?.hasOpportunity === true;
|
|
67
|
+
const isContinuation = result.isContinuation ?? false;
|
|
68
|
+
const priorTurnCount = result.priorTurnCount ?? 0;
|
|
69
|
+
const turnFlow = (result.messages ?? [])
|
|
70
|
+
.map((m) => {
|
|
71
|
+
const dataPart = m.parts?.find((p) => p.kind === "data");
|
|
72
|
+
if (!dataPart?.data)
|
|
73
|
+
return null;
|
|
74
|
+
const turn = dataPart.data;
|
|
75
|
+
return turn.action ?? "unknown";
|
|
76
|
+
})
|
|
77
|
+
.filter(Boolean)
|
|
78
|
+
.join(" → ");
|
|
79
|
+
const statusTag = hasOpportunity ? "✓ opportunity" : "✗ rejected";
|
|
80
|
+
traceEmitter?.({ type: "agent_end", name: "Negotiating candidate", durationMs, summary: `${candidate.userId}: ${turnFlow} ${statusTag}` });
|
|
81
|
+
if (candidate.opportunityId) {
|
|
82
|
+
emitWide({
|
|
83
|
+
type: "negotiation_session_end",
|
|
84
|
+
opportunityId: candidate.opportunityId,
|
|
85
|
+
negotiationConversationId: result.conversationId ?? "",
|
|
86
|
+
durationMs: Date.now() - start,
|
|
87
|
+
isContinuation,
|
|
88
|
+
turnsAdded: outcome?.turnCount ?? 0,
|
|
89
|
+
priorTurnCount,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const accepted = hasOpportunity && outcome
|
|
93
|
+
? {
|
|
94
|
+
userId: candidate.userId,
|
|
95
|
+
agreedRoles: outcome.agreedRoles,
|
|
96
|
+
reasoning: outcome.reasoning,
|
|
97
|
+
turnCount: outcome.turnCount,
|
|
98
|
+
}
|
|
99
|
+
: null;
|
|
100
|
+
if (onCandidateResolved) {
|
|
101
|
+
const turnHistory = turnsFromMessages(result.messages ?? []);
|
|
102
|
+
const resolvedOutcome = result.outcome ?? {
|
|
103
|
+
hasOpportunity: false,
|
|
104
|
+
agreedRoles: [],
|
|
105
|
+
reasoning: "no outcome returned by negotiation graph",
|
|
106
|
+
turnCount: turnHistory.length,
|
|
107
|
+
};
|
|
108
|
+
try {
|
|
109
|
+
await onCandidateResolved({
|
|
110
|
+
candidate,
|
|
111
|
+
accepted,
|
|
112
|
+
turns: turnHistory,
|
|
113
|
+
outcome: resolvedOutcome,
|
|
114
|
+
...(result.continuationReceipt ? { continuationReceipt: result.continuationReceipt } : {}),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (hookErr) {
|
|
118
|
+
// Hook failures must not sink the candidate result — the aggregate
|
|
119
|
+
// return remains useful to the caller.
|
|
120
|
+
negotiateCandidatesLog.error("onCandidateResolved hook threw", {
|
|
121
|
+
candidateUserId: candidate.userId,
|
|
122
|
+
error: hookErr,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return accepted;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
const durationMs = Date.now() - start;
|
|
130
|
+
traceEmitter?.({ type: "agent_end", name: "Negotiating candidate", durationMs, summary: `${candidate.userId}: error` });
|
|
131
|
+
if (candidate.opportunityId) {
|
|
132
|
+
emitWide({
|
|
133
|
+
type: "negotiation_session_end",
|
|
134
|
+
opportunityId: candidate.opportunityId,
|
|
135
|
+
negotiationConversationId: "",
|
|
136
|
+
durationMs: Date.now() - start,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
negotiateCandidatesLog.error("Negotiation failed", { candidateUserId: candidate.userId, error: err });
|
|
140
|
+
if (onCandidateResolved) {
|
|
141
|
+
try {
|
|
142
|
+
await onCandidateResolved({
|
|
143
|
+
candidate,
|
|
144
|
+
accepted: null,
|
|
145
|
+
turns: [],
|
|
146
|
+
outcome: {
|
|
147
|
+
hasOpportunity: false,
|
|
148
|
+
agreedRoles: [],
|
|
149
|
+
reasoning: err instanceof Error ? err.message : String(err),
|
|
150
|
+
turnCount: 0,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// ignore hook failure on error path
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}));
|
|
161
|
+
return results.filter((r) => r !== null);
|
|
162
|
+
}
|