@indexnetwork/protocol 14.3.2-rc.477.1 → 17.0.0-rc.479.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +141 -0
- package/IMPLEMENTATION.md +50 -52
- package/STABILITY.md +3 -3
- package/dist/chat/chat.agent.js +2 -3
- package/dist/chat/chat.graph.d.ts +41 -1
- package/dist/chat/chat.graph.js +108 -127
- package/dist/chat/negotiator.persona.d.ts +1 -1
- package/dist/chat/negotiator.persona.js +1 -4
- package/dist/chat/negotiator.prompt.js +1 -2
- package/dist/chat/onboarding.persona.js +0 -1
- package/dist/chat/reporter.persona.js +0 -1
- package/dist/chat/signal.persona.js +0 -1
- package/dist/contacts/application/contact.tools.d.ts +6 -9
- package/dist/contacts/application/contact.tools.js +11 -92
- package/dist/contacts/application/index.d.ts +2 -14
- package/dist/contacts/application/index.js +2 -13
- package/dist/contacts/domain/contact.types.d.ts +0 -23
- package/dist/contacts/domain/index.d.ts +2 -6
- package/dist/contacts/index.d.ts +1 -1
- package/dist/contacts/index.js +1 -1
- package/dist/contacts/ports/contact.repository.port.d.ts +5 -12
- package/dist/contacts/ports/contact.repository.port.js +4 -6
- package/dist/contacts/ports/contact.tools.port.d.ts +1 -3
- package/dist/contacts/ports/contact.tools.port.js +1 -2
- package/dist/contacts/ports/index.d.ts +1 -1
- package/dist/contacts/ports/index.js +1 -1
- package/dist/discovery/hyde.frame.d.ts +4 -4
- package/dist/discovery/hyde.graph.d.ts +71 -12
- package/dist/discovery/hyde.graph.js +337 -335
- package/dist/discovery/lens.inferrer.d.ts +6 -6
- package/dist/enrichment/enrichment.graph.d.ts +127 -9
- package/dist/enrichment/enrichment.graph.js +633 -655
- package/dist/enrichment/enrichment.state.d.ts +1 -1
- package/dist/enrichment/enrichment.tools.context-read.d.ts +10 -0
- package/dist/enrichment/enrichment.tools.context-read.js +353 -0
- package/dist/enrichment/enrichment.tools.context-write.d.ts +9 -0
- package/dist/enrichment/enrichment.tools.context-write.js +417 -0
- package/dist/enrichment/enrichment.tools.d.ts +11 -1
- package/dist/enrichment/enrichment.tools.helpers.d.ts +139 -0
- package/dist/enrichment/enrichment.tools.helpers.js +234 -0
- package/dist/enrichment/enrichment.tools.js +16 -975
- package/dist/index.d.ts +27 -50
- package/dist/index.js +17 -28
- package/dist/intents/application/intent.graph.d.ts +71 -67
- package/dist/intents/application/intent.graph.execute.d.ts +59 -0
- package/dist/intents/application/intent.graph.execute.js +301 -0
- package/dist/intents/application/intent.graph.infer.d.ts +44 -0
- package/dist/intents/application/intent.graph.infer.js +97 -0
- package/dist/intents/application/intent.graph.js +96 -888
- package/dist/intents/application/intent.graph.reconcile.d.ts +71 -0
- package/dist/intents/application/intent.graph.reconcile.js +274 -0
- package/dist/intents/application/intent.graph.shared.d.ts +70 -0
- package/dist/intents/application/intent.graph.shared.js +153 -0
- package/dist/intents/domain/intent.state.d.ts +1 -1
- package/dist/maintenance/maintenance.graph.d.ts +66 -3
- package/dist/maintenance/maintenance.graph.js +155 -156
- package/dist/mcp/mcp.authorization-policy.d.ts +24 -28
- package/dist/mcp/mcp.authorization-policy.js +14 -34
- package/dist/mcp/mcp.server.d.ts +3 -3
- package/dist/mcp/mcp.server.js +14 -20
- package/dist/negotiations/application/negotiation.candidates.d.ts +83 -0
- package/dist/negotiations/application/negotiation.candidates.js +162 -0
- package/dist/negotiations/application/negotiation.graph.d.ts +91 -157
- package/dist/negotiations/application/negotiation.graph.finalize.d.ts +5 -0
- package/dist/negotiations/application/negotiation.graph.finalize.js +280 -0
- package/dist/negotiations/application/negotiation.graph.init.d.ts +54 -0
- package/dist/negotiations/application/negotiation.graph.init.js +227 -0
- package/dist/negotiations/application/negotiation.graph.js +69 -1388
- package/dist/negotiations/application/negotiation.graph.screen.d.ts +23 -0
- package/dist/negotiations/application/negotiation.graph.screen.js +108 -0
- package/dist/negotiations/application/negotiation.graph.shared.d.ts +75 -0
- package/dist/negotiations/application/negotiation.graph.shared.js +125 -0
- package/dist/negotiations/application/negotiation.graph.turn.d.ts +105 -0
- package/dist/negotiations/application/negotiation.graph.turn.js +484 -0
- package/dist/negotiations/domain/negotiation.state.d.ts +1 -1
- package/dist/negotiations/domain/negotiation.state.js +0 -1
- package/dist/networks/application/indexer.graph.d.ts +165 -7
- package/dist/networks/application/indexer.graph.js +339 -388
- package/dist/networks/application/indexer.state.d.ts +1 -1
- package/dist/networks/application/membership.graph.d.ts +83 -5
- package/dist/networks/application/membership.graph.js +177 -207
- package/dist/networks/application/network.graph.d.ts +148 -5
- package/dist/networks/application/network.graph.js +249 -278
- package/dist/networks/domain/membership.state.d.ts +1 -1
- package/dist/networks/domain/network.state.d.ts +1 -1
- package/dist/opportunities/application/delivery-card.cache.d.ts +1 -1
- package/dist/opportunities/application/delivery-card.cache.js +2 -2
- package/dist/opportunities/application/index.d.ts +2 -2
- package/dist/opportunities/application/index.js +2 -2
- package/dist/opportunities/application/opportunity.evaluator.js +1 -1
- package/dist/opportunities/application/opportunity.graph.d.ts +686 -473
- package/dist/opportunities/application/opportunity.graph.discovery-strategies.d.ts +109 -0
- package/dist/opportunities/application/opportunity.graph.discovery-strategies.js +451 -0
- package/dist/opportunities/application/opportunity.graph.discovery.d.ts +69 -0
- package/dist/opportunities/application/opportunity.graph.discovery.js +397 -0
- package/dist/opportunities/application/opportunity.graph.evaluation.d.ts +82 -0
- package/dist/opportunities/application/opportunity.graph.evaluation.js +608 -0
- package/dist/opportunities/application/opportunity.graph.js +120 -3690
- package/dist/opportunities/application/opportunity.graph.modes.d.ts +538 -0
- package/dist/opportunities/application/opportunity.graph.modes.js +538 -0
- package/dist/opportunities/application/opportunity.graph.negotiate.d.ts +109 -0
- package/dist/opportunities/application/opportunity.graph.negotiate.js +392 -0
- package/dist/opportunities/application/opportunity.graph.persist-node.d.ts +93 -0
- package/dist/opportunities/application/opportunity.graph.persist-node.js +765 -0
- package/dist/opportunities/application/opportunity.graph.prep.d.ts +150 -0
- package/dist/opportunities/application/opportunity.graph.prep.js +381 -0
- package/dist/opportunities/application/opportunity.graph.shared.d.ts +173 -0
- package/dist/opportunities/application/opportunity.graph.shared.js +199 -0
- package/dist/opportunities/application/opportunity.presentation.d.ts +399 -0
- package/dist/opportunities/application/{opportunity.presenter.js → opportunity.presentation.js} +735 -9
- package/dist/opportunities/application/opportunity.tools.cards.d.ts +152 -0
- package/dist/opportunities/application/opportunity.tools.cards.js +235 -0
- package/dist/opportunities/application/opportunity.tools.d.ts +8 -114
- package/dist/opportunities/application/opportunity.tools.js +28 -711
- package/dist/opportunities/application/opportunity.tools.list.d.ts +10 -0
- package/dist/opportunities/application/opportunity.tools.list.js +493 -0
- package/dist/opportunities/domain/index.d.ts +3 -3
- package/dist/opportunities/domain/index.js +3 -3
- package/dist/opportunities/domain/opportunity.state.d.ts +19 -19
- package/dist/opportunities/index.d.ts +6 -6
- package/dist/opportunities/index.js +4 -4
- package/dist/opportunities/ports/opportunity.tools.port.d.ts +1 -1
- package/dist/opportunities/radar/radar.graph.d.ts +57 -13
- package/dist/opportunities/radar/radar.graph.js +470 -471
- package/dist/premises/premise.graph.d.ts +88 -20
- package/dist/premises/premise.graph.js +207 -218
- package/dist/questions/domain/question.schema.d.ts +40 -40
- package/dist/shared/agent/tool.factory.js +0 -8
- package/dist/shared/agent/tool.helpers.d.ts +21 -45
- package/dist/shared/agent/tool.helpers.js +1 -2
- package/dist/shared/agent/tool.registry.d.ts +4 -3
- package/dist/shared/agent/tool.registry.js +2 -4
- package/dist/shared/agent/tool.runtime.js +0 -2
- package/dist/shared/agent/utility.tools.js +9 -13
- package/dist/shared/interfaces/database.capabilities.d.ts +100 -0
- package/dist/shared/interfaces/database.capabilities.js +7 -0
- package/dist/shared/interfaces/database.entities.d.ts +533 -0
- package/dist/shared/interfaces/database.entities.js +10 -0
- package/dist/shared/interfaces/database.identity-queries.d.ts +294 -0
- package/dist/shared/interfaces/database.identity-queries.js +4 -0
- package/dist/shared/interfaces/database.interface.d.ts +15 -2277
- package/dist/shared/interfaces/database.interface.js +8 -0
- package/dist/shared/interfaces/database.member-queries.d.ts +221 -0
- package/dist/shared/interfaces/database.member-queries.js +4 -0
- package/dist/shared/interfaces/database.negotiation.d.ts +305 -0
- package/dist/shared/interfaces/database.negotiation.js +26 -0
- package/dist/shared/interfaces/database.network-queries.d.ts +277 -0
- package/dist/shared/interfaces/database.network-queries.js +4 -0
- package/dist/shared/interfaces/database.opportunity-queries.d.ts +285 -0
- package/dist/shared/interfaces/database.opportunity-queries.js +4 -0
- package/dist/shared/interfaces/database.port.d.ts +322 -0
- package/dist/shared/interfaces/database.port.js +29 -0
- package/dist/shared/schemas/discovery-question.schema.d.ts +14 -14
- package/dist/shared/schemas/negotiation-digest.schema.d.ts +2 -2
- package/package.json +2 -15
- package/dist/contacts/application/contact.inviter.d.ts +0 -49
- package/dist/contacts/application/contact.inviter.js +0 -64
- package/dist/integrations/application/index.d.ts +0 -14
- package/dist/integrations/application/index.js +0 -14
- package/dist/integrations/application/integration.tools.d.ts +0 -27
- package/dist/integrations/application/integration.tools.js +0 -98
- package/dist/integrations/domain/index.d.ts +0 -16
- package/dist/integrations/domain/index.js +0 -1
- package/dist/integrations/domain/integration.types.d.ts +0 -51
- package/dist/integrations/domain/integration.types.js +0 -9
- package/dist/integrations/index.d.ts +0 -10
- package/dist/integrations/index.js +0 -8
- package/dist/integrations/ports/index.d.ts +0 -25
- package/dist/integrations/ports/index.js +0 -23
- package/dist/integrations/ports/integration.adapter.port.d.ts +0 -62
- package/dist/integrations/ports/integration.adapter.port.js +0 -15
- package/dist/integrations/ports/integration.importer.port.d.ts +0 -31
- package/dist/integrations/ports/integration.importer.port.js +0 -15
- package/dist/integrations/ports/integration.tools.port.d.ts +0 -25
- package/dist/integrations/ports/integration.tools.port.js +0 -18
- package/dist/opportunities/application/opportunity.card-presentation.d.ts +0 -44
- package/dist/opportunities/application/opportunity.card-presentation.js +0 -93
- package/dist/opportunities/application/opportunity.presenter.d.ts +0 -156
- package/dist/opportunities/domain/opportunity.presentation-cache.d.ts +0 -5
- package/dist/opportunities/domain/opportunity.presentation-cache.js +0 -11
- package/dist/opportunities/domain/opportunity.presentation.d.ts +0 -76
- package/dist/opportunities/domain/opportunity.presentation.js +0 -516
- package/dist/opportunities/domain/opportunity.safe-presentation.d.ts +0 -104
- package/dist/opportunities/domain/opportunity.safe-presentation.js +0 -102
package/dist/chat/chat.graph.js
CHANGED
|
@@ -19,24 +19,6 @@ function isRetriableError(err) {
|
|
|
19
19
|
lower.includes("etimedout"));
|
|
20
20
|
}
|
|
21
21
|
const RETRY_DELAY_MS = 800;
|
|
22
|
-
// ══════════════════════════════════════════════════════════════════════════════
|
|
23
|
-
// CHAT GRAPH FACTORY (Agent Loop Architecture)
|
|
24
|
-
// ══════════════════════════════════════════════════════════════════════════════
|
|
25
|
-
/**
|
|
26
|
-
* Factory class to build and compile the Chat Graph.
|
|
27
|
-
*
|
|
28
|
-
* Architecture: ReAct-Style Agent Loop
|
|
29
|
-
*
|
|
30
|
-
* The graph contains a single node that runs an agent loop:
|
|
31
|
-
* 1. Agent receives messages (conversation + tool results)
|
|
32
|
-
* 2. Agent decides: call tools OR respond to user
|
|
33
|
-
* 3. If tools called → execute → add results → loop back
|
|
34
|
-
* 4. If response → exit loop → stream to user
|
|
35
|
-
*
|
|
36
|
-
* This replaces the previous 17-node conditional routing architecture
|
|
37
|
-
* with a flexible, LLM-driven approach that can handle multi-step
|
|
38
|
-
* reasoning and self-correction.
|
|
39
|
-
*/
|
|
40
22
|
export class ChatGraphFactory {
|
|
41
23
|
constructor(database, embedder, scraper, chatSession, protocolDeps,
|
|
42
24
|
/** Persona driving this graph's agent loop. Required — there is no default. */
|
|
@@ -139,68 +121,107 @@ export class ChatGraphFactory {
|
|
|
139
121
|
* @returns Uncompiled StateGraph
|
|
140
122
|
*/
|
|
141
123
|
buildGraph() {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
124
|
+
const deps = {
|
|
125
|
+
database: this.database,
|
|
126
|
+
embedder: this.embedder,
|
|
127
|
+
scraper: this.scraper,
|
|
128
|
+
protocolDeps: this.protocolDeps,
|
|
129
|
+
persona: this.persona,
|
|
130
|
+
};
|
|
147
131
|
// ─────────────────────────────────────────────────────────────────────────
|
|
148
|
-
//
|
|
132
|
+
// GRAPH ASSEMBLY
|
|
149
133
|
// ─────────────────────────────────────────────────────────────────────────
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
134
|
+
const workflow = new StateGraph(ChatGraphState)
|
|
135
|
+
.addNode("agent_loop", (state, config) => agentLoopNode(state, config, deps))
|
|
136
|
+
.addEdge(START, "agent_loop")
|
|
137
|
+
.addEdge("agent_loop", END);
|
|
138
|
+
logger.verbose("Graph built successfully (agent loop architecture)");
|
|
139
|
+
return workflow;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The main agent loop node.
|
|
144
|
+
* Runs a ReAct-style agent that calls tools until it decides to respond.
|
|
145
|
+
*
|
|
146
|
+
* Uses `agent.streamRun()` + `config.writer` so that text tokens and
|
|
147
|
+
* tool-activity events are pushed into the graph's custom stream in
|
|
148
|
+
* real-time rather than batched at the end.
|
|
149
|
+
*/
|
|
150
|
+
export async function agentLoopNode(state, config, deps) {
|
|
151
|
+
return timed("ChatGraph.agentLoop", async () => {
|
|
152
|
+
logger.verbose("Agent loop starting", {
|
|
153
|
+
userId: state.userId,
|
|
154
|
+
messageCount: state.messages.length,
|
|
155
|
+
currentIteration: state.iterationCount
|
|
156
|
+
});
|
|
157
|
+
const runLoop = async () => {
|
|
158
|
+
const legacyNetworkId = state.networkId;
|
|
159
|
+
const scopeType = state.scopeType ?? (legacyNetworkId ? 'network' : undefined);
|
|
160
|
+
const scopeId = state.scopeId ?? legacyNetworkId;
|
|
161
|
+
const agent = await ChatAgent.create({
|
|
162
|
+
...deps.protocolDeps,
|
|
163
|
+
userId: state.userId,
|
|
164
|
+
database: deps.database,
|
|
165
|
+
embedder: deps.embedder,
|
|
166
|
+
scraper: deps.scraper,
|
|
167
|
+
...(legacyNetworkId ? { networkId: legacyNetworkId } : {}),
|
|
168
|
+
...(scopeType && scopeId ? { scopeType, scopeId } : {}),
|
|
169
|
+
sessionId: state.sessionId,
|
|
170
|
+
}, deps.persona);
|
|
171
|
+
// Direct streaming writer - emit events immediately instead of buffering
|
|
172
|
+
const directWriter = (data) => {
|
|
173
|
+
try {
|
|
174
|
+
config.writer?.(data);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
/* swallow if writer is gone */
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
// Get signal from configurable (passed by streamer via graph.stream() config)
|
|
181
|
+
const signal = config.configurable?.signal;
|
|
182
|
+
const result = await agent.streamRun(state.messages, directWriter, signal);
|
|
183
|
+
return result;
|
|
184
|
+
};
|
|
185
|
+
try {
|
|
186
|
+
const result = await runLoop();
|
|
187
|
+
logger.debug("Agent streamRun result", {
|
|
188
|
+
responseText: result.responseText,
|
|
189
|
+
iterationCount: result.iterationCount,
|
|
190
|
+
messageCount: result.messages.length,
|
|
191
|
+
});
|
|
192
|
+
logger.verbose("Agent loop complete", {
|
|
193
|
+
userId: state.userId,
|
|
194
|
+
iterations: result.iterationCount,
|
|
195
|
+
responseLength: result.responseText.length
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
messages: result.messages,
|
|
199
|
+
responseText: result.responseText,
|
|
200
|
+
iterationCount: result.iterationCount,
|
|
201
|
+
shouldContinue: false,
|
|
202
|
+
debugMeta: result.debugMeta,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
if (isRetriableError(error)) {
|
|
207
|
+
const signal = config.configurable?.signal;
|
|
208
|
+
if (signal?.aborted) {
|
|
209
|
+
return {
|
|
210
|
+
error: "Request aborted",
|
|
211
|
+
responseText: "",
|
|
212
|
+
shouldContinue: false,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
logger.warn("Agent loop failed with retriable error, retrying once", {
|
|
161
216
|
userId: state.userId,
|
|
162
|
-
|
|
163
|
-
currentIteration: state.iterationCount
|
|
217
|
+
error: error instanceof Error ? error.message : String(error)
|
|
164
218
|
});
|
|
165
|
-
|
|
166
|
-
const legacyNetworkId = state.networkId;
|
|
167
|
-
const scopeType = state.scopeType ?? (legacyNetworkId ? 'network' : undefined);
|
|
168
|
-
const scopeId = state.scopeId ?? legacyNetworkId;
|
|
169
|
-
const agent = await ChatAgent.create({
|
|
170
|
-
...protocolDeps,
|
|
171
|
-
userId: state.userId,
|
|
172
|
-
database,
|
|
173
|
-
embedder,
|
|
174
|
-
scraper,
|
|
175
|
-
...(legacyNetworkId ? { networkId: legacyNetworkId } : {}),
|
|
176
|
-
...(scopeType && scopeId ? { scopeType, scopeId } : {}),
|
|
177
|
-
sessionId: state.sessionId,
|
|
178
|
-
}, persona);
|
|
179
|
-
// Direct streaming writer - emit events immediately instead of buffering
|
|
180
|
-
const directWriter = (data) => {
|
|
181
|
-
try {
|
|
182
|
-
config.writer?.(data);
|
|
183
|
-
}
|
|
184
|
-
catch {
|
|
185
|
-
/* swallow if writer is gone */
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
// Get signal from configurable (passed by streamer via graph.stream() config)
|
|
189
|
-
const signal = config.configurable?.signal;
|
|
190
|
-
const result = await agent.streamRun(state.messages, directWriter, signal);
|
|
191
|
-
return result;
|
|
192
|
-
};
|
|
219
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
193
220
|
try {
|
|
194
221
|
const result = await runLoop();
|
|
195
|
-
logger.
|
|
196
|
-
responseText: result.responseText,
|
|
197
|
-
iterationCount: result.iterationCount,
|
|
198
|
-
messageCount: result.messages.length,
|
|
199
|
-
});
|
|
200
|
-
logger.verbose("Agent loop complete", {
|
|
222
|
+
logger.verbose("Agent loop complete after retry", {
|
|
201
223
|
userId: state.userId,
|
|
202
224
|
iterations: result.iterationCount,
|
|
203
|
-
responseLength: result.responseText.length
|
|
204
225
|
});
|
|
205
226
|
return {
|
|
206
227
|
messages: result.messages,
|
|
@@ -210,67 +231,27 @@ export class ChatGraphFactory {
|
|
|
210
231
|
debugMeta: result.debugMeta,
|
|
211
232
|
};
|
|
212
233
|
}
|
|
213
|
-
catch (
|
|
214
|
-
|
|
215
|
-
const signal = config.configurable?.signal;
|
|
216
|
-
if (signal?.aborted) {
|
|
217
|
-
return {
|
|
218
|
-
error: "Request aborted",
|
|
219
|
-
responseText: "",
|
|
220
|
-
shouldContinue: false,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
logger.warn("Agent loop failed with retriable error, retrying once", {
|
|
224
|
-
userId: state.userId,
|
|
225
|
-
error: error instanceof Error ? error.message : String(error)
|
|
226
|
-
});
|
|
227
|
-
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
228
|
-
try {
|
|
229
|
-
const result = await runLoop();
|
|
230
|
-
logger.verbose("Agent loop complete after retry", {
|
|
231
|
-
userId: state.userId,
|
|
232
|
-
iterations: result.iterationCount,
|
|
233
|
-
});
|
|
234
|
-
return {
|
|
235
|
-
messages: result.messages,
|
|
236
|
-
responseText: result.responseText,
|
|
237
|
-
iterationCount: result.iterationCount,
|
|
238
|
-
shouldContinue: false,
|
|
239
|
-
debugMeta: result.debugMeta,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
catch (retryError) {
|
|
243
|
-
logger.error("Agent loop failed on retry", {
|
|
244
|
-
userId: state.userId,
|
|
245
|
-
error: retryError instanceof Error ? retryError.message : String(retryError)
|
|
246
|
-
});
|
|
247
|
-
return {
|
|
248
|
-
error: retryError instanceof Error ? retryError.message : "Agent loop failed",
|
|
249
|
-
responseText: "I apologize, but I encountered an issue processing your request. Please try again.",
|
|
250
|
-
shouldContinue: false
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
logger.error("Agent loop failed", {
|
|
234
|
+
catch (retryError) {
|
|
235
|
+
logger.error("Agent loop failed on retry", {
|
|
255
236
|
userId: state.userId,
|
|
256
|
-
error:
|
|
237
|
+
error: retryError instanceof Error ? retryError.message : String(retryError)
|
|
257
238
|
});
|
|
258
239
|
return {
|
|
259
|
-
error:
|
|
240
|
+
error: retryError instanceof Error ? retryError.message : "Agent loop failed",
|
|
260
241
|
responseText: "I apologize, but I encountered an issue processing your request. Please try again.",
|
|
261
242
|
shouldContinue: false
|
|
262
243
|
};
|
|
263
244
|
}
|
|
245
|
+
}
|
|
246
|
+
logger.error("Agent loop failed", {
|
|
247
|
+
userId: state.userId,
|
|
248
|
+
error: error instanceof Error ? error.message : String(error)
|
|
264
249
|
});
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
.addEdge("agent_loop", END);
|
|
273
|
-
logger.verbose("Graph built successfully (agent loop architecture)");
|
|
274
|
-
return workflow;
|
|
275
|
-
}
|
|
250
|
+
return {
|
|
251
|
+
error: error instanceof Error ? error.message : "Agent loop failed",
|
|
252
|
+
responseText: "I apologize, but I encountered an issue processing your request. Please try again.",
|
|
253
|
+
shouldContinue: false
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
});
|
|
276
257
|
}
|
|
@@ -25,7 +25,7 @@ export declare const NEGOTIATOR_PERSONA_ID = "negotiator";
|
|
|
25
25
|
* - agent management (`register/update/delete_agent`, permission grants),
|
|
26
26
|
* - `confirm_opportunity_delivery` (OpenClaw ledger write, never chat).
|
|
27
27
|
*/
|
|
28
|
-
export declare const NEGOTIATOR_TOOL_NAMES: readonly ["list_negotiations", "get_negotiation", "respond_to_negotiation", "list_opportunities", "update_opportunity", "read_pending_questions", "answer_pending_question", "read_intents", "create_intent", "update_intent", "delete_intent", "search_intents", "read_intent_indexes", "create_intent_index", "delete_intent_index", "read_user_contexts", "create_user_context", "update_user_context", "confirm_user_context", "preview_user_context", "read_premises", "create_premise", "update_premise", "retract_premise", "read_networks", "read_network_memberships", "create_network_membership", "delete_network_membership", "list_contacts", "search_contacts", "
|
|
28
|
+
export declare const NEGOTIATOR_TOOL_NAMES: readonly ["list_negotiations", "get_negotiation", "respond_to_negotiation", "list_opportunities", "update_opportunity", "read_pending_questions", "answer_pending_question", "read_intents", "create_intent", "update_intent", "delete_intent", "search_intents", "read_intent_indexes", "create_intent_index", "delete_intent_index", "read_user_contexts", "create_user_context", "update_user_context", "confirm_user_context", "preview_user_context", "read_premises", "create_premise", "update_premise", "retract_premise", "read_networks", "read_network_memberships", "create_network_membership", "delete_network_membership", "list_contacts", "search_contacts", "remove_contact", "scrape_url"];
|
|
29
29
|
/**
|
|
30
30
|
* Filters a full chat-tool registry down to the negotiator allowlist.
|
|
31
31
|
* Exported separately so the scoping rule is unit-testable without
|
|
@@ -73,13 +73,10 @@ export const NEGOTIATOR_TOOL_NAMES = [
|
|
|
73
73
|
"read_network_memberships",
|
|
74
74
|
"create_network_membership",
|
|
75
75
|
"delete_network_membership",
|
|
76
|
-
// Contacts —
|
|
76
|
+
// Contacts — read/remove only; contacts arise from accepted opportunities
|
|
77
77
|
"list_contacts",
|
|
78
78
|
"search_contacts",
|
|
79
|
-
"add_contact",
|
|
80
79
|
"remove_contact",
|
|
81
|
-
"import_contacts",
|
|
82
|
-
"import_gmail_contacts",
|
|
83
80
|
// Utility — create_intent's own contract instructs scraping pasted URLs
|
|
84
81
|
// before synthesizing a signal description (P4.5)
|
|
85
82
|
"scrape_url",
|
|
@@ -145,8 +145,7 @@ ${profileContext}
|
|
|
145
145
|
| **read_premises** / **create_premise** / **update_premise** / **retract_premise** | ... | The client's premises (facts they've established) |
|
|
146
146
|
| **read_networks** / **read_network_memberships** | — | The client's communities and memberships |
|
|
147
147
|
| **create_network_membership** / **delete_network_membership** | networkId | Join/leave a community on instruction |
|
|
148
|
-
| **list_contacts** / **search_contacts** / **
|
|
149
|
-
| **import_contacts** / **import_gmail_contacts** | ... | Bulk contact import on instruction |
|
|
148
|
+
| **list_contacts** / **search_contacts** / **remove_contact** | ... | The client's contacts |
|
|
150
149
|
| **scrape_url** | url, objective | Read a link the client pasted (e.g. before drafting a signal from it) |${memoryToolsRows}
|
|
151
150
|
|
|
152
151
|
## Grounding rules
|
|
@@ -56,7 +56,6 @@ export async function createOnboardingTools(deps, preResolvedContext) {
|
|
|
56
56
|
userId: deps.userId,
|
|
57
57
|
networkId: explicitScope.scopeType === "network" ? explicitScope.scopeId : deps.networkId,
|
|
58
58
|
sessionId: deps.sessionId,
|
|
59
|
-
contactsEnabled: deps.contactsEnabled,
|
|
60
59
|
});
|
|
61
60
|
if (explicitScope.scopeType && explicitScope.scopeId) {
|
|
62
61
|
resolvedContext.scopeType = explicitScope.scopeType;
|
|
@@ -179,7 +179,6 @@ export async function createReporterTools(deps, preResolvedContext) {
|
|
|
179
179
|
userId: deps.userId,
|
|
180
180
|
networkId: explicitScope.scopeType === "network" ? explicitScope.scopeId : deps.networkId,
|
|
181
181
|
sessionId: deps.sessionId,
|
|
182
|
-
contactsEnabled: deps.contactsEnabled,
|
|
183
182
|
actionToolsEnabled: deps.actionToolsEnabled,
|
|
184
183
|
});
|
|
185
184
|
if (explicitScope.scopeType && explicitScope.scopeId) {
|
|
@@ -289,7 +289,6 @@ export async function createSignalTools(deps, preResolvedContext) {
|
|
|
289
289
|
userId: deps.userId,
|
|
290
290
|
networkId: explicitScope.scopeType === "network" ? explicitScope.scopeId : deps.networkId,
|
|
291
291
|
sessionId: deps.sessionId,
|
|
292
|
-
contactsEnabled: deps.contactsEnabled,
|
|
293
292
|
});
|
|
294
293
|
if (explicitScope.scopeType && explicitScope.scopeId) {
|
|
295
294
|
resolvedContext.scopeType = explicitScope.scopeType;
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* contacts/application — createContactTools canonical implementation.
|
|
3
3
|
*
|
|
4
|
-
* Creates contact management tools for the chat agent. Enables
|
|
5
|
-
*
|
|
4
|
+
* Creates contact management tools for the chat agent. Enables listing,
|
|
5
|
+
* removing, and searching the user's personal network.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* IND-549: moved from contact/contact.tools.ts into the canonical
|
|
12
|
-
* contacts/application layer.
|
|
7
|
+
* Contacts are established by accepting an opportunity — opportunity accept
|
|
8
|
+
* and start-chat write the mutual `contact` memberships. There is no import or
|
|
9
|
+
* manual-add path, and no ghost users: every contact is a real account.
|
|
13
10
|
*/
|
|
14
11
|
import type { DefineTool } from '../../shared/agent/tool.helpers.js';
|
|
15
12
|
import type { ContactToolDeps } from '../ports/index.js';
|
|
16
13
|
/**
|
|
17
14
|
* Creates contact management tools for the chat agent.
|
|
18
|
-
* Enables
|
|
15
|
+
* Enables listing, searching, and removing entries in the user's network.
|
|
19
16
|
*/
|
|
20
17
|
export declare function createContactTools(defineTool: DefineTool, deps: ContactToolDeps): any[];
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* contacts/application — createContactTools canonical implementation.
|
|
3
3
|
*
|
|
4
|
-
* Creates contact management tools for the chat agent. Enables
|
|
5
|
-
*
|
|
4
|
+
* Creates contact management tools for the chat agent. Enables listing,
|
|
5
|
+
* removing, and searching the user's personal network.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* IND-549: moved from contact/contact.tools.ts into the canonical
|
|
12
|
-
* contacts/application layer.
|
|
7
|
+
* Contacts are established by accepting an opportunity — opportunity accept
|
|
8
|
+
* and start-chat write the mutual `contact` memberships. There is no import or
|
|
9
|
+
* manual-add path, and no ghost users: every contact is a real account.
|
|
13
10
|
*/
|
|
14
11
|
import { z } from 'zod';
|
|
15
12
|
import { success, error } from '../../shared/agent/tool.helpers.js';
|
|
@@ -17,58 +14,18 @@ import { protocolLogger } from '../../shared/observability/protocol.logger.js';
|
|
|
17
14
|
const logger = protocolLogger('ChatTools:Contact');
|
|
18
15
|
/**
|
|
19
16
|
* Creates contact management tools for the chat agent.
|
|
20
|
-
* Enables
|
|
17
|
+
* Enables listing, searching, and removing entries in the user's network.
|
|
21
18
|
*/
|
|
22
19
|
export function createContactTools(defineTool, deps) {
|
|
23
20
|
const { contactService } = deps;
|
|
24
|
-
// Contact import / manual-add create ghost users. These are gated behind the
|
|
25
|
-
// CONTACTS_ENABLED flag (injected as deps.contactsEnabled). Read/remove/search
|
|
26
|
-
// tools below are always available so existing contacts stay manageable.
|
|
27
|
-
const contactsEnabled = deps.contactsEnabled === true;
|
|
28
|
-
// Only register when enabled: in the registry path defineTool registers as a
|
|
29
|
-
// side effect, so the call itself must be gated, not just the returned array.
|
|
30
|
-
const import_contacts = contactsEnabled ? defineTool({
|
|
31
|
-
name: 'import_contacts',
|
|
32
|
-
description: "Bulk-imports contacts into the authenticated user's personal network (personal network). Contacts become members of the user's " +
|
|
33
|
-
"personal network with 'contact' permission, making their approved signals eligible for background matching.\n\n" +
|
|
34
|
-
"**What happens:** Each contact is matched by email. If the email belongs to an existing user, they're linked directly. " +
|
|
35
|
-
"If not, a 'ghost user' is created — a placeholder account enriched with public profile data (from LinkedIn, GitHub, etc.) " +
|
|
36
|
-
"that participates in opportunity matching even before the person joins the platform.\n\n" +
|
|
37
|
-
"**When to use:** When the user provides a list of contacts to add (from CSV, manual input, or any source other than Gmail). " +
|
|
38
|
-
"For Gmail specifically, use import_gmail_contacts instead.\n\n" +
|
|
39
|
-
"**Returns:** Import statistics: imported (total processed), skipped (invalid), newContacts (ghost users created), " +
|
|
40
|
-
"existingContacts (already in network). Use list_contacts to see all contacts after import.",
|
|
41
|
-
querySchema: z.object({
|
|
42
|
-
contacts: z.array(z.object({
|
|
43
|
-
name: z.string().describe('Full name of the contact (e.g. "Jane Smith")'),
|
|
44
|
-
email: z.string().describe('Email address — used as the unique identifier for matching existing users'),
|
|
45
|
-
})).describe('Array of contact objects to import. Each must have name and email. Duplicates (by email) are skipped.'),
|
|
46
|
-
}),
|
|
47
|
-
handler: async ({ context, query }) => {
|
|
48
|
-
try {
|
|
49
|
-
const result = await contactService.importContacts(context.userId, query.contacts);
|
|
50
|
-
return success({
|
|
51
|
-
message: `Imported ${result.imported} contacts to your network.`,
|
|
52
|
-
imported: result.imported,
|
|
53
|
-
skipped: result.skipped,
|
|
54
|
-
newContacts: result.newContacts,
|
|
55
|
-
existingContacts: result.existingContacts,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
logger.error('Failed to import contacts', { err });
|
|
60
|
-
return error('Failed to import contacts. Please try again.');
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
}) : null;
|
|
64
21
|
const list_contacts = defineTool({
|
|
65
22
|
name: 'list_contacts',
|
|
66
|
-
description: "Lists all contacts in the authenticated user's personal network. Contacts are people the user has
|
|
67
|
-
"
|
|
23
|
+
description: "Lists all contacts in the authenticated user's personal network. Contacts are people the user has " +
|
|
24
|
+
"accepted an opportunity with, stored as members of their personal network.\n\n" +
|
|
68
25
|
"**When to use:** To see who's in the user's network, find a contact's userId for other operations, " +
|
|
69
26
|
"or check if a specific person is already a contact.\n\n" +
|
|
70
|
-
"**Returns:** Array of contacts, each with userId (use with read_user_contexts), name, email, avatar URL
|
|
71
|
-
"
|
|
27
|
+
"**Returns:** Array of contacts, each with userId (use with read_user_contexts), name, email, and avatar URL. " +
|
|
28
|
+
"Use read_user_contexts(userId) to get the full profile. " +
|
|
72
29
|
"Approved signals are matched in the background; list_opportunities only reviews persisted results.",
|
|
73
30
|
querySchema: z.object({
|
|
74
31
|
limit: z.number().optional().describe('Maximum number of contacts to return. Omit to return all contacts. Use for large networks to paginate results.'),
|
|
@@ -96,38 +53,6 @@ export function createContactTools(defineTool, deps) {
|
|
|
96
53
|
}
|
|
97
54
|
},
|
|
98
55
|
});
|
|
99
|
-
const add_contact = contactsEnabled ? defineTool({
|
|
100
|
-
name: 'add_contact',
|
|
101
|
-
description: "Adds a single contact to the authenticated user's personal network by email address. " +
|
|
102
|
-
"For bulk imports, use import_contacts instead.\n\n" +
|
|
103
|
-
"**What happens:** Looks up the email. If an account exists, links that user as a contact. " +
|
|
104
|
-
"If not, creates a ghost user (placeholder enriched with public profile data) and adds them. " +
|
|
105
|
-
"Their approved signals can then become eligible for background matching within the user's personal network.\n\n" +
|
|
106
|
-
"**When to use:** When the user wants to add a specific person (e.g. 'add john@example.com to my network').\n\n" +
|
|
107
|
-
"**Returns:** Confirmation with the contact's userId and whether a new ghost user was created (isNewGhost). " +
|
|
108
|
-
"Background matching may create persisted opportunities from approved signals; list_opportunities only reviews those results.",
|
|
109
|
-
querySchema: z.object({
|
|
110
|
-
email: z.string().describe('Email address of the person to add. Used as unique identifier — if already a contact, the operation is idempotent.'),
|
|
111
|
-
name: z.string().optional().describe('Full name of the contact. Optional — if omitted, the email prefix is used as name. Provide when known for better profile enrichment.'),
|
|
112
|
-
}),
|
|
113
|
-
handler: async ({ context, query }) => {
|
|
114
|
-
try {
|
|
115
|
-
const result = await contactService.addContact(context.userId, query.email, { name: query.name, restore: true });
|
|
116
|
-
return success({
|
|
117
|
-
added: true,
|
|
118
|
-
message: result.isNew
|
|
119
|
-
? `Added ${query.name || query.email} to your network. Their profile is being enriched.`
|
|
120
|
-
: `Added ${query.name || query.email} to your network.`,
|
|
121
|
-
userId: result.userId,
|
|
122
|
-
isNewGhost: result.isNew,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
catch (err) {
|
|
126
|
-
logger.error('Failed to add contact', { err });
|
|
127
|
-
return error('Failed to add contact. Please try again.');
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
}) : null;
|
|
131
56
|
const remove_contact = defineTool({
|
|
132
57
|
name: 'remove_contact',
|
|
133
58
|
description: "Removes a contact from the authenticated user's personal network. The contact relationship is deleted — " +
|
|
@@ -181,11 +106,5 @@ export function createContactTools(defineTool, deps) {
|
|
|
181
106
|
}
|
|
182
107
|
},
|
|
183
108
|
});
|
|
184
|
-
return [
|
|
185
|
-
...(import_contacts ? [import_contacts] : []),
|
|
186
|
-
...(add_contact ? [add_contact] : []),
|
|
187
|
-
list_contacts,
|
|
188
|
-
remove_contact,
|
|
189
|
-
search_contacts,
|
|
190
|
-
];
|
|
109
|
+
return [list_contacts, remove_contact, search_contacts];
|
|
191
110
|
}
|
|
@@ -4,19 +4,7 @@
|
|
|
4
4
|
* ## Exports
|
|
5
5
|
*
|
|
6
6
|
* ### Tool factory
|
|
7
|
-
* - `createContactTools` — creates contact management MCP tools
|
|
8
|
-
* list,
|
|
9
|
-
* deps.contactsEnabled; read/remove/search are always registered.
|
|
10
|
-
*
|
|
11
|
-
* ### Invite generator
|
|
12
|
-
* - `generateInviteMessage` — LLM-based invite message generator for ghost
|
|
13
|
-
* users; produces short, contextual messages referencing the opportunity.
|
|
14
|
-
*
|
|
15
|
-
* IND-549: canonical application layer for the contacts capability.
|
|
16
|
-
* Legacy paths:
|
|
17
|
-
* - contact/contact.tools.ts → thin compatibility shim pointing here
|
|
18
|
-
* - contact/contact.inviter.ts → thin compatibility shim pointing here
|
|
7
|
+
* - `createContactTools` — creates contact management MCP tools
|
|
8
|
+
* (list, remove, search).
|
|
19
9
|
*/
|
|
20
10
|
export { createContactTools } from "./contact.tools.js";
|
|
21
|
-
export { generateInviteMessage } from "./contact.inviter.js";
|
|
22
|
-
export type { InviteInput, InviteOutput } from "./contact.inviter.js";
|
|
@@ -4,18 +4,7 @@
|
|
|
4
4
|
* ## Exports
|
|
5
5
|
*
|
|
6
6
|
* ### Tool factory
|
|
7
|
-
* - `createContactTools` — creates contact management MCP tools
|
|
8
|
-
* list,
|
|
9
|
-
* deps.contactsEnabled; read/remove/search are always registered.
|
|
10
|
-
*
|
|
11
|
-
* ### Invite generator
|
|
12
|
-
* - `generateInviteMessage` — LLM-based invite message generator for ghost
|
|
13
|
-
* users; produces short, contextual messages referencing the opportunity.
|
|
14
|
-
*
|
|
15
|
-
* IND-549: canonical application layer for the contacts capability.
|
|
16
|
-
* Legacy paths:
|
|
17
|
-
* - contact/contact.tools.ts → thin compatibility shim pointing here
|
|
18
|
-
* - contact/contact.inviter.ts → thin compatibility shim pointing here
|
|
7
|
+
* - `createContactTools` — creates contact management MCP tools
|
|
8
|
+
* (list, remove, search).
|
|
19
9
|
*/
|
|
20
10
|
export { createContactTools } from "./contact.tools.js";
|
|
21
|
-
export { generateInviteMessage } from "./contact.inviter.js";
|
|
@@ -5,29 +5,6 @@
|
|
|
5
5
|
*
|
|
6
6
|
* IND-549: canonical domain layer for the contacts capability.
|
|
7
7
|
*/
|
|
8
|
-
/** Input for importing a single contact. */
|
|
9
|
-
export interface ContactInput {
|
|
10
|
-
name: string;
|
|
11
|
-
email: string;
|
|
12
|
-
}
|
|
13
|
-
/** Result of adding a single contact. */
|
|
14
|
-
export interface ContactResult {
|
|
15
|
-
userId: string;
|
|
16
|
-
isNew: boolean;
|
|
17
|
-
isGhost: boolean;
|
|
18
|
-
}
|
|
19
|
-
/** Result of importing contacts in bulk. */
|
|
20
|
-
export interface ContactImportResult {
|
|
21
|
-
imported: number;
|
|
22
|
-
skipped: number;
|
|
23
|
-
newContacts: number;
|
|
24
|
-
existingContacts: number;
|
|
25
|
-
details: Array<{
|
|
26
|
-
email: string;
|
|
27
|
-
userId: string;
|
|
28
|
-
isNew: boolean;
|
|
29
|
-
}>;
|
|
30
|
-
}
|
|
31
8
|
/** Contact with user details, as returned by listContacts. */
|
|
32
9
|
export interface ContactEntry {
|
|
33
10
|
userId: string;
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* contacts/domain — pure contact entity value types and constants.
|
|
3
3
|
*
|
|
4
|
-
* Contains
|
|
5
|
-
* and ContactSearchResult.
|
|
4
|
+
* Contains ContactEntry and ContactSearchResult.
|
|
6
5
|
*
|
|
7
6
|
* ## What does NOT live here
|
|
8
7
|
*
|
|
9
8
|
* - ContactServiceAdapter: persistence port — lives in contacts/ports.
|
|
10
9
|
* - ContactToolDeps: tool host port — lives in contacts/ports.
|
|
11
10
|
* - createContactTools: application layer — lives in contacts/application.
|
|
12
|
-
* - generateInviteMessage: application layer — lives in contacts/application.
|
|
13
|
-
*
|
|
14
|
-
* IND-549: canonical domain layer for the contacts capability.
|
|
15
11
|
*/
|
|
16
|
-
export type {
|
|
12
|
+
export type { ContactEntry, ContactSearchResult, } from "./contact.types.js";
|
package/dist/contacts/index.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* Supersedes the capabilities/contacts.facade.ts + contacts/public/ pair; the
|
|
6
6
|
* export list is the union of the facades it replaces, so the contract is unchanged.
|
|
7
7
|
*/
|
|
8
|
-
export { createContactTools
|
|
8
|
+
export { createContactTools } from "./application/index.js";
|
|
9
9
|
export type { ContactServiceAdapter, ContactToolDeps, } from "./ports/index.js";
|
package/dist/contacts/index.js
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* Supersedes the capabilities/contacts.facade.ts + contacts/public/ pair; the
|
|
6
6
|
* export list is the union of the facades it replaces, so the contract is unchanged.
|
|
7
7
|
*/
|
|
8
|
-
export { createContactTools
|
|
8
|
+
export { createContactTools } from "./application/index.js";
|