@indexnetwork/protocol 4.17.0-rc.360.1 → 4.18.0-rc.362.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 +2 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/negotiation/negotiation.graph.d.ts.map +1 -1
- package/dist/negotiation/negotiation.graph.js +25 -0
- package/dist/negotiation/negotiation.graph.js.map +1 -1
- package/dist/opportunity/discriminator/discriminator.adjustments.d.ts +10 -1
- package/dist/opportunity/discriminator/discriminator.adjustments.d.ts.map +1 -1
- package/dist/opportunity/discriminator/discriminator.adjustments.js +12 -4
- package/dist/opportunity/discriminator/discriminator.adjustments.js.map +1 -1
- package/dist/opportunity/discriminator/discriminator.question.d.ts +2 -0
- package/dist/opportunity/discriminator/discriminator.question.d.ts.map +1 -1
- package/dist/opportunity/discriminator/discriminator.question.js +1 -0
- package/dist/opportunity/discriminator/discriminator.question.js.map +1 -1
- package/dist/opportunity/feed/feed.graph.js +2 -2
- package/dist/opportunity/feed/feed.graph.js.map +1 -1
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.env.d.ts +44 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.env.d.ts.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.env.js +45 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.env.js.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.extractor.d.ts +25 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.extractor.d.ts.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.extractor.js +189 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.extractor.js.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.miner.d.ts +27 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.miner.d.ts.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.miner.js +113 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.miner.js.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.shadow.d.ts +20 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.shadow.d.ts.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.shadow.js +62 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.shadow.js.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.types.d.ts +192 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.types.d.ts.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.types.js +19 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.types.js.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.verifier.d.ts +35 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.verifier.d.ts.map +1 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.verifier.js +92 -0
- package/dist/opportunity/negotiation-evidence/negotiation-evidence.verifier.js.map +1 -0
- package/dist/opportunity/opportunity.graph.d.ts +9 -1
- package/dist/opportunity/opportunity.graph.d.ts.map +1 -1
- package/dist/opportunity/opportunity.graph.js +64 -31
- package/dist/opportunity/opportunity.graph.js.map +1 -1
- package/dist/questioner/questioner.types.d.ts +2 -0
- package/dist/questioner/questioner.types.d.ts.map +1 -1
- package/dist/questioner/questioner.types.js.map +1 -1
- package/dist/shared/agent/model.config.d.ts +5 -0
- package/dist/shared/agent/model.config.d.ts.map +1 -1
- package/dist/shared/agent/model.config.js +1 -0
- package/dist/shared/agent/model.config.js.map +1 -1
- package/dist/shared/schemas/question.schema.d.ts +21 -0
- package/dist/shared/schemas/question.schema.d.ts.map +1 -1
- package/dist/shared/schemas/question.schema.js +6 -0
- package/dist/shared/schemas/question.schema.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lens C negotiation-evidence — shared types (IND-433).
|
|
3
|
+
*
|
|
4
|
+
* Lens C mines neutral clarification hypotheses from RECURRING negotiation
|
|
5
|
+
* evidence, read in place at mining time. It never builds a durable transcript
|
|
6
|
+
* projection and never summarizes an entire pair DM; the only content it will
|
|
7
|
+
* ever touch is a narrow, positively-constructed allowlist:
|
|
8
|
+
*
|
|
9
|
+
* - authoritative owner answers (the recipient's own answers),
|
|
10
|
+
* - structured bilateral actions / coarse outcomes, and
|
|
11
|
+
* - explicitly shared message content.
|
|
12
|
+
*
|
|
13
|
+
* Everything else — screen/evaluator reasoning, agent chain-of-thought,
|
|
14
|
+
* `memoryHints`, private negotiator memories/reflections, disclosure subjects,
|
|
15
|
+
* untagged shared answers, and old synthesized digests — is excluded by
|
|
16
|
+
* construction (never mapped into an {@link AllowlistedEvidence}).
|
|
17
|
+
*/
|
|
18
|
+
/** The four allowlisted evidence families. Nothing else may be surfaced. */
|
|
19
|
+
export type EvidenceKind = "owner_answer" | "bilateral_action" | "coarse_outcome" | "shared_message";
|
|
20
|
+
/**
|
|
21
|
+
* Who authored an evidence unit. `system` covers structured bilateral facts
|
|
22
|
+
* (actions/outcomes) that belong to neither party's voice. The distinction is
|
|
23
|
+
* load-bearing: a counterparty statement may support an OBSERVATION but never
|
|
24
|
+
* a fact or preference ABOUT the recipient (IND-433).
|
|
25
|
+
*/
|
|
26
|
+
export type EvidenceSpeaker = "owner" | "counterparty" | "system";
|
|
27
|
+
/**
|
|
28
|
+
* One unit of allowlisted evidence, extracted in place for exactly one
|
|
29
|
+
* (recipient, intent, opportunity, task) tuple. Provenance travels with the
|
|
30
|
+
* unit so cross-recipient / cross-intent / cross-opportunity / cross-network /
|
|
31
|
+
* cross-task / cross-speaker contamination is a pure-function rejection rather
|
|
32
|
+
* than a downstream concern.
|
|
33
|
+
*/
|
|
34
|
+
export interface AllowlistedEvidence {
|
|
35
|
+
/** Deterministic id, unique within one mining pass: `${kind}:${opportunityId}:${ordinal}`. */
|
|
36
|
+
evidenceId: string;
|
|
37
|
+
kind: EvidenceKind;
|
|
38
|
+
speaker: EvidenceSpeaker;
|
|
39
|
+
/** The only text a support reference may quote — bounded, exclusion-scrubbed. */
|
|
40
|
+
content: string;
|
|
41
|
+
recipientUserId: string;
|
|
42
|
+
intentId: string;
|
|
43
|
+
intentFingerprint: string;
|
|
44
|
+
opportunityId: string;
|
|
45
|
+
taskId: string;
|
|
46
|
+
conversationId: string;
|
|
47
|
+
networkId: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* One raw negotiation turn as read in place. Untrusted: it still carries the
|
|
51
|
+
* fields Lens C must EXCLUDE (`reasoning`, `askUser`/disclosure). The extractor
|
|
52
|
+
* maps only the allowlisted projection of this record.
|
|
53
|
+
*/
|
|
54
|
+
export interface RawEvidenceTurn {
|
|
55
|
+
/** Turn author user id — mapped to owner/counterparty against the segment. */
|
|
56
|
+
senderUserId: string;
|
|
57
|
+
/** Structured bilateral action (propose/accept/counter/decline/...). */
|
|
58
|
+
action: string;
|
|
59
|
+
/** Free-text message body, if any. */
|
|
60
|
+
message?: string | null;
|
|
61
|
+
/**
|
|
62
|
+
* True only when this message was EXPLICITLY shared/consented for reuse.
|
|
63
|
+
* Untagged messages are excluded — Lens C never mines an untagged answer.
|
|
64
|
+
*/
|
|
65
|
+
sharedTagged?: boolean;
|
|
66
|
+
/** Chain-of-thought — EXCLUDED. Present here only to prove it is dropped. */
|
|
67
|
+
reasoning?: string | null;
|
|
68
|
+
/** Disclosure subject — EXCLUDED. Present here only to prove it is dropped. */
|
|
69
|
+
disclosureSubject?: string | null;
|
|
70
|
+
}
|
|
71
|
+
/** Coarse, structured outcome facts (no evaluator reasoning). */
|
|
72
|
+
export interface RawEvidenceOutcome {
|
|
73
|
+
hasOpportunity: boolean;
|
|
74
|
+
/** `turn_cap | timeout` are coarse; `screened_out` is a private gate → dropped. */
|
|
75
|
+
reason?: "turn_cap" | "timeout" | "screened_out";
|
|
76
|
+
/** Agreed collaboration roles, if any. */
|
|
77
|
+
agreedRoles?: Array<{
|
|
78
|
+
userId: string;
|
|
79
|
+
role: string;
|
|
80
|
+
}>;
|
|
81
|
+
/** Evaluator reasoning — EXCLUDED. Present here only to prove it is dropped. */
|
|
82
|
+
reasoning?: string | null;
|
|
83
|
+
}
|
|
84
|
+
/** Authoritative owner answer (the recipient's own answer to a question). */
|
|
85
|
+
export interface RawEvidenceOwnerAnswer {
|
|
86
|
+
/** Answerer user id — must equal the segment recipient to be authoritative. */
|
|
87
|
+
answererUserId: string;
|
|
88
|
+
selectedOptions: string[];
|
|
89
|
+
freeText?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* All in-place negotiation data for ONE opportunity segment, scoped to an
|
|
93
|
+
* exact recipient + intent/fingerprint + opportunity + task. Continuations of
|
|
94
|
+
* the same opportunity arrive as separate segments sharing `opportunityId`;
|
|
95
|
+
* the extractor groups them and counts the opportunity once.
|
|
96
|
+
*/
|
|
97
|
+
export interface RawEvidenceSegment {
|
|
98
|
+
recipientUserId: string;
|
|
99
|
+
intentId: string;
|
|
100
|
+
intentFingerprint: string;
|
|
101
|
+
opportunityId: string;
|
|
102
|
+
taskId: string;
|
|
103
|
+
conversationId: string;
|
|
104
|
+
networkId: string;
|
|
105
|
+
/** The counterparty in this bilateral negotiation. */
|
|
106
|
+
counterpartyUserId: string;
|
|
107
|
+
turns: RawEvidenceTurn[];
|
|
108
|
+
outcome?: RawEvidenceOutcome | null;
|
|
109
|
+
ownerAnswers?: RawEvidenceOwnerAnswer[];
|
|
110
|
+
}
|
|
111
|
+
/** The scope a mining pass is bound to — every segment must match it exactly. */
|
|
112
|
+
export interface EvidenceMiningScope {
|
|
113
|
+
recipientUserId: string;
|
|
114
|
+
intentId: string;
|
|
115
|
+
intentFingerprint: string;
|
|
116
|
+
networkId: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The three claim shapes a hypothesis may take. The speaker constraint is
|
|
120
|
+
* enforced against these: `recipient_fact` / `recipient_preference` require
|
|
121
|
+
* owner-authored (or structured bilateral) support; `observation` may also be
|
|
122
|
+
* supported by counterparty statements.
|
|
123
|
+
*/
|
|
124
|
+
export type HypothesisClaimType = "observation" | "recipient_fact" | "recipient_preference";
|
|
125
|
+
/** A support reference proposed by the miner (before code-side verification). */
|
|
126
|
+
export interface ProposedSupportRef {
|
|
127
|
+
/** Must resolve to an {@link AllowlistedEvidence} in the pass. */
|
|
128
|
+
evidenceId: string;
|
|
129
|
+
/** Verbatim span the miner copied from that evidence's content. */
|
|
130
|
+
span: string;
|
|
131
|
+
}
|
|
132
|
+
/** One hypothesis proposed by the miner. */
|
|
133
|
+
export interface MinedEvidenceHypothesis {
|
|
134
|
+
/** Neutral, non-identifying clarification hypothesis. */
|
|
135
|
+
statement: string;
|
|
136
|
+
claimType: HypothesisClaimType;
|
|
137
|
+
supportRefs: ProposedSupportRef[];
|
|
138
|
+
}
|
|
139
|
+
/** A support reference that resolved against the allowlist. */
|
|
140
|
+
export interface VerifiedSupportRef {
|
|
141
|
+
evidenceId: string;
|
|
142
|
+
kind: EvidenceKind;
|
|
143
|
+
speaker: EvidenceSpeaker;
|
|
144
|
+
opportunityId: string;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A hypothesis after verification + the recurrence gate. Retained hypotheses
|
|
148
|
+
* are returned for OFFLINE review only — shadow mode never persists or logs
|
|
149
|
+
* their text (see {@link NegotiationEvidenceTelemetry}).
|
|
150
|
+
*/
|
|
151
|
+
export interface RetainedEvidenceHypothesis {
|
|
152
|
+
statement: string;
|
|
153
|
+
claimType: HypothesisClaimType;
|
|
154
|
+
support: VerifiedSupportRef[];
|
|
155
|
+
/** Count of DISTINCT opportunities in `support` — the recurrence measure. */
|
|
156
|
+
distinctOpportunities: number;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Aggregate-only telemetry. Deliberately carries NO evidence content, NO
|
|
160
|
+
* hypothesis text, and NO spans — only counts — so it is safe to emit to
|
|
161
|
+
* routine logs without leaking internal negotiation content.
|
|
162
|
+
*/
|
|
163
|
+
export interface NegotiationEvidenceTelemetry {
|
|
164
|
+
recipientUserId: string;
|
|
165
|
+
intentId: string;
|
|
166
|
+
/** Raw segments supplied to the pass (pre-grouping). */
|
|
167
|
+
segments: number;
|
|
168
|
+
/** Distinct opportunities after continuation grouping. */
|
|
169
|
+
distinctOpportunities: number;
|
|
170
|
+
/** Allowlisted evidence unit counts, by kind. */
|
|
171
|
+
evidenceCounts: Record<EvidenceKind, number>;
|
|
172
|
+
/** Records dropped by allowlist / exclusion / provenance mismatch. */
|
|
173
|
+
excludedRecords: number;
|
|
174
|
+
hypothesesMined: number;
|
|
175
|
+
/** Hypotheses whose every support ref verified against the allowlist. */
|
|
176
|
+
hypothesesSupported: number;
|
|
177
|
+
/** Supported hypotheses that also met the distinct-opportunity floor. */
|
|
178
|
+
hypothesesRecurrent: number;
|
|
179
|
+
/** Hypotheses discarded (unsupported ref, speaker violation, or too rare). */
|
|
180
|
+
hypothesesDiscarded: number;
|
|
181
|
+
}
|
|
182
|
+
/** Result of one shadow mining pass. */
|
|
183
|
+
export interface NegotiationEvidenceShadowResult {
|
|
184
|
+
/** Safe-to-log aggregate counts. */
|
|
185
|
+
telemetry: NegotiationEvidenceTelemetry;
|
|
186
|
+
/**
|
|
187
|
+
* Retained recurrent hypotheses for offline eval. In shadow mode the caller
|
|
188
|
+
* MUST NOT persist these or write them to routine logs.
|
|
189
|
+
*/
|
|
190
|
+
hypotheses: RetainedEvidenceHypothesis[];
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=negotiation-evidence.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiation-evidence.types.d.ts","sourceRoot":"/","sources":["opportunity/negotiation-evidence/negotiation-evidence.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lens C negotiation-evidence — shared types (IND-433).
|
|
3
|
+
*
|
|
4
|
+
* Lens C mines neutral clarification hypotheses from RECURRING negotiation
|
|
5
|
+
* evidence, read in place at mining time. It never builds a durable transcript
|
|
6
|
+
* projection and never summarizes an entire pair DM; the only content it will
|
|
7
|
+
* ever touch is a narrow, positively-constructed allowlist:
|
|
8
|
+
*
|
|
9
|
+
* - authoritative owner answers (the recipient's own answers),
|
|
10
|
+
* - structured bilateral actions / coarse outcomes, and
|
|
11
|
+
* - explicitly shared message content.
|
|
12
|
+
*
|
|
13
|
+
* Everything else — screen/evaluator reasoning, agent chain-of-thought,
|
|
14
|
+
* `memoryHints`, private negotiator memories/reflections, disclosure subjects,
|
|
15
|
+
* untagged shared answers, and old synthesized digests — is excluded by
|
|
16
|
+
* construction (never mapped into an {@link AllowlistedEvidence}).
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=negotiation-evidence.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiation-evidence.types.js","sourceRoot":"/","sources":["opportunity/negotiation-evidence/negotiation-evidence.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG","sourcesContent":["/**\n * Lens C negotiation-evidence — shared types (IND-433).\n *\n * Lens C mines neutral clarification hypotheses from RECURRING negotiation\n * evidence, read in place at mining time. It never builds a durable transcript\n * projection and never summarizes an entire pair DM; the only content it will\n * ever touch is a narrow, positively-constructed allowlist:\n *\n * - authoritative owner answers (the recipient's own answers),\n * - structured bilateral actions / coarse outcomes, and\n * - explicitly shared message content.\n *\n * Everything else — screen/evaluator reasoning, agent chain-of-thought,\n * `memoryHints`, private negotiator memories/reflections, disclosure subjects,\n * untagged shared answers, and old synthesized digests — is excluded by\n * construction (never mapped into an {@link AllowlistedEvidence}).\n */\n\n/** The four allowlisted evidence families. Nothing else may be surfaced. */\nexport type EvidenceKind =\n | \"owner_answer\"\n | \"bilateral_action\"\n | \"coarse_outcome\"\n | \"shared_message\";\n\n/**\n * Who authored an evidence unit. `system` covers structured bilateral facts\n * (actions/outcomes) that belong to neither party's voice. The distinction is\n * load-bearing: a counterparty statement may support an OBSERVATION but never\n * a fact or preference ABOUT the recipient (IND-433).\n */\nexport type EvidenceSpeaker = \"owner\" | \"counterparty\" | \"system\";\n\n/**\n * One unit of allowlisted evidence, extracted in place for exactly one\n * (recipient, intent, opportunity, task) tuple. Provenance travels with the\n * unit so cross-recipient / cross-intent / cross-opportunity / cross-network /\n * cross-task / cross-speaker contamination is a pure-function rejection rather\n * than a downstream concern.\n */\nexport interface AllowlistedEvidence {\n /** Deterministic id, unique within one mining pass: `${kind}:${opportunityId}:${ordinal}`. */\n evidenceId: string;\n kind: EvidenceKind;\n speaker: EvidenceSpeaker;\n /** The only text a support reference may quote — bounded, exclusion-scrubbed. */\n content: string;\n // Provenance (used for keying + contamination rejection; never sent to the LLM).\n recipientUserId: string;\n intentId: string;\n intentFingerprint: string;\n opportunityId: string;\n taskId: string;\n conversationId: string;\n networkId: string;\n}\n\n/**\n * One raw negotiation turn as read in place. Untrusted: it still carries the\n * fields Lens C must EXCLUDE (`reasoning`, `askUser`/disclosure). The extractor\n * maps only the allowlisted projection of this record.\n */\nexport interface RawEvidenceTurn {\n /** Turn author user id — mapped to owner/counterparty against the segment. */\n senderUserId: string;\n /** Structured bilateral action (propose/accept/counter/decline/...). */\n action: string;\n /** Free-text message body, if any. */\n message?: string | null;\n /**\n * True only when this message was EXPLICITLY shared/consented for reuse.\n * Untagged messages are excluded — Lens C never mines an untagged answer.\n */\n sharedTagged?: boolean;\n /** Chain-of-thought — EXCLUDED. Present here only to prove it is dropped. */\n reasoning?: string | null;\n /** Disclosure subject — EXCLUDED. Present here only to prove it is dropped. */\n disclosureSubject?: string | null;\n}\n\n/** Coarse, structured outcome facts (no evaluator reasoning). */\nexport interface RawEvidenceOutcome {\n hasOpportunity: boolean;\n /** `turn_cap | timeout` are coarse; `screened_out` is a private gate → dropped. */\n reason?: \"turn_cap\" | \"timeout\" | \"screened_out\";\n /** Agreed collaboration roles, if any. */\n agreedRoles?: Array<{ userId: string; role: string }>;\n /** Evaluator reasoning — EXCLUDED. Present here only to prove it is dropped. */\n reasoning?: string | null;\n}\n\n/** Authoritative owner answer (the recipient's own answer to a question). */\nexport interface RawEvidenceOwnerAnswer {\n /** Answerer user id — must equal the segment recipient to be authoritative. */\n answererUserId: string;\n selectedOptions: string[];\n freeText?: string;\n}\n\n/**\n * All in-place negotiation data for ONE opportunity segment, scoped to an\n * exact recipient + intent/fingerprint + opportunity + task. Continuations of\n * the same opportunity arrive as separate segments sharing `opportunityId`;\n * the extractor groups them and counts the opportunity once.\n */\nexport interface RawEvidenceSegment {\n recipientUserId: string;\n intentId: string;\n intentFingerprint: string;\n opportunityId: string;\n taskId: string;\n conversationId: string;\n networkId: string;\n /** The counterparty in this bilateral negotiation. */\n counterpartyUserId: string;\n turns: RawEvidenceTurn[];\n outcome?: RawEvidenceOutcome | null;\n ownerAnswers?: RawEvidenceOwnerAnswer[];\n}\n\n/** The scope a mining pass is bound to — every segment must match it exactly. */\nexport interface EvidenceMiningScope {\n recipientUserId: string;\n intentId: string;\n intentFingerprint: string;\n networkId: string;\n}\n\n/**\n * The three claim shapes a hypothesis may take. The speaker constraint is\n * enforced against these: `recipient_fact` / `recipient_preference` require\n * owner-authored (or structured bilateral) support; `observation` may also be\n * supported by counterparty statements.\n */\nexport type HypothesisClaimType =\n | \"observation\"\n | \"recipient_fact\"\n | \"recipient_preference\";\n\n/** A support reference proposed by the miner (before code-side verification). */\nexport interface ProposedSupportRef {\n /** Must resolve to an {@link AllowlistedEvidence} in the pass. */\n evidenceId: string;\n /** Verbatim span the miner copied from that evidence's content. */\n span: string;\n}\n\n/** One hypothesis proposed by the miner. */\nexport interface MinedEvidenceHypothesis {\n /** Neutral, non-identifying clarification hypothesis. */\n statement: string;\n claimType: HypothesisClaimType;\n supportRefs: ProposedSupportRef[];\n}\n\n/** A support reference that resolved against the allowlist. */\nexport interface VerifiedSupportRef {\n evidenceId: string;\n kind: EvidenceKind;\n speaker: EvidenceSpeaker;\n opportunityId: string;\n}\n\n/**\n * A hypothesis after verification + the recurrence gate. Retained hypotheses\n * are returned for OFFLINE review only — shadow mode never persists or logs\n * their text (see {@link NegotiationEvidenceTelemetry}).\n */\nexport interface RetainedEvidenceHypothesis {\n statement: string;\n claimType: HypothesisClaimType;\n support: VerifiedSupportRef[];\n /** Count of DISTINCT opportunities in `support` — the recurrence measure. */\n distinctOpportunities: number;\n}\n\n/**\n * Aggregate-only telemetry. Deliberately carries NO evidence content, NO\n * hypothesis text, and NO spans — only counts — so it is safe to emit to\n * routine logs without leaking internal negotiation content.\n */\nexport interface NegotiationEvidenceTelemetry {\n recipientUserId: string;\n intentId: string;\n /** Raw segments supplied to the pass (pre-grouping). */\n segments: number;\n /** Distinct opportunities after continuation grouping. */\n distinctOpportunities: number;\n /** Allowlisted evidence unit counts, by kind. */\n evidenceCounts: Record<EvidenceKind, number>;\n /** Records dropped by allowlist / exclusion / provenance mismatch. */\n excludedRecords: number;\n hypothesesMined: number;\n /** Hypotheses whose every support ref verified against the allowlist. */\n hypothesesSupported: number;\n /** Supported hypotheses that also met the distinct-opportunity floor. */\n hypothesesRecurrent: number;\n /** Hypotheses discarded (unsupported ref, speaker violation, or too rare). */\n hypothesesDiscarded: number;\n}\n\n/** Result of one shadow mining pass. */\nexport interface NegotiationEvidenceShadowResult {\n /** Safe-to-log aggregate counts. */\n telemetry: NegotiationEvidenceTelemetry;\n /**\n * Retained recurrent hypotheses for offline eval. In shadow mode the caller\n * MUST NOT persist these or write them to routine logs.\n */\n hypotheses: RetainedEvidenceHypothesis[];\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lens C support-reference verification + recurrence gate (IND-433).
|
|
3
|
+
*
|
|
4
|
+
* A mined hypothesis is retained ONLY when:
|
|
5
|
+
* 1. it carries at least one support reference,
|
|
6
|
+
* 2. EVERY support reference resolves to an allowlisted evidence unit in
|
|
7
|
+
* this pass AND quotes a verbatim span of that unit's content,
|
|
8
|
+
* 3. the speaker constraint holds — a claim that is a fact or preference
|
|
9
|
+
* ABOUT the recipient may never rest on a counterparty statement, and
|
|
10
|
+
* 4. its verified support spans at least `minDistinctOpportunities` DISTINCT
|
|
11
|
+
* opportunities (recurrence). Continuations were already grouped upstream,
|
|
12
|
+
* so same-pair repetition cannot inflate this.
|
|
13
|
+
*
|
|
14
|
+
* Any failure discards the whole hypothesis — there is no partial retention.
|
|
15
|
+
*/
|
|
16
|
+
import type { AllowlistedEvidence, MinedEvidenceHypothesis, RetainedEvidenceHypothesis } from "./negotiation-evidence.types.js";
|
|
17
|
+
/** Result of verifying a batch of mined hypotheses. */
|
|
18
|
+
export interface VerificationResult {
|
|
19
|
+
/** Hypotheses that passed verification AND the recurrence gate. */
|
|
20
|
+
retained: RetainedEvidenceHypothesis[];
|
|
21
|
+
/** Hypotheses whose every support ref verified (pre-recurrence). */
|
|
22
|
+
supported: number;
|
|
23
|
+
/** Supported hypotheses that also met the distinct-opportunity floor. */
|
|
24
|
+
recurrent: number;
|
|
25
|
+
/** Hypotheses discarded for any reason (mined − recurrent). */
|
|
26
|
+
discarded: number;
|
|
27
|
+
}
|
|
28
|
+
/** True when `span` is a meaningful verbatim substring of `content`. */
|
|
29
|
+
export declare function evidenceSpanMatches(content: string, span: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Verify + recurrence-gate a batch of mined hypotheses against the allowlisted
|
|
32
|
+
* evidence produced for the same pass.
|
|
33
|
+
*/
|
|
34
|
+
export declare function verifyHypotheses(hypotheses: MinedEvidenceHypothesis[], evidence: AllowlistedEvidence[], minDistinctOpportunities: number): VerificationResult;
|
|
35
|
+
//# sourceMappingURL=negotiation-evidence.verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiation-evidence.verifier.d.ts","sourceRoot":"/","sources":["opportunity/negotiation-evidence/negotiation-evidence.verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAuB,uBAAuB,EAAE,0BAA0B,EAAsB,MAAM,iCAAiC,CAAC;AAEzK,uDAAuD;AACvD,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,QAAQ,EAAE,0BAA0B,EAAE,CAAC;IACvC,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;CACnB;AAwBD,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAI1E;AAqCD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,uBAAuB,EAAE,EACrC,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,wBAAwB,EAAE,MAAM,GAC/B,kBAAkB,CA6BpB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Minimum normalized span length that counts as meaningful verbatim evidence. */
|
|
2
|
+
const MIN_SPAN_CHARS = 8;
|
|
3
|
+
/** Lowercase, fold typographic punctuation, collapse whitespace. */
|
|
4
|
+
function normalizeForMatch(s) {
|
|
5
|
+
return s
|
|
6
|
+
.toLowerCase()
|
|
7
|
+
.replace(/[\u2018\u2019\u02bc]/g, "'")
|
|
8
|
+
.replace(/[\u201c\u201d]/g, '"')
|
|
9
|
+
.replace(/[\u2013\u2014]/g, "-")
|
|
10
|
+
.replace(/\u2026/g, "...")
|
|
11
|
+
.replace(/\s+/g, " ")
|
|
12
|
+
.trim();
|
|
13
|
+
}
|
|
14
|
+
/** Strip wrapping quotes / edge punctuation the LLM habitually adds. */
|
|
15
|
+
function stripEdgePunctuation(s) {
|
|
16
|
+
return s
|
|
17
|
+
.replace(/^[\s"'.,;:!?()\u2018\u2019\u201c\u201d]+/, "")
|
|
18
|
+
.replace(/[\s"'.,;:!?()\u2018\u2019\u201c\u201d]+$/, "");
|
|
19
|
+
}
|
|
20
|
+
/** True when `span` is a meaningful verbatim substring of `content`. */
|
|
21
|
+
export function evidenceSpanMatches(content, span) {
|
|
22
|
+
const haystack = normalizeForMatch(content);
|
|
23
|
+
const needle = normalizeForMatch(stripEdgePunctuation(span));
|
|
24
|
+
return needle.length >= MIN_SPAN_CHARS && haystack.includes(needle);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A `recipient_fact` / `recipient_preference` claim must not lean on a
|
|
28
|
+
* counterparty statement. `observation` claims accept any speaker.
|
|
29
|
+
*/
|
|
30
|
+
function speakerAllowedForClaim(claimType, evidence) {
|
|
31
|
+
if (claimType === "observation")
|
|
32
|
+
return true;
|
|
33
|
+
return evidence.speaker !== "counterparty";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Verify one hypothesis. Returns the verified support (deduped) when every
|
|
37
|
+
* reference resolves and satisfies the speaker constraint; otherwise null.
|
|
38
|
+
*/
|
|
39
|
+
function verifyHypothesis(hypothesis, byId) {
|
|
40
|
+
if (hypothesis.supportRefs.length === 0)
|
|
41
|
+
return null;
|
|
42
|
+
const verified = new Map();
|
|
43
|
+
for (const ref of hypothesis.supportRefs) {
|
|
44
|
+
const evidence = byId.get(ref.evidenceId);
|
|
45
|
+
if (!evidence)
|
|
46
|
+
return null; // reference to non-allowlisted / hallucinated id
|
|
47
|
+
if (!speakerAllowedForClaim(hypothesis.claimType, evidence))
|
|
48
|
+
return null;
|
|
49
|
+
if (!evidenceSpanMatches(evidence.content, ref.span))
|
|
50
|
+
return null;
|
|
51
|
+
verified.set(evidence.evidenceId, {
|
|
52
|
+
evidenceId: evidence.evidenceId,
|
|
53
|
+
kind: evidence.kind,
|
|
54
|
+
speaker: evidence.speaker,
|
|
55
|
+
opportunityId: evidence.opportunityId,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return [...verified.values()];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Verify + recurrence-gate a batch of mined hypotheses against the allowlisted
|
|
62
|
+
* evidence produced for the same pass.
|
|
63
|
+
*/
|
|
64
|
+
export function verifyHypotheses(hypotheses, evidence, minDistinctOpportunities) {
|
|
65
|
+
const byId = new Map(evidence.map((e) => [e.evidenceId, e]));
|
|
66
|
+
const retained = [];
|
|
67
|
+
let supported = 0;
|
|
68
|
+
let recurrent = 0;
|
|
69
|
+
for (const hypothesis of hypotheses) {
|
|
70
|
+
const support = verifyHypothesis(hypothesis, byId);
|
|
71
|
+
if (!support)
|
|
72
|
+
continue;
|
|
73
|
+
supported += 1;
|
|
74
|
+
const distinctOpportunities = new Set(support.map((s) => s.opportunityId)).size;
|
|
75
|
+
if (distinctOpportunities < minDistinctOpportunities)
|
|
76
|
+
continue;
|
|
77
|
+
recurrent += 1;
|
|
78
|
+
retained.push({
|
|
79
|
+
statement: hypothesis.statement,
|
|
80
|
+
claimType: hypothesis.claimType,
|
|
81
|
+
support,
|
|
82
|
+
distinctOpportunities,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
retained,
|
|
87
|
+
supported,
|
|
88
|
+
recurrent,
|
|
89
|
+
discarded: hypotheses.length - recurrent,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=negotiation-evidence.verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiation-evidence.verifier.js","sourceRoot":"/","sources":["opportunity/negotiation-evidence/negotiation-evidence.verifier.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Lens C support-reference verification + recurrence gate (IND-433).\n *\n * A mined hypothesis is retained ONLY when:\n * 1. it carries at least one support reference,\n * 2. EVERY support reference resolves to an allowlisted evidence unit in\n * this pass AND quotes a verbatim span of that unit's content,\n * 3. the speaker constraint holds — a claim that is a fact or preference\n * ABOUT the recipient may never rest on a counterparty statement, and\n * 4. its verified support spans at least `minDistinctOpportunities` DISTINCT\n * opportunities (recurrence). Continuations were already grouped upstream,\n * so same-pair repetition cannot inflate this.\n *\n * Any failure discards the whole hypothesis — there is no partial retention.\n */\nimport type { AllowlistedEvidence, HypothesisClaimType, MinedEvidenceHypothesis, RetainedEvidenceHypothesis, VerifiedSupportRef } from \"./negotiation-evidence.types.js\";\n\n/** Result of verifying a batch of mined hypotheses. */\nexport interface VerificationResult {\n /** Hypotheses that passed verification AND the recurrence gate. */\n retained: RetainedEvidenceHypothesis[];\n /** Hypotheses whose every support ref verified (pre-recurrence). */\n supported: number;\n /** Supported hypotheses that also met the distinct-opportunity floor. */\n recurrent: number;\n /** Hypotheses discarded for any reason (mined − recurrent). */\n discarded: number;\n}\n\n/** Minimum normalized span length that counts as meaningful verbatim evidence. */\nconst MIN_SPAN_CHARS = 8;\n\n/** Lowercase, fold typographic punctuation, collapse whitespace. */\nfunction normalizeForMatch(s: string): string {\n return s\n .toLowerCase()\n .replace(/[\\u2018\\u2019\\u02bc]/g, \"'\")\n .replace(/[\\u201c\\u201d]/g, '\"')\n .replace(/[\\u2013\\u2014]/g, \"-\")\n .replace(/\\u2026/g, \"...\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** Strip wrapping quotes / edge punctuation the LLM habitually adds. */\nfunction stripEdgePunctuation(s: string): string {\n return s\n .replace(/^[\\s\"'.,;:!?()\\u2018\\u2019\\u201c\\u201d]+/, \"\")\n .replace(/[\\s\"'.,;:!?()\\u2018\\u2019\\u201c\\u201d]+$/, \"\");\n}\n\n/** True when `span` is a meaningful verbatim substring of `content`. */\nexport function evidenceSpanMatches(content: string, span: string): boolean {\n const haystack = normalizeForMatch(content);\n const needle = normalizeForMatch(stripEdgePunctuation(span));\n return needle.length >= MIN_SPAN_CHARS && haystack.includes(needle);\n}\n\n/**\n * A `recipient_fact` / `recipient_preference` claim must not lean on a\n * counterparty statement. `observation` claims accept any speaker.\n */\nfunction speakerAllowedForClaim(claimType: HypothesisClaimType, evidence: AllowlistedEvidence): boolean {\n if (claimType === \"observation\") return true;\n return evidence.speaker !== \"counterparty\";\n}\n\n/**\n * Verify one hypothesis. Returns the verified support (deduped) when every\n * reference resolves and satisfies the speaker constraint; otherwise null.\n */\nfunction verifyHypothesis(\n hypothesis: MinedEvidenceHypothesis,\n byId: Map<string, AllowlistedEvidence>,\n): VerifiedSupportRef[] | null {\n if (hypothesis.supportRefs.length === 0) return null;\n\n const verified = new Map<string, VerifiedSupportRef>();\n for (const ref of hypothesis.supportRefs) {\n const evidence = byId.get(ref.evidenceId);\n if (!evidence) return null; // reference to non-allowlisted / hallucinated id\n if (!speakerAllowedForClaim(hypothesis.claimType, evidence)) return null;\n if (!evidenceSpanMatches(evidence.content, ref.span)) return null;\n verified.set(evidence.evidenceId, {\n evidenceId: evidence.evidenceId,\n kind: evidence.kind,\n speaker: evidence.speaker,\n opportunityId: evidence.opportunityId,\n });\n }\n return [...verified.values()];\n}\n\n/**\n * Verify + recurrence-gate a batch of mined hypotheses against the allowlisted\n * evidence produced for the same pass.\n */\nexport function verifyHypotheses(\n hypotheses: MinedEvidenceHypothesis[],\n evidence: AllowlistedEvidence[],\n minDistinctOpportunities: number,\n): VerificationResult {\n const byId = new Map(evidence.map((e) => [e.evidenceId, e]));\n const retained: RetainedEvidenceHypothesis[] = [];\n let supported = 0;\n let recurrent = 0;\n\n for (const hypothesis of hypotheses) {\n const support = verifyHypothesis(hypothesis, byId);\n if (!support) continue;\n supported += 1;\n\n const distinctOpportunities = new Set(support.map((s) => s.opportunityId)).size;\n if (distinctOpportunities < minDistinctOpportunities) continue;\n recurrent += 1;\n\n retained.push({\n statement: hypothesis.statement,\n claimType: hypothesis.claimType,\n support,\n distinctOpportunities,\n });\n }\n\n return {\n retained,\n supported,\n recurrent,\n discarded: hypotheses.length - recurrent,\n };\n}\n"]}
|
|
@@ -42,8 +42,15 @@ export type OpportunityEvaluatorLike = {
|
|
|
42
42
|
};
|
|
43
43
|
import type { Embedder } from '../shared/interfaces/embedder.interface.js';
|
|
44
44
|
import type { CreateOpportunityData, Opportunity } from '../shared/interfaces/database.interface.js';
|
|
45
|
-
import type { NegotiationGraphLike } from "../negotiation/negotiation.state.js";
|
|
45
|
+
import type { NegotiationGraphLike, UserNegotiationContext } from "../negotiation/negotiation.state.js";
|
|
46
46
|
import type { AgentDispatcher } from "../shared/interfaces/agent-dispatcher.interface.js";
|
|
47
|
+
interface NegotiationIntentSource {
|
|
48
|
+
id?: string | null;
|
|
49
|
+
summary?: string | null;
|
|
50
|
+
payload?: string | null;
|
|
51
|
+
}
|
|
52
|
+
/** Put an opportunity actor's exact intent first, then fill the bounded context without duplicates. */
|
|
53
|
+
export declare function buildPrioritizedNegotiationIntents(activeIntents: readonly NegotiationIntentSource[], exactIntentId?: string | null, fallbackIntent?: NegotiationIntentSource | null): UserNegotiationContext['intents'];
|
|
47
54
|
/** Input shape for the HyDE graph invoke call (query-based embedding). */
|
|
48
55
|
export interface HydeGeneratorInvokeInput {
|
|
49
56
|
sourceType: 'query';
|
|
@@ -1299,4 +1306,5 @@ export declare class OpportunityGraphFactory {
|
|
|
1299
1306
|
};
|
|
1300
1307
|
}, unknown, unknown, []>;
|
|
1301
1308
|
}
|
|
1309
|
+
export {};
|
|
1302
1310
|
//# sourceMappingURL=opportunity.graph.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opportunity.graph.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,4CAA4C,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAyB,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAExO,OAAO,EAAwB,KAAK,gBAAgB,EAAuC,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACzK,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAS3F,yDAAyD;AACzD,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,CAAC,EAAE,CACP,oBAAoB,EAAE,MAAM,EAC5B,UAAU,EAAE,gBAAgB,EAAE,EAC9B,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAC3B,OAAO,CAAC,KAAK,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;KAC3C,CAAC,CAAC,CAAC;IACJ,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,KAAK,CAAC;QAC5F,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAC,CAAC;KAC9H,CAAC,CAAC,CAAC;CACL,CAAC;AACF,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,4CAA4C,CAAC;AAC1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAiE,MAAM,4CAA4C,CAAC;AAMpK,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"opportunity.graph.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,6 +53,37 @@ const negotiateExistingLog = protocolLogger('OpportunityGraph:NegotiateExisting'
|
|
|
53
53
|
const routingLog = protocolLogger('OpportunityGraph:Routing');
|
|
54
54
|
/** 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). */
|
|
55
55
|
const DEDUP_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
|
|
56
|
+
const NEGOTIATION_INTENT_LIMIT = 5;
|
|
57
|
+
/** Put an opportunity actor's exact intent first, then fill the bounded context without duplicates. */
|
|
58
|
+
export function buildPrioritizedNegotiationIntents(activeIntents, exactIntentId, fallbackIntent) {
|
|
59
|
+
const exactId = typeof exactIntentId === 'string' && exactIntentId.trim().length > 0
|
|
60
|
+
? exactIntentId
|
|
61
|
+
: null;
|
|
62
|
+
const exactActive = exactId
|
|
63
|
+
? activeIntents.find((intent) => intent.id === exactId)
|
|
64
|
+
: undefined;
|
|
65
|
+
const ordered = [
|
|
66
|
+
...(exactActive ? [exactActive] : []),
|
|
67
|
+
...(!exactActive && fallbackIntent?.id === exactId ? [fallbackIntent] : []),
|
|
68
|
+
...activeIntents,
|
|
69
|
+
];
|
|
70
|
+
const seen = new Set();
|
|
71
|
+
const intents = [];
|
|
72
|
+
for (const intent of ordered) {
|
|
73
|
+
if (typeof intent.id !== 'string' || intent.id.trim().length === 0 || seen.has(intent.id))
|
|
74
|
+
continue;
|
|
75
|
+
seen.add(intent.id);
|
|
76
|
+
intents.push({
|
|
77
|
+
id: intent.id,
|
|
78
|
+
title: intent.summary ?? '',
|
|
79
|
+
description: intent.payload ?? '',
|
|
80
|
+
confidence: 1,
|
|
81
|
+
});
|
|
82
|
+
if (intents.length === NEGOTIATION_INTENT_LIMIT)
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
return intents;
|
|
86
|
+
}
|
|
56
87
|
/** Default cap for source premises used by premise-to-premise discovery. Prevents BACKEND-5-style fan-out. */
|
|
57
88
|
const DEFAULT_SOURCE_PREMISE_DISCOVERY_LIMIT = 40;
|
|
58
89
|
function networkMembershipPairKey(userId, networkId) {
|
|
@@ -1801,14 +1832,21 @@ export class OpportunityGraphFactory {
|
|
|
1801
1832
|
// Use the same discoveryUserId pattern as evaluationNode
|
|
1802
1833
|
const discoveryUserId = (state.onBehalfOfUserId ?? state.userId);
|
|
1803
1834
|
const sourceAccount = await this.database.getUser(discoveryUserId).catch(() => null);
|
|
1835
|
+
const sourceIntentInputs = (state.indexedIntents ?? []).map((intent) => ({
|
|
1836
|
+
id: intent.intentId,
|
|
1837
|
+
summary: intent.summary ?? null,
|
|
1838
|
+
payload: intent.payload ?? null,
|
|
1839
|
+
}));
|
|
1840
|
+
const sourceHasExactIntent = sourceIntentInputs.some((intent) => intent.id === state.triggerIntentId);
|
|
1841
|
+
const sourceFallbackIntent = state.triggerIntentId && !sourceHasExactIntent
|
|
1842
|
+
? await this.database.getIntent(state.triggerIntentId).catch(() => null)
|
|
1843
|
+
: null;
|
|
1844
|
+
const ownedSourceFallback = sourceFallbackIntent?.userId === discoveryUserId
|
|
1845
|
+
? sourceFallbackIntent
|
|
1846
|
+
: null;
|
|
1804
1847
|
const sourceUser = {
|
|
1805
1848
|
id: discoveryUserId,
|
|
1806
|
-
intents: state.
|
|
1807
|
-
id: i.intentId,
|
|
1808
|
-
title: i.summary ?? '',
|
|
1809
|
-
description: i.payload ?? '',
|
|
1810
|
-
confidence: 1,
|
|
1811
|
-
})) ?? [],
|
|
1849
|
+
intents: buildPrioritizedNegotiationIntents(sourceIntentInputs, state.triggerIntentId, ownedSourceFallback),
|
|
1812
1850
|
profile: {
|
|
1813
1851
|
name: state.sourceProfile?.identity?.name ?? sourceAccount?.name,
|
|
1814
1852
|
bio: state.sourceProfile?.identity?.bio ?? sourceAccount?.intro ?? undefined,
|
|
@@ -1834,8 +1872,7 @@ export class OpportunityGraphFactory {
|
|
|
1834
1872
|
});
|
|
1835
1873
|
return null;
|
|
1836
1874
|
}
|
|
1837
|
-
const candidateActor = opp.actors
|
|
1838
|
-
.find(a => a.userId !== discoveryUserId);
|
|
1875
|
+
const candidateActor = opp.actors.find(a => a.userId !== discoveryUserId);
|
|
1839
1876
|
if (!candidateActor) {
|
|
1840
1877
|
negotiateLog.verbose('Skipping opportunity: no candidateActor found', {
|
|
1841
1878
|
opportunityId: opp.id,
|
|
@@ -1853,27 +1890,17 @@ export class OpportunityGraphFactory {
|
|
|
1853
1890
|
});
|
|
1854
1891
|
const candidates = await Promise.all(candidateEntries.map(async ({ opp, candidateActor }) => {
|
|
1855
1892
|
const userId = candidateActor.userId;
|
|
1893
|
+
const candidateIntentId = candidateActor.intentId ?? candidateActor.intent;
|
|
1856
1894
|
const [profile, user, activeIntents, intent] = await Promise.all([
|
|
1857
1895
|
this.database.getProfile(userId).catch(() => null),
|
|
1858
1896
|
this.database.getUser(userId).catch(() => null),
|
|
1859
1897
|
this.database.getActiveIntents(userId).catch(() => []),
|
|
1860
|
-
|
|
1861
|
-
? this.database.getIntent(
|
|
1898
|
+
candidateIntentId
|
|
1899
|
+
? this.database.getIntent(candidateIntentId).catch(() => null)
|
|
1862
1900
|
: null,
|
|
1863
1901
|
]);
|
|
1864
|
-
const
|
|
1865
|
-
|
|
1866
|
-
title: ai.summary ?? '',
|
|
1867
|
-
description: ai.payload ?? '',
|
|
1868
|
-
confidence: 1,
|
|
1869
|
-
});
|
|
1870
|
-
const triggerInActive = activeIntents.some(ai => ai.id === candidateActor.intentId);
|
|
1871
|
-
const triggerFallback = !triggerInActive && intent ? [toNegIntent(intent)] : [];
|
|
1872
|
-
const candidateIntents = [
|
|
1873
|
-
...triggerFallback,
|
|
1874
|
-
...activeIntents.filter(ai => ai.id === candidateActor.intentId).map(toNegIntent),
|
|
1875
|
-
...activeIntents.filter(ai => ai.id !== candidateActor.intentId).map(toNegIntent),
|
|
1876
|
-
].slice(0, 5);
|
|
1902
|
+
const ownedFallbackIntent = intent?.userId === userId ? intent : null;
|
|
1903
|
+
const candidateIntents = buildPrioritizedNegotiationIntents(activeIntents, candidateIntentId, ownedFallbackIntent);
|
|
1877
1904
|
return {
|
|
1878
1905
|
userId,
|
|
1879
1906
|
opportunityId: opp.id,
|
|
@@ -3385,6 +3412,8 @@ export class OpportunityGraphFactory {
|
|
|
3385
3412
|
negotiateExistingLog.warn('No candidate actor found', { opportunityId: state.opportunityId });
|
|
3386
3413
|
return {};
|
|
3387
3414
|
}
|
|
3415
|
+
const sourceIntentId = sourceActor.intentId ?? sourceActor.intent;
|
|
3416
|
+
const candidateIntentId = candidateActor.intentId ?? candidateActor.intent;
|
|
3388
3417
|
// Load user data for both actors in parallel
|
|
3389
3418
|
const [sourceUserAccount, sourceProfile, sourceIntents, candidateAccount, candidateProfile, candidateIntents] = await Promise.all([
|
|
3390
3419
|
this.database.getUser(sourceActor.userId).catch(() => null),
|
|
@@ -3394,22 +3423,26 @@ export class OpportunityGraphFactory {
|
|
|
3394
3423
|
this.database.getProfile(candidateActor.userId).catch(() => null),
|
|
3395
3424
|
this.database.getActiveIntents(candidateActor.userId).catch(() => []),
|
|
3396
3425
|
]);
|
|
3397
|
-
const
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3426
|
+
const sourceHasExactIntent = sourceIntents.some((intent) => intent.id === sourceIntentId);
|
|
3427
|
+
const candidateHasExactIntent = candidateIntents.some((intent) => intent.id === candidateIntentId);
|
|
3428
|
+
const [sourceFallbackIntent, candidateFallbackIntent] = await Promise.all([
|
|
3429
|
+
sourceIntentId && !sourceHasExactIntent
|
|
3430
|
+
? this.database.getIntent(sourceIntentId).catch(() => null)
|
|
3431
|
+
: null,
|
|
3432
|
+
candidateIntentId && !candidateHasExactIntent
|
|
3433
|
+
? this.database.getIntent(candidateIntentId).catch(() => null)
|
|
3434
|
+
: null,
|
|
3435
|
+
]);
|
|
3403
3436
|
const sourceUser = {
|
|
3404
3437
|
id: sourceActor.userId,
|
|
3405
|
-
intents: sourceIntents
|
|
3438
|
+
intents: buildPrioritizedNegotiationIntents(sourceIntents, sourceIntentId, sourceFallbackIntent?.userId === sourceActor.userId ? sourceFallbackIntent : null),
|
|
3406
3439
|
profile: {
|
|
3407
3440
|
name: sourceProfile?.identity?.name ?? sourceUserAccount?.name,
|
|
3408
3441
|
bio: sourceProfile?.identity?.bio ?? sourceUserAccount?.intro ?? undefined,
|
|
3409
3442
|
location: sourceProfile?.identity?.location ?? sourceUserAccount?.location ?? undefined,
|
|
3410
3443
|
},
|
|
3411
3444
|
};
|
|
3412
|
-
const candidateIntentsForNeg = candidateIntents
|
|
3445
|
+
const candidateIntentsForNeg = buildPrioritizedNegotiationIntents(candidateIntents, candidateIntentId, candidateFallbackIntent?.userId === candidateActor.userId ? candidateFallbackIntent : null);
|
|
3413
3446
|
const candidate = {
|
|
3414
3447
|
userId: candidateActor.userId,
|
|
3415
3448
|
opportunityId: opp.id,
|