@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.
Files changed (184) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/IMPLEMENTATION.md +50 -52
  3. package/STABILITY.md +3 -3
  4. package/dist/chat/chat.agent.js +2 -3
  5. package/dist/chat/chat.graph.d.ts +41 -1
  6. package/dist/chat/chat.graph.js +108 -127
  7. package/dist/chat/negotiator.persona.d.ts +1 -1
  8. package/dist/chat/negotiator.persona.js +1 -4
  9. package/dist/chat/negotiator.prompt.js +1 -2
  10. package/dist/chat/onboarding.persona.js +0 -1
  11. package/dist/chat/reporter.persona.js +0 -1
  12. package/dist/chat/signal.persona.js +0 -1
  13. package/dist/contacts/application/contact.tools.d.ts +6 -9
  14. package/dist/contacts/application/contact.tools.js +11 -92
  15. package/dist/contacts/application/index.d.ts +2 -14
  16. package/dist/contacts/application/index.js +2 -13
  17. package/dist/contacts/domain/contact.types.d.ts +0 -23
  18. package/dist/contacts/domain/index.d.ts +2 -6
  19. package/dist/contacts/index.d.ts +1 -1
  20. package/dist/contacts/index.js +1 -1
  21. package/dist/contacts/ports/contact.repository.port.d.ts +5 -12
  22. package/dist/contacts/ports/contact.repository.port.js +4 -6
  23. package/dist/contacts/ports/contact.tools.port.d.ts +1 -3
  24. package/dist/contacts/ports/contact.tools.port.js +1 -2
  25. package/dist/contacts/ports/index.d.ts +1 -1
  26. package/dist/contacts/ports/index.js +1 -1
  27. package/dist/discovery/hyde.frame.d.ts +4 -4
  28. package/dist/discovery/hyde.graph.d.ts +71 -12
  29. package/dist/discovery/hyde.graph.js +337 -335
  30. package/dist/discovery/lens.inferrer.d.ts +6 -6
  31. package/dist/enrichment/enrichment.graph.d.ts +127 -9
  32. package/dist/enrichment/enrichment.graph.js +633 -655
  33. package/dist/enrichment/enrichment.state.d.ts +1 -1
  34. package/dist/enrichment/enrichment.tools.context-read.d.ts +10 -0
  35. package/dist/enrichment/enrichment.tools.context-read.js +353 -0
  36. package/dist/enrichment/enrichment.tools.context-write.d.ts +9 -0
  37. package/dist/enrichment/enrichment.tools.context-write.js +417 -0
  38. package/dist/enrichment/enrichment.tools.d.ts +11 -1
  39. package/dist/enrichment/enrichment.tools.helpers.d.ts +139 -0
  40. package/dist/enrichment/enrichment.tools.helpers.js +234 -0
  41. package/dist/enrichment/enrichment.tools.js +16 -975
  42. package/dist/index.d.ts +27 -50
  43. package/dist/index.js +17 -28
  44. package/dist/intents/application/intent.graph.d.ts +71 -67
  45. package/dist/intents/application/intent.graph.execute.d.ts +59 -0
  46. package/dist/intents/application/intent.graph.execute.js +301 -0
  47. package/dist/intents/application/intent.graph.infer.d.ts +44 -0
  48. package/dist/intents/application/intent.graph.infer.js +97 -0
  49. package/dist/intents/application/intent.graph.js +96 -888
  50. package/dist/intents/application/intent.graph.reconcile.d.ts +71 -0
  51. package/dist/intents/application/intent.graph.reconcile.js +274 -0
  52. package/dist/intents/application/intent.graph.shared.d.ts +70 -0
  53. package/dist/intents/application/intent.graph.shared.js +153 -0
  54. package/dist/intents/domain/intent.state.d.ts +1 -1
  55. package/dist/maintenance/maintenance.graph.d.ts +66 -3
  56. package/dist/maintenance/maintenance.graph.js +155 -156
  57. package/dist/mcp/mcp.authorization-policy.d.ts +24 -28
  58. package/dist/mcp/mcp.authorization-policy.js +14 -34
  59. package/dist/mcp/mcp.server.d.ts +3 -3
  60. package/dist/mcp/mcp.server.js +14 -20
  61. package/dist/negotiations/application/negotiation.candidates.d.ts +83 -0
  62. package/dist/negotiations/application/negotiation.candidates.js +162 -0
  63. package/dist/negotiations/application/negotiation.graph.d.ts +91 -157
  64. package/dist/negotiations/application/negotiation.graph.finalize.d.ts +5 -0
  65. package/dist/negotiations/application/negotiation.graph.finalize.js +280 -0
  66. package/dist/negotiations/application/negotiation.graph.init.d.ts +54 -0
  67. package/dist/negotiations/application/negotiation.graph.init.js +227 -0
  68. package/dist/negotiations/application/negotiation.graph.js +69 -1388
  69. package/dist/negotiations/application/negotiation.graph.screen.d.ts +23 -0
  70. package/dist/negotiations/application/negotiation.graph.screen.js +108 -0
  71. package/dist/negotiations/application/negotiation.graph.shared.d.ts +75 -0
  72. package/dist/negotiations/application/negotiation.graph.shared.js +125 -0
  73. package/dist/negotiations/application/negotiation.graph.turn.d.ts +105 -0
  74. package/dist/negotiations/application/negotiation.graph.turn.js +484 -0
  75. package/dist/negotiations/domain/negotiation.state.d.ts +1 -1
  76. package/dist/negotiations/domain/negotiation.state.js +0 -1
  77. package/dist/networks/application/indexer.graph.d.ts +165 -7
  78. package/dist/networks/application/indexer.graph.js +339 -388
  79. package/dist/networks/application/indexer.state.d.ts +1 -1
  80. package/dist/networks/application/membership.graph.d.ts +83 -5
  81. package/dist/networks/application/membership.graph.js +177 -207
  82. package/dist/networks/application/network.graph.d.ts +148 -5
  83. package/dist/networks/application/network.graph.js +249 -278
  84. package/dist/networks/domain/membership.state.d.ts +1 -1
  85. package/dist/networks/domain/network.state.d.ts +1 -1
  86. package/dist/opportunities/application/delivery-card.cache.d.ts +1 -1
  87. package/dist/opportunities/application/delivery-card.cache.js +2 -2
  88. package/dist/opportunities/application/index.d.ts +2 -2
  89. package/dist/opportunities/application/index.js +2 -2
  90. package/dist/opportunities/application/opportunity.evaluator.js +1 -1
  91. package/dist/opportunities/application/opportunity.graph.d.ts +686 -473
  92. package/dist/opportunities/application/opportunity.graph.discovery-strategies.d.ts +109 -0
  93. package/dist/opportunities/application/opportunity.graph.discovery-strategies.js +451 -0
  94. package/dist/opportunities/application/opportunity.graph.discovery.d.ts +69 -0
  95. package/dist/opportunities/application/opportunity.graph.discovery.js +397 -0
  96. package/dist/opportunities/application/opportunity.graph.evaluation.d.ts +82 -0
  97. package/dist/opportunities/application/opportunity.graph.evaluation.js +608 -0
  98. package/dist/opportunities/application/opportunity.graph.js +120 -3690
  99. package/dist/opportunities/application/opportunity.graph.modes.d.ts +538 -0
  100. package/dist/opportunities/application/opportunity.graph.modes.js +538 -0
  101. package/dist/opportunities/application/opportunity.graph.negotiate.d.ts +109 -0
  102. package/dist/opportunities/application/opportunity.graph.negotiate.js +392 -0
  103. package/dist/opportunities/application/opportunity.graph.persist-node.d.ts +93 -0
  104. package/dist/opportunities/application/opportunity.graph.persist-node.js +765 -0
  105. package/dist/opportunities/application/opportunity.graph.prep.d.ts +150 -0
  106. package/dist/opportunities/application/opportunity.graph.prep.js +381 -0
  107. package/dist/opportunities/application/opportunity.graph.shared.d.ts +173 -0
  108. package/dist/opportunities/application/opportunity.graph.shared.js +199 -0
  109. package/dist/opportunities/application/opportunity.presentation.d.ts +399 -0
  110. package/dist/opportunities/application/{opportunity.presenter.js → opportunity.presentation.js} +735 -9
  111. package/dist/opportunities/application/opportunity.tools.cards.d.ts +152 -0
  112. package/dist/opportunities/application/opportunity.tools.cards.js +235 -0
  113. package/dist/opportunities/application/opportunity.tools.d.ts +8 -114
  114. package/dist/opportunities/application/opportunity.tools.js +28 -711
  115. package/dist/opportunities/application/opportunity.tools.list.d.ts +10 -0
  116. package/dist/opportunities/application/opportunity.tools.list.js +493 -0
  117. package/dist/opportunities/domain/index.d.ts +3 -3
  118. package/dist/opportunities/domain/index.js +3 -3
  119. package/dist/opportunities/domain/opportunity.state.d.ts +19 -19
  120. package/dist/opportunities/index.d.ts +6 -6
  121. package/dist/opportunities/index.js +4 -4
  122. package/dist/opportunities/ports/opportunity.tools.port.d.ts +1 -1
  123. package/dist/opportunities/radar/radar.graph.d.ts +57 -13
  124. package/dist/opportunities/radar/radar.graph.js +470 -471
  125. package/dist/premises/premise.graph.d.ts +88 -20
  126. package/dist/premises/premise.graph.js +207 -218
  127. package/dist/questions/domain/question.schema.d.ts +40 -40
  128. package/dist/shared/agent/tool.factory.js +0 -8
  129. package/dist/shared/agent/tool.helpers.d.ts +21 -45
  130. package/dist/shared/agent/tool.helpers.js +1 -2
  131. package/dist/shared/agent/tool.registry.d.ts +4 -3
  132. package/dist/shared/agent/tool.registry.js +2 -4
  133. package/dist/shared/agent/tool.runtime.js +0 -2
  134. package/dist/shared/agent/utility.tools.js +9 -13
  135. package/dist/shared/interfaces/database.capabilities.d.ts +100 -0
  136. package/dist/shared/interfaces/database.capabilities.js +7 -0
  137. package/dist/shared/interfaces/database.entities.d.ts +533 -0
  138. package/dist/shared/interfaces/database.entities.js +10 -0
  139. package/dist/shared/interfaces/database.identity-queries.d.ts +294 -0
  140. package/dist/shared/interfaces/database.identity-queries.js +4 -0
  141. package/dist/shared/interfaces/database.interface.d.ts +15 -2277
  142. package/dist/shared/interfaces/database.interface.js +8 -0
  143. package/dist/shared/interfaces/database.member-queries.d.ts +221 -0
  144. package/dist/shared/interfaces/database.member-queries.js +4 -0
  145. package/dist/shared/interfaces/database.negotiation.d.ts +305 -0
  146. package/dist/shared/interfaces/database.negotiation.js +26 -0
  147. package/dist/shared/interfaces/database.network-queries.d.ts +277 -0
  148. package/dist/shared/interfaces/database.network-queries.js +4 -0
  149. package/dist/shared/interfaces/database.opportunity-queries.d.ts +285 -0
  150. package/dist/shared/interfaces/database.opportunity-queries.js +4 -0
  151. package/dist/shared/interfaces/database.port.d.ts +322 -0
  152. package/dist/shared/interfaces/database.port.js +29 -0
  153. package/dist/shared/schemas/discovery-question.schema.d.ts +14 -14
  154. package/dist/shared/schemas/negotiation-digest.schema.d.ts +2 -2
  155. package/package.json +2 -15
  156. package/dist/contacts/application/contact.inviter.d.ts +0 -49
  157. package/dist/contacts/application/contact.inviter.js +0 -64
  158. package/dist/integrations/application/index.d.ts +0 -14
  159. package/dist/integrations/application/index.js +0 -14
  160. package/dist/integrations/application/integration.tools.d.ts +0 -27
  161. package/dist/integrations/application/integration.tools.js +0 -98
  162. package/dist/integrations/domain/index.d.ts +0 -16
  163. package/dist/integrations/domain/index.js +0 -1
  164. package/dist/integrations/domain/integration.types.d.ts +0 -51
  165. package/dist/integrations/domain/integration.types.js +0 -9
  166. package/dist/integrations/index.d.ts +0 -10
  167. package/dist/integrations/index.js +0 -8
  168. package/dist/integrations/ports/index.d.ts +0 -25
  169. package/dist/integrations/ports/index.js +0 -23
  170. package/dist/integrations/ports/integration.adapter.port.d.ts +0 -62
  171. package/dist/integrations/ports/integration.adapter.port.js +0 -15
  172. package/dist/integrations/ports/integration.importer.port.d.ts +0 -31
  173. package/dist/integrations/ports/integration.importer.port.js +0 -15
  174. package/dist/integrations/ports/integration.tools.port.d.ts +0 -25
  175. package/dist/integrations/ports/integration.tools.port.js +0 -18
  176. package/dist/opportunities/application/opportunity.card-presentation.d.ts +0 -44
  177. package/dist/opportunities/application/opportunity.card-presentation.js +0 -93
  178. package/dist/opportunities/application/opportunity.presenter.d.ts +0 -156
  179. package/dist/opportunities/domain/opportunity.presentation-cache.d.ts +0 -5
  180. package/dist/opportunities/domain/opportunity.presentation-cache.js +0 -11
  181. package/dist/opportunities/domain/opportunity.presentation.d.ts +0 -76
  182. package/dist/opportunities/domain/opportunity.presentation.js +0 -516
  183. package/dist/opportunities/domain/opportunity.safe-presentation.d.ts +0 -104
  184. 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
+ }