@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
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared vocabulary for the opportunity graph's nodes and modes.
|
|
3
|
+
*
|
|
4
|
+
* The nodes used to be closures inside `OpportunityGraphFactory.createGraph()`,
|
|
5
|
+
* capturing `this` and the resolved thresholds. They are now top-level functions
|
|
6
|
+
* that take an explicit {@link OpportunityGraphDeps} bag, so each node is
|
|
7
|
+
* readable — and testable — on its own. This module owns the pieces more than
|
|
8
|
+
* one of them needs: the dependency bag, the loggers, the trace wrapper, and the
|
|
9
|
+
* small pure helpers.
|
|
10
|
+
*/
|
|
11
|
+
import type { Id } from '../../shared/interfaces/database.interface.js';
|
|
12
|
+
import { OpportunityGraphState, type IndexedIntent, type SourceProfileData, type CandidateMatch } from '../domain/opportunity.state.js';
|
|
13
|
+
import type { CandidateProfile, EvaluatorEntity, EvaluatorInput } from './opportunity.evaluator.js';
|
|
14
|
+
import type { OpportunityGraphDatabase, Opportunity } from '../../shared/interfaces/database.interface.js';
|
|
15
|
+
import type { Embedder } from '../../shared/interfaces/embedder.interface.js';
|
|
16
|
+
import type { NegotiationGraphLike } from '../../negotiations/index.js';
|
|
17
|
+
import type { AgentDispatcher } from '../../shared/interfaces/agent-dispatcher.interface.js';
|
|
18
|
+
import type { QueueOpportunityNotificationFn } from './opportunity.lifecycle.js';
|
|
19
|
+
import type { StampNewbornOpportunitiesFn } from './opportunity.newborn-stamping.js';
|
|
20
|
+
/** The graph's channel state, as every node sees it. */
|
|
21
|
+
export type OpportunityState = typeof OpportunityGraphState.State;
|
|
22
|
+
/** Optional evaluator for testing (avoids LLM calls). */
|
|
23
|
+
export type OpportunityEvaluatorLike = {
|
|
24
|
+
invoke?: (sourceProfileContext: string, candidates: CandidateProfile[], options: {
|
|
25
|
+
minScore?: number;
|
|
26
|
+
}) => Promise<Array<{
|
|
27
|
+
sourceId: string;
|
|
28
|
+
candidateId: string;
|
|
29
|
+
score: number;
|
|
30
|
+
reasoning: string;
|
|
31
|
+
valencyRole: 'Agent' | 'Patient' | 'Peer';
|
|
32
|
+
}>>;
|
|
33
|
+
invokeEntityBundle?: (input: EvaluatorInput, options: {
|
|
34
|
+
minScore?: number;
|
|
35
|
+
returnAll?: boolean;
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
}) => Promise<Array<{
|
|
38
|
+
reasoning: string;
|
|
39
|
+
score: number;
|
|
40
|
+
actors: Array<{
|
|
41
|
+
userId: string;
|
|
42
|
+
role: 'agent' | 'patient' | 'peer';
|
|
43
|
+
intentId?: string | null;
|
|
44
|
+
evidenceKey?: string | null;
|
|
45
|
+
}>;
|
|
46
|
+
}>>;
|
|
47
|
+
};
|
|
48
|
+
/** Input shape for the HyDE graph invoke call (query-based embedding). */
|
|
49
|
+
export interface HydeGeneratorInvokeInput {
|
|
50
|
+
sourceType: 'query';
|
|
51
|
+
sourceText: string;
|
|
52
|
+
forceRegenerate?: boolean;
|
|
53
|
+
profileContext?: string;
|
|
54
|
+
}
|
|
55
|
+
/** The compiled HyDE graph, as the discovery node consumes it. */
|
|
56
|
+
export interface OpportunityHydeGenerator {
|
|
57
|
+
invoke: (input: HydeGeneratorInvokeInput) => Promise<{
|
|
58
|
+
hydeEmbeddings: Record<string, number[]>;
|
|
59
|
+
lenses?: Array<{
|
|
60
|
+
label: string;
|
|
61
|
+
corpus: 'profiles' | 'intents' | 'premises';
|
|
62
|
+
}>;
|
|
63
|
+
hydeDocuments?: Record<string, {
|
|
64
|
+
hydeText?: string;
|
|
65
|
+
lens?: string;
|
|
66
|
+
}>;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
export interface OpportunityGraphThresholdOverrides {
|
|
70
|
+
retrievalMinSimilarity?: number;
|
|
71
|
+
evaluatorMinScore?: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Everything the nodes and modes reach for. Composed once by
|
|
75
|
+
* `OpportunityGraphFactory` and passed to each function explicitly.
|
|
76
|
+
*/
|
|
77
|
+
export interface OpportunityGraphDeps {
|
|
78
|
+
database: OpportunityGraphDatabase;
|
|
79
|
+
embedder: Embedder;
|
|
80
|
+
hydeGenerator: OpportunityHydeGenerator;
|
|
81
|
+
/** Resolved evaluator: the injected test double, or a real `OpportunityEvaluator`. */
|
|
82
|
+
evaluatorAgent: OpportunityEvaluatorLike;
|
|
83
|
+
queueNotification?: QueueOpportunityNotificationFn;
|
|
84
|
+
negotiationGraph?: NegotiationGraphLike;
|
|
85
|
+
/**
|
|
86
|
+
* Used on the chat path to decide whether to wait for the user's personal
|
|
87
|
+
* agent (long timeout) or fall back to the system agent immediately
|
|
88
|
+
* (short timeout). Without it, the chat path always uses a short timeout.
|
|
89
|
+
*/
|
|
90
|
+
agentDispatcher?: Pick<AgentDispatcher, 'hasExternalAgent'>;
|
|
91
|
+
/**
|
|
92
|
+
* Callback to enqueue a negotiate_existing job for an opportunity.
|
|
93
|
+
* When provided, negotiate_existing mode uses this to queue follow-up
|
|
94
|
+
* negotiations after introducer approval.
|
|
95
|
+
*/
|
|
96
|
+
queueNegotiateExisting?: (opportunityId: string, userId: string) => Promise<void>;
|
|
97
|
+
/** Host-side P4b stamper. Omitted by manual/introducer/enrichment roots. */
|
|
98
|
+
stampNewbornOpportunities?: StampNewbornOpportunitiesFn;
|
|
99
|
+
retrievalMinSimilarity: number;
|
|
100
|
+
evaluatorMinScore: number;
|
|
101
|
+
}
|
|
102
|
+
export declare const logger: import("../../shared/observability/log.js").LoggerWithSource;
|
|
103
|
+
export declare const prepLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
104
|
+
export declare const scopeLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
105
|
+
export declare const resolveLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
106
|
+
export declare const discoveryLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
107
|
+
export declare const evaluationLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
108
|
+
export declare const negotiateLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
109
|
+
export declare const rankingLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
110
|
+
export declare const introValidationLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
111
|
+
export declare const introEvaluationLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
112
|
+
export declare const persistLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
113
|
+
export declare const persistPathLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
114
|
+
export declare const persistDedupLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
115
|
+
export declare const readLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
116
|
+
export declare const updateLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
117
|
+
export declare const deleteLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
118
|
+
export declare const sendLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
119
|
+
export declare const negotiateExistingLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
120
|
+
export declare const routingLog: import("../../shared/observability/log.js").LoggerWithSource;
|
|
121
|
+
/**
|
|
122
|
+
* Error text can include provider response bodies, URLs, and credentials. Keep
|
|
123
|
+
* observability useful by retaining only a conservative error class at this
|
|
124
|
+
* boundary; detailed errors are intentionally not emitted from graph traces.
|
|
125
|
+
*/
|
|
126
|
+
export declare function safeOpportunityGraphError(_error: unknown): string;
|
|
127
|
+
/**
|
|
128
|
+
* Wraps a graph node function to emit agent_start/agent_end trace events
|
|
129
|
+
* at its boundaries so the frontend TRACE panel shows real-time progress.
|
|
130
|
+
* @param traceName - Kebab-case agent name (e.g. "opportunity-prep")
|
|
131
|
+
* @param nodeFn - The original node function
|
|
132
|
+
* @param summaryFn - Optional function to derive a summary string from the node result
|
|
133
|
+
*/
|
|
134
|
+
export declare function withNodeTrace<S, R>(traceName: string, nodeFn: (state: S) => Promise<R>, summaryFn?: (result: R) => string | undefined): (state: S) => Promise<R>;
|
|
135
|
+
/** Shared trace summary: surface `error` when a node returned one. */
|
|
136
|
+
export declare function errorSummary(result: unknown): string | undefined;
|
|
137
|
+
/** Time window for persist-node dedup. Suppresses a second opportunity with the same person while a recent one (within 30 days) is still in flight, so a person is not re-surfaced multiple times within a month (EDG-23). */
|
|
138
|
+
export declare const DEDUP_WINDOW_MS: number;
|
|
139
|
+
export declare function isActiveNegotiationTaskFresh(task: {
|
|
140
|
+
state: string;
|
|
141
|
+
updatedAt: Date;
|
|
142
|
+
}): boolean;
|
|
143
|
+
export declare function triggerForOwner(opportunity: Opportunity, ownerUserId: string): string | undefined;
|
|
144
|
+
export declare function belongsToOwnedIntent(opportunity: Opportunity, ownerUserId: string, triggerIntentId: string): boolean;
|
|
145
|
+
export declare function getRejectionCooldownMs(): number;
|
|
146
|
+
/**
|
|
147
|
+
* Similarity multiplier applied to candidates that fall within the rejection
|
|
148
|
+
* cool-down window (IND-567). 0.5 halves their ranking score, typically
|
|
149
|
+
* pushing them below the evaluation-batch cut while leaving a soft trace in
|
|
150
|
+
* the trace log rather than silently dropping them.
|
|
151
|
+
*/
|
|
152
|
+
export declare const REJECTION_COOLDOWN_SIMILARITY_PENALTY = 0.5;
|
|
153
|
+
export declare function networkMembershipPairKey(userId: string, networkId: string): string;
|
|
154
|
+
/** Per-source cap for candidate premise matches. */
|
|
155
|
+
export declare const PREMISE_MATCH_LIMIT_PER_SOURCE = 20;
|
|
156
|
+
/** Resolve the source premise discovery cap from env, preserving 0 as an explicit disable switch. */
|
|
157
|
+
export declare function getSourcePremiseDiscoveryLimit(): number;
|
|
158
|
+
export declare function buildEvaluatorEvidenceKey(candidate: CandidateMatch): string;
|
|
159
|
+
/**
|
|
160
|
+
* Builds a compact text summary of the discoverer's profile and active intents
|
|
161
|
+
* for use as profileContext in HyDE generation.
|
|
162
|
+
* @param profile - The discoverer's profile data (identity, attributes)
|
|
163
|
+
* @param intents - The discoverer's indexed intents (capped at 5)
|
|
164
|
+
* @returns A context string, or undefined if no meaningful data is available
|
|
165
|
+
*/
|
|
166
|
+
export declare function buildDiscovererContext(profile: SourceProfileData | null | undefined, intents: IndexedIntent[] | undefined): string | undefined;
|
|
167
|
+
/**
|
|
168
|
+
* Build a networkContexts map for the evaluator from a set of entities.
|
|
169
|
+
* Fetches network data, checks permissions.contextInjection.discovery,
|
|
170
|
+
* and renders context for eligible networks.
|
|
171
|
+
*/
|
|
172
|
+
export declare function buildNetworkContexts(entities: EvaluatorEntity[], database: Pick<OpportunityGraphDatabase, 'getNetwork'>): Promise<Record<string, string>>;
|
|
173
|
+
export type { Id };
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared vocabulary for the opportunity graph's nodes and modes.
|
|
3
|
+
*
|
|
4
|
+
* The nodes used to be closures inside `OpportunityGraphFactory.createGraph()`,
|
|
5
|
+
* capturing `this` and the resolved thresholds. They are now top-level functions
|
|
6
|
+
* that take an explicit {@link OpportunityGraphDeps} bag, so each node is
|
|
7
|
+
* readable — and testable — on its own. This module owns the pieces more than
|
|
8
|
+
* one of them needs: the dependency bag, the loggers, the trace wrapper, and the
|
|
9
|
+
* small pure helpers.
|
|
10
|
+
*/
|
|
11
|
+
import { ASK_USER_LOCK_SLACK_MS, askUserAnswerWindowMs } from '../../negotiations/index.js';
|
|
12
|
+
import { protocolLogger } from '../../shared/observability/protocol.logger.js';
|
|
13
|
+
import { renderNetworkContext } from '../../shared/network/metadata.renderer.js';
|
|
14
|
+
import { requestContext } from '../../shared/observability/request-context.js';
|
|
15
|
+
export const logger = protocolLogger('OpportunityGraph');
|
|
16
|
+
export const prepLog = protocolLogger('OpportunityGraph:Prep');
|
|
17
|
+
export const scopeLog = protocolLogger('OpportunityGraph:Scope');
|
|
18
|
+
export const resolveLog = protocolLogger('OpportunityGraph:Resolve');
|
|
19
|
+
export const discoveryLog = protocolLogger('OpportunityGraph:Discovery');
|
|
20
|
+
export const evaluationLog = protocolLogger('OpportunityGraph:Evaluation');
|
|
21
|
+
export const negotiateLog = protocolLogger('OpportunityGraph:Negotiate');
|
|
22
|
+
export const rankingLog = protocolLogger('OpportunityGraph:Ranking');
|
|
23
|
+
export const introValidationLog = protocolLogger('OpportunityGraph:IntroValidation');
|
|
24
|
+
export const introEvaluationLog = protocolLogger('OpportunityGraph:IntroEvaluation');
|
|
25
|
+
export const persistLog = protocolLogger('OpportunityGraph:Persist');
|
|
26
|
+
export const persistPathLog = protocolLogger('OpportunityGraph:Persist:PathSelect');
|
|
27
|
+
export const persistDedupLog = protocolLogger('OpportunityGraph:Persist:Dedup');
|
|
28
|
+
export const readLog = protocolLogger('OpportunityGraph:Read');
|
|
29
|
+
export const updateLog = protocolLogger('OpportunityGraph:Update');
|
|
30
|
+
export const deleteLog = protocolLogger('OpportunityGraph:Delete');
|
|
31
|
+
export const sendLog = protocolLogger('OpportunityGraph:Send');
|
|
32
|
+
export const negotiateExistingLog = protocolLogger('OpportunityGraph:NegotiateExisting');
|
|
33
|
+
export const routingLog = protocolLogger('OpportunityGraph:Routing');
|
|
34
|
+
/**
|
|
35
|
+
* Error text can include provider response bodies, URLs, and credentials. Keep
|
|
36
|
+
* observability useful by retaining only a conservative error class at this
|
|
37
|
+
* boundary; detailed errors are intentionally not emitted from graph traces.
|
|
38
|
+
*/
|
|
39
|
+
export function safeOpportunityGraphError(_error) {
|
|
40
|
+
return 'OpportunityEvaluationError: [redacted]';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Wraps a graph node function to emit agent_start/agent_end trace events
|
|
44
|
+
* at its boundaries so the frontend TRACE panel shows real-time progress.
|
|
45
|
+
* @param traceName - Kebab-case agent name (e.g. "opportunity-prep")
|
|
46
|
+
* @param nodeFn - The original node function
|
|
47
|
+
* @param summaryFn - Optional function to derive a summary string from the node result
|
|
48
|
+
*/
|
|
49
|
+
export function withNodeTrace(traceName, nodeFn, summaryFn) {
|
|
50
|
+
return async (state) => {
|
|
51
|
+
const traceEmitter = requestContext.getStore()?.traceEmitter;
|
|
52
|
+
const nodeStart = Date.now();
|
|
53
|
+
traceEmitter?.({ type: "agent_start", name: traceName });
|
|
54
|
+
try {
|
|
55
|
+
const result = await nodeFn(state);
|
|
56
|
+
const durationMs = Date.now() - nodeStart;
|
|
57
|
+
const summary = summaryFn?.(result) ?? undefined;
|
|
58
|
+
traceEmitter?.({ type: "agent_end", name: traceName, durationMs, summary });
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
const durationMs = Date.now() - nodeStart;
|
|
63
|
+
const errMsg = safeOpportunityGraphError(err);
|
|
64
|
+
traceEmitter?.({ type: "agent_end", name: traceName, durationMs, summary: `error: ${errMsg}` });
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** Shared trace summary: surface `error` when a node returned one. */
|
|
70
|
+
export function errorSummary(result) {
|
|
71
|
+
const r = result;
|
|
72
|
+
return r?.error ? `error: ${r.error}` : undefined;
|
|
73
|
+
}
|
|
74
|
+
/** Time window for persist-node dedup. Suppresses a second opportunity with the same person while a recent one (within 30 days) is still in flight, so a person is not re-surfaced multiple times within a month (EDG-23). */
|
|
75
|
+
export const DEDUP_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
|
|
76
|
+
const ACTIVE_NEGOTIATION_TASK_STATES = new Set([
|
|
77
|
+
'submitted',
|
|
78
|
+
'working',
|
|
79
|
+
'input_required',
|
|
80
|
+
'waiting_for_agent',
|
|
81
|
+
'claimed',
|
|
82
|
+
]);
|
|
83
|
+
export function isActiveNegotiationTaskFresh(task) {
|
|
84
|
+
if (!ACTIVE_NEGOTIATION_TASK_STATES.has(task.state))
|
|
85
|
+
return false;
|
|
86
|
+
const freshnessMs = task.state === 'input_required'
|
|
87
|
+
? askUserAnswerWindowMs() + ASK_USER_LOCK_SLACK_MS
|
|
88
|
+
: 5 * 60 * 1000;
|
|
89
|
+
return Date.now() - new Date(task.updatedAt).getTime() < freshnessMs;
|
|
90
|
+
}
|
|
91
|
+
export function triggerForOwner(opportunity, ownerUserId) {
|
|
92
|
+
return opportunity.detection.triggeredBy
|
|
93
|
+
?? opportunity.actors.find((actor) => actor.userId === ownerUserId)?.intent;
|
|
94
|
+
}
|
|
95
|
+
export function belongsToOwnedIntent(opportunity, ownerUserId, triggerIntentId) {
|
|
96
|
+
return opportunity.detection.triggeredBy === triggerIntentId
|
|
97
|
+
|| opportunity.actors.some((actor) => actor.userId === ownerUserId && actor.intent === triggerIntentId);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* IND-567: Cool-down window (ms) for cross-query rejection suppression.
|
|
101
|
+
* Candidates with a recently rejected or stalled opportunity within this window
|
|
102
|
+
* receive a similarity penalty during evaluation ranking. Default 7 days.
|
|
103
|
+
* Override with DISCOVERY_REJECTION_COOLDOWN_DAYS (positive float).
|
|
104
|
+
*/
|
|
105
|
+
const DEFAULT_REJECTION_COOLDOWN_MS = 7 * 24 * 60 * 60 * 1000;
|
|
106
|
+
export function getRejectionCooldownMs() {
|
|
107
|
+
const raw = process.env.DISCOVERY_REJECTION_COOLDOWN_DAYS;
|
|
108
|
+
if (!raw)
|
|
109
|
+
return DEFAULT_REJECTION_COOLDOWN_MS;
|
|
110
|
+
const n = Number.parseFloat(raw);
|
|
111
|
+
return Number.isFinite(n) && n > 0 ? Math.round(n * 24 * 60 * 60 * 1000) : DEFAULT_REJECTION_COOLDOWN_MS;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Similarity multiplier applied to candidates that fall within the rejection
|
|
115
|
+
* cool-down window (IND-567). 0.5 halves their ranking score, typically
|
|
116
|
+
* pushing them below the evaluation-batch cut while leaving a soft trace in
|
|
117
|
+
* the trace log rather than silently dropping them.
|
|
118
|
+
*/
|
|
119
|
+
export const REJECTION_COOLDOWN_SIMILARITY_PENALTY = 0.5;
|
|
120
|
+
/** Default cap for source premises used by premise-to-premise discovery. Prevents BACKEND-5-style fan-out. */
|
|
121
|
+
const DEFAULT_SOURCE_PREMISE_DISCOVERY_LIMIT = 40;
|
|
122
|
+
/** NUL separator: it cannot occur inside an id, so the composite key is unambiguous. */
|
|
123
|
+
const PAIR_KEY_SEPARATOR = String.fromCharCode(0);
|
|
124
|
+
export function networkMembershipPairKey(userId, networkId) {
|
|
125
|
+
return userId + PAIR_KEY_SEPARATOR + networkId;
|
|
126
|
+
}
|
|
127
|
+
/** Per-source cap for candidate premise matches. */
|
|
128
|
+
export const PREMISE_MATCH_LIMIT_PER_SOURCE = 20;
|
|
129
|
+
/** Resolve the source premise discovery cap from env, preserving 0 as an explicit disable switch. */
|
|
130
|
+
export function getSourcePremiseDiscoveryLimit() {
|
|
131
|
+
const raw = process.env.DISCOVERY_SOURCE_PREMISE_LIMIT;
|
|
132
|
+
if (raw === undefined || raw.trim() === '')
|
|
133
|
+
return DEFAULT_SOURCE_PREMISE_DISCOVERY_LIMIT;
|
|
134
|
+
const parsed = Number.parseInt(raw, 10);
|
|
135
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_SOURCE_PREMISE_DISCOVERY_LIMIT;
|
|
136
|
+
}
|
|
137
|
+
export function buildEvaluatorEvidenceKey(candidate) {
|
|
138
|
+
return [
|
|
139
|
+
candidate.candidateUserId,
|
|
140
|
+
candidate.networkId,
|
|
141
|
+
candidate.candidateIntentId ?? candidate.candidatePremiseId ?? candidate.candidateContextId ?? candidate.sourceContextId ?? 'profile',
|
|
142
|
+
].join(':');
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Builds a compact text summary of the discoverer's profile and active intents
|
|
146
|
+
* for use as profileContext in HyDE generation.
|
|
147
|
+
* @param profile - The discoverer's profile data (identity, attributes)
|
|
148
|
+
* @param intents - The discoverer's indexed intents (capped at 5)
|
|
149
|
+
* @returns A context string, or undefined if no meaningful data is available
|
|
150
|
+
*/
|
|
151
|
+
export function buildDiscovererContext(profile, intents) {
|
|
152
|
+
const lines = [];
|
|
153
|
+
if (profile) {
|
|
154
|
+
const identity = profile.identity;
|
|
155
|
+
if (identity?.name || identity?.bio) {
|
|
156
|
+
lines.push(`Profile: ${[identity.name, identity.bio].filter(Boolean).join(', ')}`);
|
|
157
|
+
}
|
|
158
|
+
if (identity?.location) {
|
|
159
|
+
lines.push(`Location: ${identity.location}`);
|
|
160
|
+
}
|
|
161
|
+
if (profile.context) {
|
|
162
|
+
lines.push(`Context: ${profile.context}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (intents?.length) {
|
|
166
|
+
// indexedIntents preserves DB order from getActiveIntents (newest first),
|
|
167
|
+
// so slice(0, 5) is deterministic without an explicit sort.
|
|
168
|
+
const capped = intents.slice(0, 5);
|
|
169
|
+
lines.push('');
|
|
170
|
+
lines.push('Active intents:');
|
|
171
|
+
for (const intent of capped) {
|
|
172
|
+
lines.push(`- ${intent.payload}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return lines.length > 0 ? lines.join('\n') : undefined;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Build a networkContexts map for the evaluator from a set of entities.
|
|
179
|
+
* Fetches network data, checks permissions.contextInjection.discovery,
|
|
180
|
+
* and renders context for eligible networks.
|
|
181
|
+
*/
|
|
182
|
+
export async function buildNetworkContexts(entities, database) {
|
|
183
|
+
const networkIds = [...new Set(entities.map((e) => e.networkId))];
|
|
184
|
+
const networks = await Promise.all(networkIds.map((nid) => database.getNetwork(nid).then((n) => ({ nid, n }))));
|
|
185
|
+
const contexts = {};
|
|
186
|
+
for (const { nid, n: network } of networks) {
|
|
187
|
+
if (!network)
|
|
188
|
+
continue;
|
|
189
|
+
const perms = (network.permissions ?? {});
|
|
190
|
+
const injection = perms.contextInjection;
|
|
191
|
+
if (injection?.discovery === false)
|
|
192
|
+
continue;
|
|
193
|
+
contexts[nid] = renderNetworkContext({
|
|
194
|
+
title: network.title,
|
|
195
|
+
prompt: network.prompt,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return contexts;
|
|
199
|
+
}
|