@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,23 @@
1
+ /**
2
+ * Negotiation graph, stage 2: the outreach gate.
3
+ */
4
+ import { type ScreenDecisionRecord } from "./negotiation.screen.js";
5
+ import type { NegotiationGraphDeps, NegotiationState } from "./negotiation.graph.shared.js";
6
+ /**
7
+ * Screen node (P2.1) — the outreach gate. Runs between init and the first
8
+ * turn on FRESH negotiations only (routing skips it on continuations and
9
+ * when NEGOTIATION_SCREEN_MODE=off). The reaching client's negotiator
10
+ * decides whether the match is worth its client's name; in shadow mode the
11
+ * decision is recorded (task metadata + trace event + log line) but never
12
+ * blocks — the negotiation always proceeds to the first turn. In enforce
13
+ * mode (P2.2) a `pass` routes straight to finalize: zero turns, zero
14
+ * counterparty involvement, outcome `reason: "screened_out"`, opportunity
15
+ * quietly `rejected` (init had already flipped it to `negotiating`).
16
+ * A failed screen still fails OPEN in every mode.
17
+ */
18
+ export declare function screenNode(state: NegotiationState, deps: NegotiationGraphDeps): Promise<{
19
+ screenDecision: ScreenDecisionRecord;
20
+ memoryBySide: {
21
+ [x: string]: import("../index.js").NegotiatorMemoryEntry[];
22
+ };
23
+ }>;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Negotiation graph, stage 2: the outreach gate.
3
+ */
4
+ import { requestContext } from "../../shared/observability/request-context.js";
5
+ import { configuredScreenMode } from "../domain/negotiation.screen.contracts.js";
6
+ import { buildAttributedDialogue, memoryQueryText, retrieveMemory, screenNodeLog, turnsFromMessages } from "./negotiation.graph.shared.js";
7
+ /**
8
+ * Screen node (P2.1) — the outreach gate. Runs between init and the first
9
+ * turn on FRESH negotiations only (routing skips it on continuations and
10
+ * when NEGOTIATION_SCREEN_MODE=off). The reaching client's negotiator
11
+ * decides whether the match is worth its client's name; in shadow mode the
12
+ * decision is recorded (task metadata + trace event + log line) but never
13
+ * blocks — the negotiation always proceeds to the first turn. In enforce
14
+ * mode (P2.2) a `pass` routes straight to finalize: zero turns, zero
15
+ * counterparty involvement, outcome `reason: "screened_out"`, opportunity
16
+ * quietly `rejected` (init had already flipped it to `negotiating`).
17
+ * A failed screen still fails OPEN in every mode.
18
+ */
19
+ export async function screenNode(state, deps) {
20
+ const traceEmitter = requestContext.getStore()?.traceEmitter;
21
+ const emitWide = (event) => traceEmitter?.(event);
22
+ const mode = configuredScreenMode();
23
+ const start = Date.now();
24
+ // The client is the initiator seat's user — the side whose negotiator is
25
+ // reaching out. Fresh runs stamp initiatorUserId in init; fall back to
26
+ // sourceUser (what the stamp defaults to anyway).
27
+ const initiatorId = state.initiatorUserId ?? state.sourceUser.id;
28
+ const clientIsSource = initiatorId !== state.candidateUser.id;
29
+ const clientUser = clientIsSource ? state.sourceUser : state.candidateUser;
30
+ const counterpartyUser = clientIsSource ? state.candidateUser : state.sourceUser;
31
+ // P5.3: the client's own negotiator memory informs the outreach gate.
32
+ // Cached into state so the client's first turn reuses it.
33
+ const clientSide = clientIsSource ? "source" : "candidate";
34
+ const clientMemory = state.memoryBySide?.[clientSide]
35
+ ?? (deps.memoryRetrieve
36
+ ? await retrieveMemory(deps, clientUser.id, counterpartyUser.id, memoryQueryText(state, counterpartyUser), "screen")
37
+ : []);
38
+ let decision;
39
+ let failedOpen = false;
40
+ let screenError;
41
+ try {
42
+ const counterpartyContext = (await deps.database.getUserContext(counterpartyUser.id, null).catch(() => null))?.text ?? "";
43
+ const priorDialogueAttributed = buildAttributedDialogue(state);
44
+ decision = await deps.screener.invoke({
45
+ clientUser,
46
+ counterpartyUser,
47
+ ...(counterpartyContext && { counterpartyContext }),
48
+ ...(clientMemory.length > 0 && { memory: clientMemory }),
49
+ // discoveryQuery belongs to the discovery session's source user; only
50
+ // meaningful for the client when the client holds the source side.
51
+ ...(clientIsSource && state.discoveryQuery && { discoveryQuery: state.discoveryQuery }),
52
+ seedAssessment: state.seedAssessment,
53
+ indexContext: state.indexContext,
54
+ isContinuation: state.isContinuation,
55
+ ...(state.messages.length > 0 && { priorDialogue: turnsFromMessages(state.messages) }),
56
+ ...(priorDialogueAttributed && { priorDialogueAttributed }),
57
+ });
58
+ }
59
+ catch (err) {
60
+ // Fail open: a screen failure must never block a negotiation.
61
+ failedOpen = true;
62
+ screenError = err instanceof Error ? err.message : String(err);
63
+ screenNodeLog.warn("Screen failed; proceeding open (reach_out)", {
64
+ taskId: state.taskId,
65
+ opportunityId: state.opportunityId || undefined,
66
+ error: screenError,
67
+ });
68
+ decision = {
69
+ decision: "reach_out",
70
+ reasoning: `screen_error: ${screenError}`,
71
+ evidence: { counterpartyPremiseFit: "", intentAlignment: "" },
72
+ };
73
+ }
74
+ const durationMs = Date.now() - start;
75
+ const record = {
76
+ ...decision,
77
+ mode,
78
+ ...(failedOpen && { failedOpen, error: screenError }),
79
+ screenedAt: new Date().toISOString(),
80
+ durationMs,
81
+ };
82
+ await deps.database.setTaskScreenDecision?.(state.taskId, record, state.continuationExecution).catch((err) => {
83
+ screenNodeLog.error("Failed to persist screen decision", { taskId: state.taskId, error: err });
84
+ });
85
+ screenNodeLog.info("negotiation_screen", {
86
+ taskId: state.taskId,
87
+ opportunityId: state.opportunityId || undefined,
88
+ decision: decision.decision,
89
+ mode,
90
+ failedOpen,
91
+ durationMs,
92
+ });
93
+ if (state.opportunityId) {
94
+ emitWide({
95
+ type: "negotiation_screen",
96
+ opportunityId: state.opportunityId,
97
+ negotiationConversationId: state.conversationId,
98
+ decision: decision.decision,
99
+ reasoning: decision.reasoning,
100
+ mode,
101
+ failedOpen,
102
+ durationMs,
103
+ });
104
+ }
105
+ // Routing happens on the conditional edge: shadow always proceeds to
106
+ // the first turn; enforce routes a (non-failed-open) pass to finalize.
107
+ return { screenDecision: record, memoryBySide: { [clientSide]: clientMemory } };
108
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Shared vocabulary for the negotiation graph's nodes.
3
+ *
4
+ * The nodes were closures inside `NegotiationGraphFactory.createGraph()`,
5
+ * capturing the injected database, dispatcher and queues. They are top-level
6
+ * functions now, each taking an explicit {@link NegotiationGraphDeps}; this
7
+ * module owns the bag itself and the helpers more than one node needs.
8
+ */
9
+ import type { NegotiationGraphDatabase } from "../../shared/interfaces/database.interface.js";
10
+ import type { NegotiationTimeoutQueue } from "../../shared/interfaces/negotiation-events.interface.js";
11
+ import type { AgentDispatcher } from "../../shared/interfaces/agent-dispatcher.interface.js";
12
+ import { NegotiationGraphState, type NegotiationTurn, type UserNegotiationContext } from "../domain/negotiation.state.js";
13
+ import { IndexNegotiator } from "./negotiation.agent.js";
14
+ import { NegotiationScreener } from "./negotiation.screen.js";
15
+ import type { QuestionerEnqueueFn } from "../../questions/index.js";
16
+ import type { ReflectEnqueueFn } from "./negotiation.reflect.js";
17
+ import type { NegotiatorMemoryEntry, NegotiatorMemoryRetrieveFn, NegotiatorMemoryScope } from "../domain/negotiation.memory.js";
18
+ import { type AttributedPriorDialogue, type TaskAttribution } from '../negotiation.attribution.js';
19
+ /** The graph's channel state, as every node sees it. */
20
+ export type NegotiationState = typeof NegotiationGraphState.State;
21
+ /** Everything the negotiation nodes reach for. Composed once by the factory. */
22
+ export interface NegotiationGraphDeps {
23
+ database: NegotiationGraphDatabase;
24
+ dispatcher: AgentDispatcher;
25
+ timeoutQueue?: NegotiationTimeoutQueue;
26
+ questionerEnqueue?: QuestionerEnqueueFn;
27
+ reflectEnqueue?: ReflectEnqueueFn;
28
+ memoryRetrieve?: NegotiatorMemoryRetrieveFn;
29
+ /** In-process negotiator used when no personal agent answers. */
30
+ systemAgent: IndexNegotiator;
31
+ /** Outreach gate for fresh negotiations. */
32
+ screener: NegotiationScreener;
33
+ }
34
+ export declare const logger: import("../../shared/observability/log.js").LoggerWithSource;
35
+ export declare const initLog: import("../../shared/observability/log.js").LoggerWithSource;
36
+ export declare const screenNodeLog: import("../../shared/observability/log.js").LoggerWithSource;
37
+ export declare const turnLog: import("../../shared/observability/log.js").LoggerWithSource;
38
+ export declare const finalizeLog: import("../../shared/observability/log.js").LoggerWithSource;
39
+ export declare const negotiateCandidatesLog: import("../../shared/observability/log.js").LoggerWithSource;
40
+ /** Extracts the ordered NegotiationTurn list from A2A message data parts. */
41
+ export declare function turnsFromMessages(messages: Array<{
42
+ parts: unknown[];
43
+ }>): NegotiationTurn[];
44
+ /**
45
+ * Whether `userId`'s side has already spent its one `ask_user` client
46
+ * consultation in this conversation (P3.2 rationing: max one per negotiation
47
+ * per side, checked against the full message history so continuations count
48
+ * prior sessions' consultations too).
49
+ */
50
+ export declare function hasPriorAskUser(messages: Array<{
51
+ senderId: string;
52
+ parts: unknown[];
53
+ }>, userId: string): boolean;
54
+ /**
55
+ * P5.3 memory retrieval — never throws, never blocks a negotiation. The
56
+ * injected fn already resolves [] when NEGOTIATOR_MEMORY_INJECT is off;
57
+ * this wrapper adds the graph-side failure guard.
58
+ */
59
+ export declare function retrieveMemory(deps: NegotiationGraphDeps, userId: string, counterpartyUserId: string, queryText: string, scope: NegotiatorMemoryScope): Promise<NegotiatorMemoryEntry[]>;
60
+ /** Similarity query text: seed reasoning + counterparty context. */
61
+ export declare function memoryQueryText(state: NegotiationState, counterparty: UserNegotiationContext): string;
62
+ /**
63
+ * IND-569: resolve a prior negotiation task's attribution metadata for the
64
+ * per-opportunity prior-dialogue labels. Never throws — any failure returns
65
+ * null so the turns degrade to the unattributed block instead of leaking
66
+ * into the current opportunity's context.
67
+ */
68
+ export declare function resolveTaskAttribution(deps: NegotiationGraphDeps, taskId: string): Promise<TaskAttribution | null>;
69
+ /**
70
+ * IND-569: build the attributed prior dialogue passed to the screener and
71
+ * turn prompts. Combines the immutable seeded attribution (earlier + legacy
72
+ * unattributed blocks, resolved once in init) with this session's own turns
73
+ * (task-id-matched). Null when there is no seeded attribution.
74
+ */
75
+ export declare function buildAttributedDialogue(state: NegotiationState): AttributedPriorDialogue | null;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Shared vocabulary for the negotiation graph's nodes.
3
+ *
4
+ * The nodes were closures inside `NegotiationGraphFactory.createGraph()`,
5
+ * capturing the injected database, dispatcher and queues. They are top-level
6
+ * functions now, each taking an explicit {@link NegotiationGraphDeps}; this
7
+ * module owns the bag itself and the helpers more than one node needs.
8
+ */
9
+ import { protocolLogger } from "../../shared/observability/protocol.logger.js";
10
+ import { attributedDialogueIsEmpty, combineAttributedDialogue } from '../negotiation.attribution.js';
11
+ export const logger = protocolLogger("NegotiationGraph");
12
+ export const initLog = protocolLogger("NegotiationGraph:Init");
13
+ export const screenNodeLog = protocolLogger("NegotiationGraph:Screen");
14
+ export const turnLog = protocolLogger("NegotiationGraph:Turn");
15
+ export const finalizeLog = protocolLogger("NegotiationGraph:Finalize");
16
+ export const negotiateCandidatesLog = protocolLogger("NegotiationGraph:negotiateCandidates");
17
+ /** Extracts the ordered NegotiationTurn list from A2A message data parts. */
18
+ export function turnsFromMessages(messages) {
19
+ return messages
20
+ .map((m) => {
21
+ const dataPart = m.parts.find((p) => p.kind === "data");
22
+ return dataPart?.data;
23
+ })
24
+ .filter(Boolean);
25
+ }
26
+ /**
27
+ * Whether `userId`'s side has already spent its one `ask_user` client
28
+ * consultation in this conversation (P3.2 rationing: max one per negotiation
29
+ * per side, checked against the full message history so continuations count
30
+ * prior sessions' consultations too).
31
+ */
32
+ export function hasPriorAskUser(messages, userId) {
33
+ const sender = `agent:${userId}`;
34
+ return messages.some((m) => {
35
+ if (m.senderId !== sender)
36
+ return false;
37
+ const dataPart = m.parts.find((p) => p.kind === "data");
38
+ return dataPart?.data?.action === "ask_user";
39
+ });
40
+ }
41
+ /**
42
+ * P5.3 memory retrieval — never throws, never blocks a negotiation. The
43
+ * injected fn already resolves [] when NEGOTIATOR_MEMORY_INJECT is off;
44
+ * this wrapper adds the graph-side failure guard.
45
+ */
46
+ export async function retrieveMemory(deps, userId, counterpartyUserId, queryText, scope) {
47
+ if (!deps.memoryRetrieve)
48
+ return [];
49
+ try {
50
+ return await deps.memoryRetrieve({ userId, counterpartyUserId, queryText, scope });
51
+ }
52
+ catch (err) {
53
+ logger.warn("Negotiator memory retrieval failed; proceeding without memory", {
54
+ userId,
55
+ scope,
56
+ error: err instanceof Error ? err.message : String(err),
57
+ });
58
+ return [];
59
+ }
60
+ }
61
+ /** Similarity query text: seed reasoning + counterparty context. */
62
+ export function memoryQueryText(state, counterparty) {
63
+ return [
64
+ state.discoveryQuery ? `Search: ${state.discoveryQuery}` : "",
65
+ state.seedAssessment?.reasoning ?? "",
66
+ counterparty?.profile?.name ?? "",
67
+ counterparty?.profile?.bio ?? "",
68
+ (counterparty?.intents ?? []).slice(0, 5).map((i) => `${i.title}: ${i.description}`).join("\n"),
69
+ ].filter(Boolean).join("\n");
70
+ }
71
+ /**
72
+ * IND-569: resolve a prior negotiation task's attribution metadata for the
73
+ * per-opportunity prior-dialogue labels. Never throws — any failure returns
74
+ * null so the turns degrade to the unattributed block instead of leaking
75
+ * into the current opportunity's context.
76
+ */
77
+ export async function resolveTaskAttribution(deps, taskId) {
78
+ try {
79
+ const task = await deps.database.getTask(taskId);
80
+ if (!task)
81
+ return null;
82
+ const md = (task.metadata ?? {});
83
+ const opportunityId = typeof md.opportunityId === 'string' && md.opportunityId.length > 0 ? md.opportunityId : null;
84
+ const snapshots = Array.isArray(md.intentSnapshots) ? md.intentSnapshots : [];
85
+ const sourceIntentId = typeof md.sourceIntentId === 'string' ? md.sourceIntentId : null;
86
+ const snap = snapshots.find((s) => s && s.intentId === sourceIntentId) ?? snapshots[0];
87
+ const opportunityTitle = snap && typeof snap.title === 'string' && snap.title.trim().length > 0 ? snap.title : null;
88
+ let outcome = null;
89
+ try {
90
+ const artifacts = await deps.database.getArtifactsForTask(taskId);
91
+ const outArtifact = artifacts.find((a) => a.name === 'negotiation-outcome');
92
+ if (outArtifact) {
93
+ const firstPart = Array.isArray(outArtifact.parts) ? outArtifact.parts[0] : undefined;
94
+ const data = firstPart?.data;
95
+ if (data && typeof data.hasOpportunity === 'boolean') {
96
+ outcome = data.hasOpportunity ? 'accepted' : (data.reason === 'screened_out' ? 'not pursued' : 'declined');
97
+ }
98
+ else if (typeof outArtifact.metadata?.continuationOutcome === 'string') {
99
+ outcome = outArtifact.metadata.continuationOutcome;
100
+ }
101
+ }
102
+ }
103
+ catch { /* outcome stays null; header degrades to "outcome unknown" */ }
104
+ const concludedAt = task.updatedAt instanceof Date
105
+ ? task.updatedAt.toISOString()
106
+ : (task.updatedAt ? new Date(task.updatedAt).toISOString() : null);
107
+ return { opportunityId, opportunityTitle, outcome, concludedAt };
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ /**
114
+ * IND-569: build the attributed prior dialogue passed to the screener and
115
+ * turn prompts. Combines the immutable seeded attribution (earlier + legacy
116
+ * unattributed blocks, resolved once in init) with this session's own turns
117
+ * (task-id-matched). Null when there is no seeded attribution.
118
+ */
119
+ export function buildAttributedDialogue(state) {
120
+ if (!state.isContinuation || !state.priorAttribution)
121
+ return null;
122
+ const currentSessionTurns = turnsFromMessages(state.messages.filter((m) => m.taskId === state.taskId));
123
+ const dialogue = combineAttributedDialogue(state.priorAttribution, currentSessionTurns);
124
+ return attributedDialogueIsEmpty(dialogue) ? null : dialogue;
125
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Negotiation graph, stage 3: one negotiator turn.
3
+ */
4
+ import { type DeadlockShiftRecord } from "../domain/negotiation.deadlock.js";
5
+ import type { NegotiationGraphDeps, NegotiationState } from "./negotiation.graph.shared.js";
6
+ export declare function turnNode(state: NegotiationState, deps: NegotiationGraphDeps): Promise<{
7
+ status: "waiting_for_agent";
8
+ lastTurn?: undefined;
9
+ firstTurnScreenedOut?: undefined;
10
+ turnCount?: undefined;
11
+ error?: undefined;
12
+ } | {
13
+ lastTurn: {
14
+ action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
15
+ assessment: {
16
+ reasoning: string;
17
+ suggestedRoles: {
18
+ ownUser: "agent" | "patient" | "peer";
19
+ otherUser: "agent" | "patient" | "peer";
20
+ };
21
+ };
22
+ message?: string | null | undefined;
23
+ askUser?: {
24
+ reason: "unresolved_owner_constraint" | "consequential_disclosure_permission" | "repeated_non_convergence" | "insufficient_commitment_authority";
25
+ } | null | undefined;
26
+ };
27
+ firstTurnScreenedOut: boolean;
28
+ status?: undefined;
29
+ turnCount?: undefined;
30
+ error?: undefined;
31
+ } | {
32
+ deadlockShift?: DeadlockShiftRecord | undefined;
33
+ messages: {
34
+ id: string;
35
+ senderId: string;
36
+ role: "agent";
37
+ parts: unknown;
38
+ createdAt: Date;
39
+ }[];
40
+ turnCount: number;
41
+ lastTurn: {
42
+ action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
43
+ assessment: {
44
+ reasoning: string;
45
+ suggestedRoles: {
46
+ ownUser: "agent" | "patient" | "peer";
47
+ otherUser: "agent" | "patient" | "peer";
48
+ };
49
+ };
50
+ message?: string | null | undefined;
51
+ askUser?: {
52
+ reason: "unresolved_owner_constraint" | "consequential_disclosure_permission" | "repeated_non_convergence" | "insufficient_commitment_authority";
53
+ } | null | undefined;
54
+ };
55
+ status: "input_required";
56
+ firstTurnScreenedOut?: undefined;
57
+ error?: undefined;
58
+ } | {
59
+ deadlockShift?: DeadlockShiftRecord | undefined;
60
+ outreachOpened?: boolean | undefined;
61
+ messages: {
62
+ id: string;
63
+ senderId: string;
64
+ role: "agent";
65
+ parts: unknown;
66
+ createdAt: Date;
67
+ }[];
68
+ turnCount: number;
69
+ currentSpeaker: "source" | "candidate";
70
+ lastTurn: {
71
+ action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
72
+ assessment: {
73
+ reasoning: string;
74
+ suggestedRoles: {
75
+ ownUser: "agent" | "patient" | "peer";
76
+ otherUser: "agent" | "patient" | "peer";
77
+ };
78
+ };
79
+ message?: string | null | undefined;
80
+ askUser?: {
81
+ reason: "unresolved_owner_constraint" | "consequential_disclosure_permission" | "repeated_non_convergence" | "insufficient_commitment_authority";
82
+ } | null | undefined;
83
+ };
84
+ memoryBySide: {
85
+ [x: string]: import("../index.js").NegotiatorMemoryEntry[];
86
+ };
87
+ status?: undefined;
88
+ firstTurnScreenedOut?: undefined;
89
+ error?: undefined;
90
+ } | {
91
+ lastTurn: {
92
+ action: "propose" | "accept" | "reject" | "counter" | "question" | "outreach" | "withdraw" | "decline" | "ask_user";
93
+ assessment: {
94
+ reasoning: string;
95
+ suggestedRoles: {
96
+ ownUser: "peer";
97
+ otherUser: "peer";
98
+ };
99
+ };
100
+ };
101
+ turnCount: number;
102
+ error: string;
103
+ status?: undefined;
104
+ firstTurnScreenedOut?: undefined;
105
+ }>;