@indexnetwork/protocol 14.3.2-rc.477.1 → 17.0.0-rc.479.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +141 -0
- package/IMPLEMENTATION.md +50 -52
- package/STABILITY.md +3 -3
- package/dist/chat/chat.agent.js +2 -3
- package/dist/chat/chat.graph.d.ts +41 -1
- package/dist/chat/chat.graph.js +108 -127
- package/dist/chat/negotiator.persona.d.ts +1 -1
- package/dist/chat/negotiator.persona.js +1 -4
- package/dist/chat/negotiator.prompt.js +1 -2
- package/dist/chat/onboarding.persona.js +0 -1
- package/dist/chat/reporter.persona.js +0 -1
- package/dist/chat/signal.persona.js +0 -1
- package/dist/contacts/application/contact.tools.d.ts +6 -9
- package/dist/contacts/application/contact.tools.js +11 -92
- package/dist/contacts/application/index.d.ts +2 -14
- package/dist/contacts/application/index.js +2 -13
- package/dist/contacts/domain/contact.types.d.ts +0 -23
- package/dist/contacts/domain/index.d.ts +2 -6
- package/dist/contacts/index.d.ts +1 -1
- package/dist/contacts/index.js +1 -1
- package/dist/contacts/ports/contact.repository.port.d.ts +5 -12
- package/dist/contacts/ports/contact.repository.port.js +4 -6
- package/dist/contacts/ports/contact.tools.port.d.ts +1 -3
- package/dist/contacts/ports/contact.tools.port.js +1 -2
- package/dist/contacts/ports/index.d.ts +1 -1
- package/dist/contacts/ports/index.js +1 -1
- package/dist/discovery/hyde.frame.d.ts +4 -4
- package/dist/discovery/hyde.graph.d.ts +71 -12
- package/dist/discovery/hyde.graph.js +337 -335
- package/dist/discovery/lens.inferrer.d.ts +6 -6
- package/dist/enrichment/enrichment.graph.d.ts +127 -9
- package/dist/enrichment/enrichment.graph.js +633 -655
- package/dist/enrichment/enrichment.state.d.ts +1 -1
- package/dist/enrichment/enrichment.tools.context-read.d.ts +10 -0
- package/dist/enrichment/enrichment.tools.context-read.js +353 -0
- package/dist/enrichment/enrichment.tools.context-write.d.ts +9 -0
- package/dist/enrichment/enrichment.tools.context-write.js +417 -0
- package/dist/enrichment/enrichment.tools.d.ts +11 -1
- package/dist/enrichment/enrichment.tools.helpers.d.ts +139 -0
- package/dist/enrichment/enrichment.tools.helpers.js +234 -0
- package/dist/enrichment/enrichment.tools.js +16 -975
- package/dist/index.d.ts +27 -50
- package/dist/index.js +17 -28
- package/dist/intents/application/intent.graph.d.ts +71 -67
- package/dist/intents/application/intent.graph.execute.d.ts +59 -0
- package/dist/intents/application/intent.graph.execute.js +301 -0
- package/dist/intents/application/intent.graph.infer.d.ts +44 -0
- package/dist/intents/application/intent.graph.infer.js +97 -0
- package/dist/intents/application/intent.graph.js +96 -888
- package/dist/intents/application/intent.graph.reconcile.d.ts +71 -0
- package/dist/intents/application/intent.graph.reconcile.js +274 -0
- package/dist/intents/application/intent.graph.shared.d.ts +70 -0
- package/dist/intents/application/intent.graph.shared.js +153 -0
- package/dist/intents/domain/intent.state.d.ts +1 -1
- package/dist/maintenance/maintenance.graph.d.ts +66 -3
- package/dist/maintenance/maintenance.graph.js +155 -156
- package/dist/mcp/mcp.authorization-policy.d.ts +24 -28
- package/dist/mcp/mcp.authorization-policy.js +14 -34
- package/dist/mcp/mcp.server.d.ts +3 -3
- package/dist/mcp/mcp.server.js +14 -20
- package/dist/negotiations/application/negotiation.candidates.d.ts +83 -0
- package/dist/negotiations/application/negotiation.candidates.js +162 -0
- package/dist/negotiations/application/negotiation.graph.d.ts +91 -157
- package/dist/negotiations/application/negotiation.graph.finalize.d.ts +5 -0
- package/dist/negotiations/application/negotiation.graph.finalize.js +280 -0
- package/dist/negotiations/application/negotiation.graph.init.d.ts +54 -0
- package/dist/negotiations/application/negotiation.graph.init.js +227 -0
- package/dist/negotiations/application/negotiation.graph.js +69 -1388
- package/dist/negotiations/application/negotiation.graph.screen.d.ts +23 -0
- package/dist/negotiations/application/negotiation.graph.screen.js +108 -0
- package/dist/negotiations/application/negotiation.graph.shared.d.ts +75 -0
- package/dist/negotiations/application/negotiation.graph.shared.js +125 -0
- package/dist/negotiations/application/negotiation.graph.turn.d.ts +105 -0
- package/dist/negotiations/application/negotiation.graph.turn.js +484 -0
- package/dist/negotiations/domain/negotiation.state.d.ts +1 -1
- package/dist/negotiations/domain/negotiation.state.js +0 -1
- package/dist/networks/application/indexer.graph.d.ts +165 -7
- package/dist/networks/application/indexer.graph.js +339 -388
- package/dist/networks/application/indexer.state.d.ts +1 -1
- package/dist/networks/application/membership.graph.d.ts +83 -5
- package/dist/networks/application/membership.graph.js +177 -207
- package/dist/networks/application/network.graph.d.ts +148 -5
- package/dist/networks/application/network.graph.js +249 -278
- package/dist/networks/domain/membership.state.d.ts +1 -1
- package/dist/networks/domain/network.state.d.ts +1 -1
- package/dist/opportunities/application/delivery-card.cache.d.ts +1 -1
- package/dist/opportunities/application/delivery-card.cache.js +2 -2
- package/dist/opportunities/application/index.d.ts +2 -2
- package/dist/opportunities/application/index.js +2 -2
- package/dist/opportunities/application/opportunity.evaluator.js +1 -1
- package/dist/opportunities/application/opportunity.graph.d.ts +686 -473
- package/dist/opportunities/application/opportunity.graph.discovery-strategies.d.ts +109 -0
- package/dist/opportunities/application/opportunity.graph.discovery-strategies.js +451 -0
- package/dist/opportunities/application/opportunity.graph.discovery.d.ts +69 -0
- package/dist/opportunities/application/opportunity.graph.discovery.js +397 -0
- package/dist/opportunities/application/opportunity.graph.evaluation.d.ts +82 -0
- package/dist/opportunities/application/opportunity.graph.evaluation.js +608 -0
- package/dist/opportunities/application/opportunity.graph.js +120 -3690
- package/dist/opportunities/application/opportunity.graph.modes.d.ts +538 -0
- package/dist/opportunities/application/opportunity.graph.modes.js +538 -0
- package/dist/opportunities/application/opportunity.graph.negotiate.d.ts +109 -0
- package/dist/opportunities/application/opportunity.graph.negotiate.js +392 -0
- package/dist/opportunities/application/opportunity.graph.persist-node.d.ts +93 -0
- package/dist/opportunities/application/opportunity.graph.persist-node.js +765 -0
- package/dist/opportunities/application/opportunity.graph.prep.d.ts +150 -0
- package/dist/opportunities/application/opportunity.graph.prep.js +381 -0
- package/dist/opportunities/application/opportunity.graph.shared.d.ts +173 -0
- package/dist/opportunities/application/opportunity.graph.shared.js +199 -0
- package/dist/opportunities/application/opportunity.presentation.d.ts +399 -0
- package/dist/opportunities/application/{opportunity.presenter.js → opportunity.presentation.js} +735 -9
- package/dist/opportunities/application/opportunity.tools.cards.d.ts +152 -0
- package/dist/opportunities/application/opportunity.tools.cards.js +235 -0
- package/dist/opportunities/application/opportunity.tools.d.ts +8 -114
- package/dist/opportunities/application/opportunity.tools.js +28 -711
- package/dist/opportunities/application/opportunity.tools.list.d.ts +10 -0
- package/dist/opportunities/application/opportunity.tools.list.js +493 -0
- package/dist/opportunities/domain/index.d.ts +3 -3
- package/dist/opportunities/domain/index.js +3 -3
- package/dist/opportunities/domain/opportunity.state.d.ts +19 -19
- package/dist/opportunities/index.d.ts +6 -6
- package/dist/opportunities/index.js +4 -4
- package/dist/opportunities/ports/opportunity.tools.port.d.ts +1 -1
- package/dist/opportunities/radar/radar.graph.d.ts +57 -13
- package/dist/opportunities/radar/radar.graph.js +470 -471
- package/dist/premises/premise.graph.d.ts +88 -20
- package/dist/premises/premise.graph.js +207 -218
- package/dist/questions/domain/question.schema.d.ts +40 -40
- package/dist/shared/agent/tool.factory.js +0 -8
- package/dist/shared/agent/tool.helpers.d.ts +21 -45
- package/dist/shared/agent/tool.helpers.js +1 -2
- package/dist/shared/agent/tool.registry.d.ts +4 -3
- package/dist/shared/agent/tool.registry.js +2 -4
- package/dist/shared/agent/tool.runtime.js +0 -2
- package/dist/shared/agent/utility.tools.js +9 -13
- package/dist/shared/interfaces/database.capabilities.d.ts +100 -0
- package/dist/shared/interfaces/database.capabilities.js +7 -0
- package/dist/shared/interfaces/database.entities.d.ts +533 -0
- package/dist/shared/interfaces/database.entities.js +10 -0
- package/dist/shared/interfaces/database.identity-queries.d.ts +294 -0
- package/dist/shared/interfaces/database.identity-queries.js +4 -0
- package/dist/shared/interfaces/database.interface.d.ts +15 -2277
- package/dist/shared/interfaces/database.interface.js +8 -0
- package/dist/shared/interfaces/database.member-queries.d.ts +221 -0
- package/dist/shared/interfaces/database.member-queries.js +4 -0
- package/dist/shared/interfaces/database.negotiation.d.ts +305 -0
- package/dist/shared/interfaces/database.negotiation.js +26 -0
- package/dist/shared/interfaces/database.network-queries.d.ts +277 -0
- package/dist/shared/interfaces/database.network-queries.js +4 -0
- package/dist/shared/interfaces/database.opportunity-queries.d.ts +285 -0
- package/dist/shared/interfaces/database.opportunity-queries.js +4 -0
- package/dist/shared/interfaces/database.port.d.ts +322 -0
- package/dist/shared/interfaces/database.port.js +29 -0
- package/dist/shared/schemas/discovery-question.schema.d.ts +14 -14
- package/dist/shared/schemas/negotiation-digest.schema.d.ts +2 -2
- package/package.json +2 -15
- package/dist/contacts/application/contact.inviter.d.ts +0 -49
- package/dist/contacts/application/contact.inviter.js +0 -64
- package/dist/integrations/application/index.d.ts +0 -14
- package/dist/integrations/application/index.js +0 -14
- package/dist/integrations/application/integration.tools.d.ts +0 -27
- package/dist/integrations/application/integration.tools.js +0 -98
- package/dist/integrations/domain/index.d.ts +0 -16
- package/dist/integrations/domain/index.js +0 -1
- package/dist/integrations/domain/integration.types.d.ts +0 -51
- package/dist/integrations/domain/integration.types.js +0 -9
- package/dist/integrations/index.d.ts +0 -10
- package/dist/integrations/index.js +0 -8
- package/dist/integrations/ports/index.d.ts +0 -25
- package/dist/integrations/ports/index.js +0 -23
- package/dist/integrations/ports/integration.adapter.port.d.ts +0 -62
- package/dist/integrations/ports/integration.adapter.port.js +0 -15
- package/dist/integrations/ports/integration.importer.port.d.ts +0 -31
- package/dist/integrations/ports/integration.importer.port.js +0 -15
- package/dist/integrations/ports/integration.tools.port.d.ts +0 -25
- package/dist/integrations/ports/integration.tools.port.js +0 -18
- package/dist/opportunities/application/opportunity.card-presentation.d.ts +0 -44
- package/dist/opportunities/application/opportunity.card-presentation.js +0 -93
- package/dist/opportunities/application/opportunity.presenter.d.ts +0 -156
- package/dist/opportunities/domain/opportunity.presentation-cache.d.ts +0 -5
- package/dist/opportunities/domain/opportunity.presentation-cache.js +0 -11
- package/dist/opportunities/domain/opportunity.presentation.d.ts +0 -76
- package/dist/opportunities/domain/opportunity.presentation.js +0 -516
- package/dist/opportunities/domain/opportunity.safe-presentation.d.ts +0 -104
- package/dist/opportunities/domain/opportunity.safe-presentation.js +0 -102
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent graph, stage 4 and the read fast path.
|
|
3
|
+
*/
|
|
4
|
+
import { ExecutionResult } from "../domain/intent.state.js";
|
|
5
|
+
import { type IntentGraphDeps, type IntentState } from "./intent.graph.shared.js";
|
|
6
|
+
/**
|
|
7
|
+
* Node 4: Executor
|
|
8
|
+
* Executes reconciler actions against the database.
|
|
9
|
+
*/
|
|
10
|
+
export declare function executorNode(state: IntentState, deps: IntentGraphDeps): Promise<{
|
|
11
|
+
executionResults: ExecutionResult[];
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Node: Query
|
|
15
|
+
* Fast-path read node — fetches intents from DB based on scope.
|
|
16
|
+
* Handles: global user intents, network-scoped (all or filtered by user).
|
|
17
|
+
* No LLM calls; no inference/verification/reconciliation.
|
|
18
|
+
*/
|
|
19
|
+
export declare function queryNode(state: IntentState, deps: IntentGraphDeps): Promise<{
|
|
20
|
+
readResult: {
|
|
21
|
+
count: number;
|
|
22
|
+
intents: never[];
|
|
23
|
+
message: string;
|
|
24
|
+
networkId?: undefined;
|
|
25
|
+
};
|
|
26
|
+
} | {
|
|
27
|
+
readResult: {
|
|
28
|
+
count: number;
|
|
29
|
+
intents: {
|
|
30
|
+
id: string;
|
|
31
|
+
description: string;
|
|
32
|
+
summary: string | null;
|
|
33
|
+
createdAt: Date;
|
|
34
|
+
}[];
|
|
35
|
+
message?: undefined;
|
|
36
|
+
networkId?: undefined;
|
|
37
|
+
};
|
|
38
|
+
} | {
|
|
39
|
+
readResult: {
|
|
40
|
+
count: number;
|
|
41
|
+
intents: never[];
|
|
42
|
+
message: string;
|
|
43
|
+
networkId: string;
|
|
44
|
+
};
|
|
45
|
+
} | {
|
|
46
|
+
readResult: {
|
|
47
|
+
count: number;
|
|
48
|
+
networkId: string;
|
|
49
|
+
intents: {
|
|
50
|
+
id: string;
|
|
51
|
+
description: string;
|
|
52
|
+
summary: string | null;
|
|
53
|
+
createdAt: Date;
|
|
54
|
+
userId: string;
|
|
55
|
+
userName: string | null;
|
|
56
|
+
}[];
|
|
57
|
+
message?: undefined;
|
|
58
|
+
};
|
|
59
|
+
}>;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent graph, stage 4 and the read fast path.
|
|
3
|
+
*/
|
|
4
|
+
import { normalizeIntentDescription } from "../domain/intent.proposal.js";
|
|
5
|
+
import { timed } from "../../shared/observability/performance.js";
|
|
6
|
+
import { enforceIntentActionBoundary, generateIntentEmbedding, logger, toSpeechActType } from "./intent.graph.shared.js";
|
|
7
|
+
/**
|
|
8
|
+
* Node 4: Executor
|
|
9
|
+
* Executes reconciler actions against the database.
|
|
10
|
+
*/
|
|
11
|
+
export async function executorNode(state, deps) {
|
|
12
|
+
return timed("IntentGraph.executor", async () => {
|
|
13
|
+
const actions = enforceIntentActionBoundary(state.operationMode, state.targetIntentIds, state.actions ?? []);
|
|
14
|
+
if (actions.length === 0) {
|
|
15
|
+
return { executionResults: [] };
|
|
16
|
+
}
|
|
17
|
+
logger.verbose('Executing actions', { count: actions.length });
|
|
18
|
+
const results = [];
|
|
19
|
+
const scopeEnvelope = state.scopeType && state.scopeId
|
|
20
|
+
? { scopeType: state.scopeType, scopeId: state.scopeId }
|
|
21
|
+
: {};
|
|
22
|
+
const verifiedIntentByPayload = new Map();
|
|
23
|
+
for (const verifiedIntent of state.verifiedIntents) {
|
|
24
|
+
verifiedIntentByPayload.set(verifiedIntent.description, verifiedIntent);
|
|
25
|
+
verifiedIntentByPayload.set(normalizeIntentDescription(verifiedIntent.description), verifiedIntent);
|
|
26
|
+
}
|
|
27
|
+
for (const action of actions) {
|
|
28
|
+
const actionType = action.type.toLowerCase();
|
|
29
|
+
try {
|
|
30
|
+
if (actionType === 'create') {
|
|
31
|
+
const createAction = action;
|
|
32
|
+
const sanitizedPayload = normalizeIntentDescription(createAction.payload);
|
|
33
|
+
const matchedVerifiedIntent = verifiedIntentByPayload.get(createAction.payload) ||
|
|
34
|
+
verifiedIntentByPayload.get(sanitizedPayload);
|
|
35
|
+
// Generate embedding for the intent payload
|
|
36
|
+
const flatEmbedding = await generateIntentEmbedding(deps, sanitizedPayload);
|
|
37
|
+
const created = await deps.database.createIntent({
|
|
38
|
+
userId: state.userId,
|
|
39
|
+
payload: sanitizedPayload,
|
|
40
|
+
confidence: createAction.score ? createAction.score / 100 : 1.0,
|
|
41
|
+
inferenceType: 'explicit',
|
|
42
|
+
sourceType: 'discovery_form',
|
|
43
|
+
embedding: flatEmbedding,
|
|
44
|
+
semanticEntropy: createAction.semanticEntropy ??
|
|
45
|
+
matchedVerifiedIntent?.verification?.semantic_entropy ??
|
|
46
|
+
null,
|
|
47
|
+
referentialAnchor: createAction.referentialAnchor ??
|
|
48
|
+
matchedVerifiedIntent?.verification?.referential_anchor ??
|
|
49
|
+
null,
|
|
50
|
+
felicityAuthority: matchedVerifiedIntent?.verification?.felicity_scores.authority ?? null,
|
|
51
|
+
felicitySincerity: matchedVerifiedIntent?.verification?.felicity_scores.sincerity ?? null,
|
|
52
|
+
felicityClarity: matchedVerifiedIntent?.verification?.felicity_scores.clarity ?? null,
|
|
53
|
+
intentMode: createAction.intentMode ?? null,
|
|
54
|
+
speechActType: toSpeechActType(matchedVerifiedIntent?.verification?.classification),
|
|
55
|
+
});
|
|
56
|
+
results.push({ actionType: 'create', success: true, intentId: created.id, payload: sanitizedPayload });
|
|
57
|
+
logger.verbose('Created intent', { intentId: created.id });
|
|
58
|
+
deps.intentQueue?.addGenerateHydeJob({
|
|
59
|
+
intentId: created.id,
|
|
60
|
+
userId: state.userId,
|
|
61
|
+
...scopeEnvelope,
|
|
62
|
+
}).catch((err) => logger.error('Failed to enqueue intent HyDE job', { intentId: created.id, error: err }));
|
|
63
|
+
if (deps.questionerEnqueue) {
|
|
64
|
+
const userContext = (await deps.database.getUserContext(state.userId, null))?.text ?? '';
|
|
65
|
+
deps.questionerEnqueue({
|
|
66
|
+
mode: 'intent',
|
|
67
|
+
userId: state.userId,
|
|
68
|
+
sourceType: 'intent',
|
|
69
|
+
sourceId: created.id,
|
|
70
|
+
...scopeEnvelope,
|
|
71
|
+
context: {
|
|
72
|
+
intentId: created.id,
|
|
73
|
+
payload: sanitizedPayload,
|
|
74
|
+
userContext,
|
|
75
|
+
},
|
|
76
|
+
}).catch((err) => logger.error('Failed to enqueue intent question generation', { intentId: created.id, error: err }));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (actionType === 'update') {
|
|
80
|
+
const updateAction = action;
|
|
81
|
+
const sanitizedPayload = normalizeIntentDescription(updateAction.payload);
|
|
82
|
+
const matchedVerifiedIntent = verifiedIntentByPayload.get(updateAction.payload) ||
|
|
83
|
+
verifiedIntentByPayload.get(sanitizedPayload);
|
|
84
|
+
// Regenerate embedding for the updated payload
|
|
85
|
+
const flatEmbedding = await generateIntentEmbedding(deps, sanitizedPayload, updateAction.id);
|
|
86
|
+
const updated = await deps.database.updateIntent(updateAction.id, {
|
|
87
|
+
payload: sanitizedPayload,
|
|
88
|
+
embedding: flatEmbedding,
|
|
89
|
+
semanticEntropy: matchedVerifiedIntent?.verification?.semantic_entropy ??
|
|
90
|
+
null,
|
|
91
|
+
referentialAnchor: matchedVerifiedIntent?.verification?.referential_anchor ??
|
|
92
|
+
null,
|
|
93
|
+
felicityAuthority: matchedVerifiedIntent?.verification?.felicity_scores.authority ?? null,
|
|
94
|
+
felicitySincerity: matchedVerifiedIntent?.verification?.felicity_scores.sincerity ?? null,
|
|
95
|
+
felicityClarity: matchedVerifiedIntent?.verification?.felicity_scores.clarity ?? null,
|
|
96
|
+
intentMode: updateAction.intentMode ?? null,
|
|
97
|
+
speechActType: toSpeechActType(matchedVerifiedIntent?.verification?.classification),
|
|
98
|
+
...(state.expectedIntentFingerprint !== undefined ? {
|
|
99
|
+
expectedIntentFingerprint: state.expectedIntentFingerprint,
|
|
100
|
+
expectedIntentUserId: state.userId,
|
|
101
|
+
} : {}),
|
|
102
|
+
});
|
|
103
|
+
results.push({
|
|
104
|
+
actionType: 'update',
|
|
105
|
+
success: !!updated,
|
|
106
|
+
intentId: updateAction.id,
|
|
107
|
+
payload: sanitizedPayload,
|
|
108
|
+
error: updated ? undefined : 'Intent not found'
|
|
109
|
+
});
|
|
110
|
+
logger.verbose('Updated intent', { intentId: updateAction.id });
|
|
111
|
+
if (updated) {
|
|
112
|
+
deps.intentQueue?.addGenerateHydeJob({
|
|
113
|
+
intentId: updateAction.id,
|
|
114
|
+
userId: state.userId,
|
|
115
|
+
...scopeEnvelope,
|
|
116
|
+
}).catch((err) => logger.error('Failed to enqueue intent HyDE job', { intentId: updateAction.id, error: err }));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (actionType === 'expire') {
|
|
120
|
+
const expireAction = action;
|
|
121
|
+
const result = await deps.database.archiveIntent(expireAction.id);
|
|
122
|
+
results.push({
|
|
123
|
+
actionType: 'expire',
|
|
124
|
+
success: result.success,
|
|
125
|
+
intentId: expireAction.id,
|
|
126
|
+
error: result.error
|
|
127
|
+
});
|
|
128
|
+
logger.verbose('Archived intent', { intentId: expireAction.id });
|
|
129
|
+
if (result.success) {
|
|
130
|
+
deps.intentQueue?.addDeleteHydeJob({ intentId: expireAction.id }).catch((err) => logger.error('Failed to enqueue intent HyDE delete job', { intentId: expireAction.id, error: err }));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
logger.error('Failed to execute action', { actionType: action.type, error });
|
|
136
|
+
results.push({
|
|
137
|
+
actionType,
|
|
138
|
+
success: false,
|
|
139
|
+
intentId: 'id' in action ? action.id : undefined,
|
|
140
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { executionResults: results };
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Node: Query
|
|
149
|
+
* Fast-path read node — fetches intents from DB based on scope.
|
|
150
|
+
* Handles: global user intents, network-scoped (all or filtered by user).
|
|
151
|
+
* No LLM calls; no inference/verification/reconciliation.
|
|
152
|
+
*/
|
|
153
|
+
export async function queryNode(state, deps) {
|
|
154
|
+
return timed("IntentGraph.query", async () => {
|
|
155
|
+
logger.verbose("Starting query (read mode)", {
|
|
156
|
+
userId: state.userId,
|
|
157
|
+
networkId: state.networkId,
|
|
158
|
+
queryUserId: state.queryUserId,
|
|
159
|
+
allUserIntents: state.allUserIntents,
|
|
160
|
+
});
|
|
161
|
+
try {
|
|
162
|
+
// Scope-aware default: caller's intents across all reachable networks.
|
|
163
|
+
// Triggered when the tool layer passed indexScope and did not pick a
|
|
164
|
+
// specific networkId or queryUserId — i.e. "my intents" in a chat
|
|
165
|
+
// where the agent's reach is more than one index.
|
|
166
|
+
if (!state.queryUserId &&
|
|
167
|
+
!state.networkId &&
|
|
168
|
+
state.indexScope &&
|
|
169
|
+
state.indexScope.length > 0) {
|
|
170
|
+
const intents = await deps.database.getActiveIntentsAcrossIndexes(state.userId, state.indexScope);
|
|
171
|
+
if (intents.length === 0) {
|
|
172
|
+
return {
|
|
173
|
+
readResult: {
|
|
174
|
+
count: 0,
|
|
175
|
+
intents: [],
|
|
176
|
+
message: "You don't have any active intents yet. Share what you're looking for.",
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
readResult: {
|
|
182
|
+
count: intents.length,
|
|
183
|
+
intents: intents.map((i) => ({
|
|
184
|
+
id: i.id,
|
|
185
|
+
description: i.payload,
|
|
186
|
+
summary: i.summary,
|
|
187
|
+
createdAt: i.createdAt,
|
|
188
|
+
})),
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
// When allUserIntents is true, ignore network scope and return all
|
|
193
|
+
const effectiveIndexId = state.allUserIntents ? undefined : state.networkId;
|
|
194
|
+
if (effectiveIndexId) {
|
|
195
|
+
// Verify membership
|
|
196
|
+
const isMember = await deps.database.isNetworkMember(effectiveIndexId, state.userId);
|
|
197
|
+
if (!isMember) {
|
|
198
|
+
return {
|
|
199
|
+
readResult: {
|
|
200
|
+
count: 0,
|
|
201
|
+
intents: [],
|
|
202
|
+
message: "Index not found or you are not a member.",
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// Network-scoped read
|
|
207
|
+
if (!state.queryUserId) {
|
|
208
|
+
// All intents in the index (any member can see)
|
|
209
|
+
const intents = await deps.database.getNetworkIntentsForMember(effectiveIndexId, state.userId, { limit: 50, offset: 0 });
|
|
210
|
+
if (intents.length === 0) {
|
|
211
|
+
return {
|
|
212
|
+
readResult: {
|
|
213
|
+
count: 0,
|
|
214
|
+
intents: [],
|
|
215
|
+
message: "No intents in this network yet.",
|
|
216
|
+
networkId: effectiveIndexId,
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
readResult: {
|
|
222
|
+
count: intents.length,
|
|
223
|
+
networkId: effectiveIndexId,
|
|
224
|
+
intents: intents.map((i) => ({
|
|
225
|
+
id: i.id,
|
|
226
|
+
description: i.payload,
|
|
227
|
+
summary: i.summary,
|
|
228
|
+
createdAt: i.createdAt,
|
|
229
|
+
userId: i.userId,
|
|
230
|
+
userName: i.userName,
|
|
231
|
+
})),
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
// Specific user's intents in the index
|
|
236
|
+
const effectiveUserId = state.queryUserId;
|
|
237
|
+
const intents = await deps.database.getIntentsInIndexForMember(effectiveUserId, effectiveIndexId);
|
|
238
|
+
if (intents.length === 0) {
|
|
239
|
+
return {
|
|
240
|
+
readResult: {
|
|
241
|
+
count: 0,
|
|
242
|
+
intents: [],
|
|
243
|
+
message: effectiveUserId === state.userId
|
|
244
|
+
? "You don't have any intents in this network yet."
|
|
245
|
+
: "No intents for that user in this network.",
|
|
246
|
+
networkId: effectiveIndexId,
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const user = await deps.database.getUser(effectiveUserId);
|
|
251
|
+
const userName = user?.name ?? null;
|
|
252
|
+
return {
|
|
253
|
+
readResult: {
|
|
254
|
+
count: intents.length,
|
|
255
|
+
networkId: effectiveIndexId,
|
|
256
|
+
intents: intents.map((i) => ({
|
|
257
|
+
id: i.id,
|
|
258
|
+
description: i.payload,
|
|
259
|
+
summary: i.summary,
|
|
260
|
+
createdAt: i.createdAt,
|
|
261
|
+
userId: effectiveUserId,
|
|
262
|
+
userName,
|
|
263
|
+
})),
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
// Global (no network scope): return user's own active intents
|
|
268
|
+
const intents = await deps.database.getActiveIntents(state.userId);
|
|
269
|
+
if (intents.length === 0) {
|
|
270
|
+
return {
|
|
271
|
+
readResult: {
|
|
272
|
+
count: 0,
|
|
273
|
+
intents: [],
|
|
274
|
+
message: "You don't have any active intents yet. Share what you're looking for.",
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
readResult: {
|
|
280
|
+
count: intents.length,
|
|
281
|
+
intents: intents.map((i) => ({
|
|
282
|
+
id: i.id,
|
|
283
|
+
description: i.payload,
|
|
284
|
+
summary: i.summary,
|
|
285
|
+
createdAt: i.createdAt,
|
|
286
|
+
})),
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
logger.error("Query node failed", { error: err });
|
|
292
|
+
return {
|
|
293
|
+
readResult: {
|
|
294
|
+
count: 0,
|
|
295
|
+
intents: [],
|
|
296
|
+
message: "Failed to fetch intents. Please try again.",
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent graph, stages 0-1: load the user's signals, then infer new ones.
|
|
3
|
+
*/
|
|
4
|
+
import type { DebugMetaAgent } from "../../agents/index.js";
|
|
5
|
+
import { type IntentGraphDeps, type IntentState } from "./intent.graph.shared.js";
|
|
6
|
+
/**
|
|
7
|
+
* Node 0: Prep
|
|
8
|
+
* Always fetches ALL of the user's active intents from the DB via getActiveIntents(userId).
|
|
9
|
+
* This ensures reconciliation can detect duplicates and modifications globally,
|
|
10
|
+
* regardless of network scope.
|
|
11
|
+
*/
|
|
12
|
+
export declare function prepNode(state: IntentState, deps: IntentGraphDeps): Promise<{
|
|
13
|
+
error: string;
|
|
14
|
+
activeIntents?: undefined;
|
|
15
|
+
activeIntentIds?: undefined;
|
|
16
|
+
trace?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
activeIntents: string;
|
|
19
|
+
activeIntentIds: string[];
|
|
20
|
+
trace: {
|
|
21
|
+
node: string;
|
|
22
|
+
detail: string;
|
|
23
|
+
}[];
|
|
24
|
+
error?: undefined;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Node 1: Inference
|
|
28
|
+
* Extracts intents from raw content.
|
|
29
|
+
* Phase 4: Uses operation mode to control behavior and determine if node should execute.
|
|
30
|
+
* Phase 5: Passes conversation context for anaphoric resolution.
|
|
31
|
+
*/
|
|
32
|
+
export declare function inferenceNode(state: IntentState, deps: IntentGraphDeps): Promise<{
|
|
33
|
+
inferredIntents: {
|
|
34
|
+
reasoning: string;
|
|
35
|
+
type: "goal" | "tombstone";
|
|
36
|
+
confidence: "low" | "medium" | "high";
|
|
37
|
+
description: string;
|
|
38
|
+
}[];
|
|
39
|
+
agentTimings: DebugMetaAgent[];
|
|
40
|
+
trace: {
|
|
41
|
+
node: string;
|
|
42
|
+
detail: string;
|
|
43
|
+
}[];
|
|
44
|
+
}>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent graph, stages 0-1: load the user's signals, then infer new ones.
|
|
3
|
+
*/
|
|
4
|
+
import { timed } from "../../shared/observability/performance.js";
|
|
5
|
+
import { requestContext } from "../../shared/observability/request-context.js";
|
|
6
|
+
import { logger } from "./intent.graph.shared.js";
|
|
7
|
+
/**
|
|
8
|
+
* Node 0: Prep
|
|
9
|
+
* Always fetches ALL of the user's active intents from the DB via getActiveIntents(userId).
|
|
10
|
+
* This ensures reconciliation can detect duplicates and modifications globally,
|
|
11
|
+
* regardless of network scope.
|
|
12
|
+
*/
|
|
13
|
+
export async function prepNode(state, deps) {
|
|
14
|
+
return timed("IntentGraph.prep", async () => {
|
|
15
|
+
logger.verbose("Starting preparation phase", {
|
|
16
|
+
operationMode: state.operationMode,
|
|
17
|
+
hasContent: !!state.inputContent,
|
|
18
|
+
targetIntentIds: state.targetIntentIds,
|
|
19
|
+
networkId: state.networkId,
|
|
20
|
+
});
|
|
21
|
+
// Gate: write operations require an existing profile
|
|
22
|
+
if (state.operationMode !== 'read') {
|
|
23
|
+
const profile = await deps.database.getProfile(state.userId);
|
|
24
|
+
if (!profile) {
|
|
25
|
+
const msg = "You need to create a profile before creating intents. Please set up your profile first.";
|
|
26
|
+
logger.error("Prep failed: no profile for user", { userId: state.userId });
|
|
27
|
+
return { error: msg };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const activeIntents = await deps.database.getActiveIntents(state.userId);
|
|
31
|
+
const formattedActiveIntents = activeIntents
|
|
32
|
+
.map(i => `ID: ${i.id}, Description: ${i.payload}, Summary: ${i.summary || 'N/A'}`)
|
|
33
|
+
.join('\n') || "No active intents.";
|
|
34
|
+
logger.verbose("Fetched active intents", {
|
|
35
|
+
count: activeIntents.length,
|
|
36
|
+
operationMode: state.operationMode
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
activeIntents: formattedActiveIntents,
|
|
40
|
+
activeIntentIds: activeIntents.map((intent) => intent.id),
|
|
41
|
+
trace: [{
|
|
42
|
+
node: "prep",
|
|
43
|
+
detail: `Fetched ${activeIntents.length} active intent(s)`,
|
|
44
|
+
}],
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Node 1: Inference
|
|
50
|
+
* Extracts intents from raw content.
|
|
51
|
+
* Phase 4: Uses operation mode to control behavior and determine if node should execute.
|
|
52
|
+
* Phase 5: Passes conversation context for anaphoric resolution.
|
|
53
|
+
*/
|
|
54
|
+
export async function inferenceNode(state, deps) {
|
|
55
|
+
return timed("IntentGraph.inference", async () => {
|
|
56
|
+
logger.verbose("Starting inference", {
|
|
57
|
+
operationMode: state.operationMode,
|
|
58
|
+
hasContent: !!state.inputContent,
|
|
59
|
+
contentPreview: state.inputContent?.substring(0, 50),
|
|
60
|
+
hasConversationContext: !!state.conversationContext,
|
|
61
|
+
conversationMessagesCount: state.conversationContext?.length || 0
|
|
62
|
+
});
|
|
63
|
+
const agentTimingsAccum = [];
|
|
64
|
+
// Phase 4: Control profile fallback based on operation mode
|
|
65
|
+
// Only allow for create operations without explicit content
|
|
66
|
+
const allowProfileFallback = state.operationMode === 'create' && !state.inputContent;
|
|
67
|
+
// Cast operationMode: 'read' and 'propose' map to 'create' for the deps.inferrer
|
|
68
|
+
// (inference node is never called in read mode; propose behaves like create for inference)
|
|
69
|
+
const inferrerMode = (state.operationMode === 'read' || state.operationMode === 'propose') ? 'create' : state.operationMode;
|
|
70
|
+
const _traceEmitterInferrer = requestContext.getStore()?.traceEmitter;
|
|
71
|
+
const inferrerStart = Date.now();
|
|
72
|
+
_traceEmitterInferrer?.({ type: "agent_start", name: "intent-inferrer" });
|
|
73
|
+
const result = await deps.inferrer.invoke(state.inputContent || null, state.userProfile, {
|
|
74
|
+
allowProfileFallback,
|
|
75
|
+
operationMode: inferrerMode,
|
|
76
|
+
conversationContext: state.conversationContext // Phase 5: Pass conversation history
|
|
77
|
+
});
|
|
78
|
+
agentTimingsAccum.push({ name: 'intent.inferrer', durationMs: Date.now() - inferrerStart });
|
|
79
|
+
_traceEmitterInferrer?.({ type: "agent_end", name: "intent-inferrer", durationMs: Date.now() - inferrerStart, summary: result.intents.length > 0 ? `Extracted ${result.intents.length} intent(s)` : "intent-inferrer completed" });
|
|
80
|
+
logger.verbose("Inference complete", {
|
|
81
|
+
inferredCount: result.intents.length,
|
|
82
|
+
operationMode: state.operationMode
|
|
83
|
+
});
|
|
84
|
+
const descriptions = result.intents.map(i => i.description).slice(0, 3);
|
|
85
|
+
const truncated = result.intents.length > 3 ? `... +${result.intents.length - 3} more` : "";
|
|
86
|
+
return {
|
|
87
|
+
inferredIntents: result.intents,
|
|
88
|
+
agentTimings: agentTimingsAccum,
|
|
89
|
+
trace: [{
|
|
90
|
+
node: "inference",
|
|
91
|
+
detail: result.intents.length === 0
|
|
92
|
+
? "No intents extracted"
|
|
93
|
+
: `Extracted ${result.intents.length}: ${descriptions.map(d => `"${d.slice(0, 50)}${d.length > 50 ? '...' : ''}"`).join(", ")}${truncated}`,
|
|
94
|
+
}],
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
}
|