@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
|
@@ -120,343 +120,23 @@ function isRuntimeVerdict(value) {
|
|
|
120
120
|
/** Factory for the HyDE generation graph. Existing five-argument calls remain valid. */
|
|
121
121
|
export class HydeGraphFactory {
|
|
122
122
|
constructor(database, embedder, cache, inferrer, generator, options = {}) {
|
|
123
|
-
|
|
124
|
-
this.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
123
|
+
const mode = options.mode ?? getHydeGenerationMode();
|
|
124
|
+
this.deps = {
|
|
125
|
+
database, embedder, cache, inferrer, generator, options, mode,
|
|
126
|
+
...(mode === HYDE_FRAME_GENERATION_VERSION
|
|
127
|
+
? { validator: options.validator ?? new HydeValidator() }
|
|
128
|
+
: {}),
|
|
129
|
+
};
|
|
129
130
|
}
|
|
130
131
|
createGraph() {
|
|
131
|
-
const
|
|
132
|
-
const mode =
|
|
133
|
-
const validator = mode === HYDE_FRAME_GENERATION_VERSION
|
|
134
|
-
? (this.options.validator ?? new HydeValidator())
|
|
135
|
-
: undefined;
|
|
136
|
-
/** Node 1: Infer lenses from source text + optional profile context. */
|
|
137
|
-
const inferLensesNode = async (state) => {
|
|
138
|
-
return timed("HydeGraph.inferLenses", async () => {
|
|
139
|
-
const { sourceText, profileContext, maxLenses } = state;
|
|
140
|
-
const agentTimingsAccum = [];
|
|
141
|
-
try {
|
|
142
|
-
const traceEmitter = requestContext.getStore()?.traceEmitter;
|
|
143
|
-
const inferrerStart = Date.now();
|
|
144
|
-
traceEmitter?.({ type: "agent_start", name: "lens-inferrer" });
|
|
145
|
-
const result = await self.inferrer.infer({
|
|
146
|
-
sourceText,
|
|
147
|
-
profileContext,
|
|
148
|
-
maxLenses,
|
|
149
|
-
...(mode === HYDE_FRAME_GENERATION_VERSION ? { frameConstrained: true } : {}),
|
|
150
|
-
});
|
|
151
|
-
const durationMs = Date.now() - inferrerStart;
|
|
152
|
-
agentTimingsAccum.push({ name: 'lens.inferrer', durationMs });
|
|
153
|
-
traceEmitter?.({ type: "agent_end", name: "lens-inferrer", durationMs, summary: result.lenses.length > 0 ? `Inferred ${result.lenses.length} lens(es)` : "lens-inferrer completed" });
|
|
154
|
-
if (mode === HYDE_FRAME_GENERATION_VERSION) {
|
|
155
|
-
const sourceFrame = sanitizeHydeSourceFrame(sourceText, result.sourceFrame ?? emptyFrame());
|
|
156
|
-
return {
|
|
157
|
-
lenses: result.lenses,
|
|
158
|
-
sourceFrame,
|
|
159
|
-
frameFingerprint: computeHydeFrameFingerprint(sourceText, sourceFrame),
|
|
160
|
-
sourceTextHash: computeHydeSourceTextHash(sourceText),
|
|
161
|
-
generatedAt: nextGenerationMarker(),
|
|
162
|
-
agentTimings: agentTimingsAccum,
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
return { lenses: result.lenses, agentTimings: agentTimingsAccum };
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
logger.error('Lens inference failed in graph node', { error });
|
|
169
|
-
if (mode === HYDE_FRAME_GENERATION_VERSION) {
|
|
170
|
-
const sourceFrame = emptyFrame();
|
|
171
|
-
return {
|
|
172
|
-
lenses: [],
|
|
173
|
-
sourceFrame,
|
|
174
|
-
frameFingerprint: computeHydeFrameFingerprint(sourceText, sourceFrame),
|
|
175
|
-
sourceTextHash: computeHydeSourceTextHash(sourceText),
|
|
176
|
-
generatedAt: nextGenerationMarker(),
|
|
177
|
-
agentTimings: agentTimingsAccum,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
return { lenses: [], agentTimings: agentTimingsAccum };
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
/** Node 2: Check the mode-isolated cache/DB for matching documents. */
|
|
185
|
-
const checkCacheNode = async (state) => {
|
|
186
|
-
return timed("HydeGraph.checkCache", async () => {
|
|
187
|
-
const { sourceType, sourceId, sourceText, lenses, forceRegenerate } = state;
|
|
188
|
-
if (forceRegenerate)
|
|
189
|
-
return { hydeDocuments: {} };
|
|
190
|
-
const frameFingerprint = mode === HYDE_FRAME_GENERATION_VERSION
|
|
191
|
-
? requireFrameFingerprint(state.frameFingerprint)
|
|
192
|
-
: undefined;
|
|
193
|
-
const sourceTextHash = mode === HYDE_FRAME_GENERATION_VERSION
|
|
194
|
-
? state.sourceTextHash ?? computeHydeSourceTextHash(sourceText)
|
|
195
|
-
: undefined;
|
|
196
|
-
const cached = {};
|
|
197
|
-
for (const lens of lenses) {
|
|
198
|
-
const key = cacheKey(mode, sourceType, sourceId ?? undefined, sourceText, lens.label, lens.corpus, frameFingerprint);
|
|
199
|
-
const fromCache = await self.cache.get(key);
|
|
200
|
-
const cacheAccepted = fromCache?.hydeText
|
|
201
|
-
&& fromCache.hydeEmbedding?.length
|
|
202
|
-
&& (mode === 'legacy' || isFrameCacheDocument(fromCache, lens.label, frameFingerprint, sourceTextHash));
|
|
203
|
-
if (cacheAccepted && fromCache) {
|
|
204
|
-
cached[lens.label] = {
|
|
205
|
-
...fromCache,
|
|
206
|
-
...(mode === HYDE_FRAME_GENERATION_VERSION ? { origin: 'cache' } : {}),
|
|
207
|
-
};
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
if (sourceId) {
|
|
211
|
-
const fromDb = await self.database.getHydeDocument(sourceType, sourceId, dbStrategy(mode, lens.label, lens.corpus));
|
|
212
|
-
const frameDbContext = mode === HYDE_FRAME_GENERATION_VERSION && fromDb
|
|
213
|
-
? fromDb.context
|
|
214
|
-
: null;
|
|
215
|
-
if (fromDb && (mode === 'legacy' || isFrameDbContext(frameDbContext, lens.label, frameFingerprint, sourceTextHash))) {
|
|
216
|
-
cached[lens.label] = {
|
|
217
|
-
lens: lens.label,
|
|
218
|
-
targetCorpus: fromDb.targetCorpus,
|
|
219
|
-
hydeText: fromDb.hydeText,
|
|
220
|
-
hydeEmbedding: fromDb.hydeEmbedding,
|
|
221
|
-
...(mode === HYDE_FRAME_GENERATION_VERSION
|
|
222
|
-
? {
|
|
223
|
-
origin: 'db',
|
|
224
|
-
validationStatus: 'valid',
|
|
225
|
-
hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION,
|
|
226
|
-
frameFingerprint,
|
|
227
|
-
sourceTextHash,
|
|
228
|
-
generatedAt: frameDbContext.generatedAt,
|
|
229
|
-
}
|
|
230
|
-
: {}),
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
if (mode === HYDE_FRAME_GENERATION_VERSION) {
|
|
236
|
-
const newestTimestamp = Math.max(...Object.values(cached).map((doc) => Date.parse(doc.generatedAt ?? '')));
|
|
237
|
-
if (Number.isFinite(newestTimestamp)) {
|
|
238
|
-
return {
|
|
239
|
-
hydeDocuments: Object.fromEntries(Object.entries(cached).filter(([, doc]) => Date.parse(doc.generatedAt ?? '') === newestTimestamp)),
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return { hydeDocuments: cached };
|
|
244
|
-
});
|
|
245
|
-
};
|
|
246
|
-
const shouldGenerate = (state) => state.lenses.some((lens) => !state.hydeDocuments[lens.label]) ? 'generate' : 'skip';
|
|
247
|
-
/** Node 3: Generate all missing documents and return a complete snapshot. */
|
|
248
|
-
const generateMissingNode = async (state) => {
|
|
249
|
-
return timed("HydeGraph.generateMissing", async () => {
|
|
250
|
-
const { sourceText, sourceFrame, lenses, hydeDocuments } = state;
|
|
251
|
-
const missing = lenses.filter((lens) => !hydeDocuments[lens.label]);
|
|
252
|
-
const agentTimingsAccum = [];
|
|
253
|
-
const generated = {};
|
|
254
|
-
const sourceTextHash = mode === HYDE_FRAME_GENERATION_VERSION
|
|
255
|
-
? state.sourceTextHash ?? computeHydeSourceTextHash(sourceText)
|
|
256
|
-
: undefined;
|
|
257
|
-
const generatedAt = mode === HYDE_FRAME_GENERATION_VERSION
|
|
258
|
-
? state.generatedAt ?? nextGenerationMarker()
|
|
259
|
-
: undefined;
|
|
260
|
-
await Promise.all(missing.map(async (lens) => {
|
|
261
|
-
const traceEmitter = requestContext.getStore()?.traceEmitter;
|
|
262
|
-
const generatorStart = Date.now();
|
|
263
|
-
traceEmitter?.({ type: "agent_start", name: "hyde-generator" });
|
|
264
|
-
const out = await self.generator.generate({
|
|
265
|
-
sourceText,
|
|
266
|
-
lens: lens.label,
|
|
267
|
-
corpus: lens.corpus,
|
|
268
|
-
...(mode === HYDE_FRAME_GENERATION_VERSION && sourceFrame ? { sourceFrame } : {}),
|
|
269
|
-
});
|
|
270
|
-
const durationMs = Date.now() - generatorStart;
|
|
271
|
-
agentTimingsAccum.push({ name: 'hyde.generator', durationMs });
|
|
272
|
-
traceEmitter?.({ type: "agent_end", name: "hyde-generator", durationMs, summary: `Generated: ${lens.label}` });
|
|
273
|
-
generated[lens.label] = {
|
|
274
|
-
lens: lens.label,
|
|
275
|
-
targetCorpus: lens.corpus,
|
|
276
|
-
hydeText: out.text,
|
|
277
|
-
hydeEmbedding: [],
|
|
278
|
-
...(mode === HYDE_FRAME_GENERATION_VERSION
|
|
279
|
-
? {
|
|
280
|
-
origin: 'generated',
|
|
281
|
-
frameFingerprint: requireFrameFingerprint(state.frameFingerprint),
|
|
282
|
-
sourceTextHash,
|
|
283
|
-
generatedAt,
|
|
284
|
-
}
|
|
285
|
-
: {}),
|
|
286
|
-
};
|
|
287
|
-
}));
|
|
288
|
-
const retained = mode === HYDE_FRAME_GENERATION_VERSION
|
|
289
|
-
? Object.fromEntries(Object.entries(hydeDocuments).map(([label, doc]) => [
|
|
290
|
-
label,
|
|
291
|
-
{
|
|
292
|
-
...doc,
|
|
293
|
-
frameFingerprint: requireFrameFingerprint(state.frameFingerprint),
|
|
294
|
-
sourceTextHash,
|
|
295
|
-
generatedAt,
|
|
296
|
-
},
|
|
297
|
-
]))
|
|
298
|
-
: hydeDocuments;
|
|
299
|
-
return { hydeDocuments: { ...retained, ...generated }, agentTimings: agentTimingsAccum };
|
|
300
|
-
});
|
|
301
|
-
};
|
|
302
|
-
/** Frame-v1 only: validate newly generated docs in one batch. */
|
|
303
|
-
const validateGeneratedNode = async (state) => {
|
|
304
|
-
return timed("HydeGraph.validateGenerated", async () => {
|
|
305
|
-
const generated = Object.values(state.hydeDocuments).filter((doc) => doc.origin === 'generated');
|
|
306
|
-
if (generated.length === 0 || !validator)
|
|
307
|
-
return { hydeDocuments: state.hydeDocuments };
|
|
308
|
-
const frame = sanitizeHydeSourceFrame(state.sourceText, state.sourceFrame ?? emptyFrame());
|
|
309
|
-
const documents = {};
|
|
310
|
-
const lensByDocumentKey = new Map();
|
|
311
|
-
for (const doc of generated) {
|
|
312
|
-
const key = opaqueDocumentKey(doc);
|
|
313
|
-
documents[key] = { corpus: doc.targetCorpus, text: doc.hydeText };
|
|
314
|
-
lensByDocumentKey.set(key, doc.lens);
|
|
315
|
-
}
|
|
316
|
-
const updated = { ...state.hydeDocuments };
|
|
317
|
-
const agentTimingsAccum = [];
|
|
318
|
-
const traceEmitter = requestContext.getStore()?.traceEmitter;
|
|
319
|
-
const validatorStart = Date.now();
|
|
320
|
-
let validCount = 0;
|
|
321
|
-
let rejectedCount = 0;
|
|
322
|
-
let failedOpenCount = 0;
|
|
323
|
-
traceEmitter?.({ type: 'agent_start', name: 'hyde-validator' });
|
|
324
|
-
try {
|
|
325
|
-
const output = await validator.validate({
|
|
326
|
-
sourceText: state.sourceText,
|
|
327
|
-
sourceFrame: frame,
|
|
328
|
-
documents,
|
|
329
|
-
});
|
|
330
|
-
const rawVerdicts = Array.isArray(output.verdicts)
|
|
331
|
-
? output.verdicts
|
|
332
|
-
: [];
|
|
333
|
-
for (const key of Object.keys(documents)) {
|
|
334
|
-
const lensLabel = lensByDocumentKey.get(key);
|
|
335
|
-
if (!lensLabel)
|
|
336
|
-
continue;
|
|
337
|
-
const matching = rawVerdicts.filter((value) => !!value && typeof value === 'object' && value.key === key);
|
|
338
|
-
const doc = updated[lensLabel];
|
|
339
|
-
if (!doc)
|
|
340
|
-
continue;
|
|
341
|
-
if (matching.length !== 1 || !isRuntimeVerdict(matching[0])) {
|
|
342
|
-
failedOpenCount += 1;
|
|
343
|
-
updated[lensLabel] = { ...doc, validationStatus: 'failed_open', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
346
|
-
const verdict = matching[0];
|
|
347
|
-
const hasUnsupportedGrounding = verdict.unsupportedNamedEntities.length > 0
|
|
348
|
-
|| verdict.unsupportedHardConstraints.length > 0;
|
|
349
|
-
const contradictory = verdict.valid === hasUnsupportedGrounding;
|
|
350
|
-
if (contradictory) {
|
|
351
|
-
failedOpenCount += 1;
|
|
352
|
-
updated[lensLabel] = { ...doc, validationStatus: 'failed_open', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
353
|
-
}
|
|
354
|
-
else if (!verdict.valid) {
|
|
355
|
-
rejectedCount += 1;
|
|
356
|
-
delete updated[lensLabel];
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
validCount += 1;
|
|
360
|
-
updated[lensLabel] = { ...doc, validationStatus: 'valid', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
catch (error) {
|
|
365
|
-
logger.error('HyDE validation failed open', { error });
|
|
366
|
-
validCount = 0;
|
|
367
|
-
rejectedCount = 0;
|
|
368
|
-
failedOpenCount = generated.length;
|
|
369
|
-
for (const doc of generated) {
|
|
370
|
-
updated[doc.lens] = { ...doc, validationStatus: 'failed_open', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
finally {
|
|
374
|
-
const durationMs = Date.now() - validatorStart;
|
|
375
|
-
agentTimingsAccum.push({ name: 'hyde.validator', durationMs });
|
|
376
|
-
traceEmitter?.({
|
|
377
|
-
type: 'agent_end',
|
|
378
|
-
name: 'hyde-validator',
|
|
379
|
-
durationMs,
|
|
380
|
-
summary: `${validCount} valid, ${rejectedCount} rejected, ${failedOpenCount} failed open`,
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
return { hydeDocuments: updated, agentTimings: agentTimingsAccum };
|
|
384
|
-
});
|
|
385
|
-
};
|
|
386
|
-
/** Embed all accepted/cached documents that do not have embeddings. */
|
|
387
|
-
const embedNode = async (state) => {
|
|
388
|
-
return timed("HydeGraph.embed", async () => {
|
|
389
|
-
const toEmbed = [];
|
|
390
|
-
const updated = {};
|
|
391
|
-
const hydeEmbeddings = {};
|
|
392
|
-
for (const [label, doc] of Object.entries(state.hydeDocuments)) {
|
|
393
|
-
if (doc.hydeEmbedding?.length) {
|
|
394
|
-
updated[label] = doc;
|
|
395
|
-
hydeEmbeddings[label] = doc.hydeEmbedding;
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
toEmbed.push({ label, doc });
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
if (toEmbed.length > 0) {
|
|
402
|
-
const embeddings = await self.embedder.generate(toEmbed.map((item) => item.doc.hydeText), undefined, getAbortSignalConfig());
|
|
403
|
-
const embeddingArray = Array.isArray(embeddings[0]) ? embeddings : [embeddings];
|
|
404
|
-
for (let i = 0; i < toEmbed.length; i++) {
|
|
405
|
-
const { label, doc } = toEmbed[i];
|
|
406
|
-
const embedding = embeddingArray[i] ?? [];
|
|
407
|
-
updated[label] = { ...doc, hydeEmbedding: embedding };
|
|
408
|
-
hydeEmbeddings[label] = embedding;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
return { hydeDocuments: updated, hydeEmbeddings };
|
|
412
|
-
});
|
|
413
|
-
};
|
|
414
|
-
/** Cache/persist only legacy docs or successfully validated frame-v1 docs. */
|
|
415
|
-
const cacheResultsNode = async (state) => {
|
|
416
|
-
return timed("HydeGraph.cacheResults", async () => {
|
|
417
|
-
const { sourceType, sourceId, sourceText, hydeDocuments } = state;
|
|
418
|
-
const frameFingerprint = mode === HYDE_FRAME_GENERATION_VERSION
|
|
419
|
-
? requireFrameFingerprint(state.frameFingerprint)
|
|
420
|
-
: undefined;
|
|
421
|
-
const sourceTextHash = mode === HYDE_FRAME_GENERATION_VERSION
|
|
422
|
-
? state.sourceTextHash ?? computeHydeSourceTextHash(sourceText)
|
|
423
|
-
: undefined;
|
|
424
|
-
for (const [label, doc] of Object.entries(hydeDocuments)) {
|
|
425
|
-
if (mode === HYDE_FRAME_GENERATION_VERSION
|
|
426
|
-
&& !isFrameCacheDocument(doc, label, frameFingerprint, sourceTextHash))
|
|
427
|
-
continue;
|
|
428
|
-
const key = cacheKey(mode, sourceType, sourceId ?? undefined, sourceText, label, doc.targetCorpus, frameFingerprint);
|
|
429
|
-
await self.cache.set(key, doc, { ttl: HYDE_DEFAULT_CACHE_TTL });
|
|
430
|
-
if (sourceId) {
|
|
431
|
-
await self.database.saveHydeDocument({
|
|
432
|
-
sourceType,
|
|
433
|
-
sourceId,
|
|
434
|
-
strategy: dbStrategy(mode, label, doc.targetCorpus),
|
|
435
|
-
targetCorpus: doc.targetCorpus,
|
|
436
|
-
hydeText: doc.hydeText,
|
|
437
|
-
hydeEmbedding: doc.hydeEmbedding,
|
|
438
|
-
...(mode === HYDE_FRAME_GENERATION_VERSION ? {
|
|
439
|
-
context: {
|
|
440
|
-
hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION,
|
|
441
|
-
lensLabel: label,
|
|
442
|
-
validationStatus: 'valid',
|
|
443
|
-
frameFingerprint: doc.frameFingerprint,
|
|
444
|
-
sourceTextHash: doc.sourceTextHash,
|
|
445
|
-
generatedAt: doc.generatedAt,
|
|
446
|
-
},
|
|
447
|
-
} : {}),
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
return {};
|
|
452
|
-
});
|
|
453
|
-
};
|
|
132
|
+
const deps = this.deps;
|
|
133
|
+
const mode = deps.mode;
|
|
454
134
|
const workflow = new StateGraph(HydeGraphState)
|
|
455
|
-
.addNode('infer_lenses', inferLensesNode)
|
|
456
|
-
.addNode('check_cache', checkCacheNode)
|
|
457
|
-
.addNode('generate_missing', generateMissingNode)
|
|
458
|
-
.addNode('embed', embedNode)
|
|
459
|
-
.addNode('cache_results', cacheResultsNode)
|
|
135
|
+
.addNode('infer_lenses', (state) => inferLensesNode(state, deps))
|
|
136
|
+
.addNode('check_cache', (state) => checkCacheNode(state, deps))
|
|
137
|
+
.addNode('generate_missing', (state) => generateMissingNode(state, deps))
|
|
138
|
+
.addNode('embed', (state) => embedNode(state, deps))
|
|
139
|
+
.addNode('cache_results', (state) => cacheResultsNode(state, deps))
|
|
460
140
|
.addEdge(START, 'infer_lenses')
|
|
461
141
|
.addEdge('infer_lenses', 'check_cache')
|
|
462
142
|
.addConditionalEdges('check_cache', shouldGenerate, {
|
|
@@ -465,7 +145,7 @@ export class HydeGraphFactory {
|
|
|
465
145
|
});
|
|
466
146
|
if (mode === HYDE_FRAME_GENERATION_VERSION) {
|
|
467
147
|
workflow
|
|
468
|
-
.addNode('validate_generated', validateGeneratedNode)
|
|
148
|
+
.addNode('validate_generated', (state) => validateGeneratedNode(state, deps))
|
|
469
149
|
.addEdge('generate_missing', 'validate_generated')
|
|
470
150
|
.addEdge('validate_generated', 'embed');
|
|
471
151
|
}
|
|
@@ -476,5 +156,327 @@ export class HydeGraphFactory {
|
|
|
476
156
|
.addEdge('embed', 'cache_results')
|
|
477
157
|
.addEdge('cache_results', END);
|
|
478
158
|
return workflow.compile();
|
|
159
|
+
return workflow.compile();
|
|
479
160
|
}
|
|
480
161
|
}
|
|
162
|
+
/** Node 1: Infer lenses from source text + optional profile context. */
|
|
163
|
+
export async function inferLensesNode(state, deps) {
|
|
164
|
+
return timed("HydeGraph.inferLenses", async () => {
|
|
165
|
+
const { sourceText, profileContext, maxLenses } = state;
|
|
166
|
+
const agentTimingsAccum = [];
|
|
167
|
+
try {
|
|
168
|
+
const traceEmitter = requestContext.getStore()?.traceEmitter;
|
|
169
|
+
const inferrerStart = Date.now();
|
|
170
|
+
traceEmitter?.({ type: "agent_start", name: "lens-inferrer" });
|
|
171
|
+
const result = await deps.inferrer.infer({
|
|
172
|
+
sourceText,
|
|
173
|
+
profileContext,
|
|
174
|
+
maxLenses,
|
|
175
|
+
...(deps.mode === HYDE_FRAME_GENERATION_VERSION ? { frameConstrained: true } : {}),
|
|
176
|
+
});
|
|
177
|
+
const durationMs = Date.now() - inferrerStart;
|
|
178
|
+
agentTimingsAccum.push({ name: 'lens.inferrer', durationMs });
|
|
179
|
+
traceEmitter?.({ type: "agent_end", name: "lens-inferrer", durationMs, summary: result.lenses.length > 0 ? `Inferred ${result.lenses.length} lens(es)` : "lens-inferrer completed" });
|
|
180
|
+
if (deps.mode === HYDE_FRAME_GENERATION_VERSION) {
|
|
181
|
+
const sourceFrame = sanitizeHydeSourceFrame(sourceText, result.sourceFrame ?? emptyFrame());
|
|
182
|
+
return {
|
|
183
|
+
lenses: result.lenses,
|
|
184
|
+
sourceFrame,
|
|
185
|
+
frameFingerprint: computeHydeFrameFingerprint(sourceText, sourceFrame),
|
|
186
|
+
sourceTextHash: computeHydeSourceTextHash(sourceText),
|
|
187
|
+
generatedAt: nextGenerationMarker(),
|
|
188
|
+
agentTimings: agentTimingsAccum,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return { lenses: result.lenses, agentTimings: agentTimingsAccum };
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
logger.error('Lens inference failed in graph node', { error });
|
|
195
|
+
if (deps.mode === HYDE_FRAME_GENERATION_VERSION) {
|
|
196
|
+
const sourceFrame = emptyFrame();
|
|
197
|
+
return {
|
|
198
|
+
lenses: [],
|
|
199
|
+
sourceFrame,
|
|
200
|
+
frameFingerprint: computeHydeFrameFingerprint(sourceText, sourceFrame),
|
|
201
|
+
sourceTextHash: computeHydeSourceTextHash(sourceText),
|
|
202
|
+
generatedAt: nextGenerationMarker(),
|
|
203
|
+
agentTimings: agentTimingsAccum,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return { lenses: [], agentTimings: agentTimingsAccum };
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/** Node 2: Check the mode-isolated cache/DB for matching documents. */
|
|
211
|
+
export async function checkCacheNode(state, deps) {
|
|
212
|
+
return timed("HydeGraph.checkCache", async () => {
|
|
213
|
+
const { sourceType, sourceId, sourceText, lenses, forceRegenerate } = state;
|
|
214
|
+
if (forceRegenerate)
|
|
215
|
+
return { hydeDocuments: {} };
|
|
216
|
+
const frameFingerprint = deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
217
|
+
? requireFrameFingerprint(state.frameFingerprint)
|
|
218
|
+
: undefined;
|
|
219
|
+
const sourceTextHash = deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
220
|
+
? state.sourceTextHash ?? computeHydeSourceTextHash(sourceText)
|
|
221
|
+
: undefined;
|
|
222
|
+
const cached = {};
|
|
223
|
+
for (const lens of lenses) {
|
|
224
|
+
const key = cacheKey(deps.mode, sourceType, sourceId ?? undefined, sourceText, lens.label, lens.corpus, frameFingerprint);
|
|
225
|
+
const fromCache = await deps.cache.get(key);
|
|
226
|
+
const cacheAccepted = fromCache?.hydeText
|
|
227
|
+
&& fromCache.hydeEmbedding?.length
|
|
228
|
+
&& (deps.mode === 'legacy' || isFrameCacheDocument(fromCache, lens.label, frameFingerprint, sourceTextHash));
|
|
229
|
+
if (cacheAccepted && fromCache) {
|
|
230
|
+
cached[lens.label] = {
|
|
231
|
+
...fromCache,
|
|
232
|
+
...(deps.mode === HYDE_FRAME_GENERATION_VERSION ? { origin: 'cache' } : {}),
|
|
233
|
+
};
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (sourceId) {
|
|
237
|
+
const fromDb = await deps.database.getHydeDocument(sourceType, sourceId, dbStrategy(deps.mode, lens.label, lens.corpus));
|
|
238
|
+
const frameDbContext = deps.mode === HYDE_FRAME_GENERATION_VERSION && fromDb
|
|
239
|
+
? fromDb.context
|
|
240
|
+
: null;
|
|
241
|
+
if (fromDb && (deps.mode === 'legacy' || isFrameDbContext(frameDbContext, lens.label, frameFingerprint, sourceTextHash))) {
|
|
242
|
+
cached[lens.label] = {
|
|
243
|
+
lens: lens.label,
|
|
244
|
+
targetCorpus: fromDb.targetCorpus,
|
|
245
|
+
hydeText: fromDb.hydeText,
|
|
246
|
+
hydeEmbedding: fromDb.hydeEmbedding,
|
|
247
|
+
...(deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
248
|
+
? {
|
|
249
|
+
origin: 'db',
|
|
250
|
+
validationStatus: 'valid',
|
|
251
|
+
hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION,
|
|
252
|
+
frameFingerprint,
|
|
253
|
+
sourceTextHash,
|
|
254
|
+
generatedAt: frameDbContext.generatedAt,
|
|
255
|
+
}
|
|
256
|
+
: {}),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (deps.mode === HYDE_FRAME_GENERATION_VERSION) {
|
|
262
|
+
const newestTimestamp = Math.max(...Object.values(cached).map((doc) => Date.parse(doc.generatedAt ?? '')));
|
|
263
|
+
if (Number.isFinite(newestTimestamp)) {
|
|
264
|
+
return {
|
|
265
|
+
hydeDocuments: Object.fromEntries(Object.entries(cached).filter(([, doc]) => Date.parse(doc.generatedAt ?? '') === newestTimestamp)),
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return { hydeDocuments: cached };
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/** Node 3: Generate all missing documents and return a complete snapshot. */
|
|
273
|
+
export async function generateMissingNode(state, deps) {
|
|
274
|
+
return timed("HydeGraph.generateMissing", async () => {
|
|
275
|
+
const { sourceText, sourceFrame, lenses, hydeDocuments } = state;
|
|
276
|
+
const missing = lenses.filter((lens) => !hydeDocuments[lens.label]);
|
|
277
|
+
const agentTimingsAccum = [];
|
|
278
|
+
const generated = {};
|
|
279
|
+
const sourceTextHash = deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
280
|
+
? state.sourceTextHash ?? computeHydeSourceTextHash(sourceText)
|
|
281
|
+
: undefined;
|
|
282
|
+
const generatedAt = deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
283
|
+
? state.generatedAt ?? nextGenerationMarker()
|
|
284
|
+
: undefined;
|
|
285
|
+
await Promise.all(missing.map(async (lens) => {
|
|
286
|
+
const traceEmitter = requestContext.getStore()?.traceEmitter;
|
|
287
|
+
const generatorStart = Date.now();
|
|
288
|
+
traceEmitter?.({ type: "agent_start", name: "hyde-generator" });
|
|
289
|
+
const out = await deps.generator.generate({
|
|
290
|
+
sourceText,
|
|
291
|
+
lens: lens.label,
|
|
292
|
+
corpus: lens.corpus,
|
|
293
|
+
...(deps.mode === HYDE_FRAME_GENERATION_VERSION && sourceFrame ? { sourceFrame } : {}),
|
|
294
|
+
});
|
|
295
|
+
const durationMs = Date.now() - generatorStart;
|
|
296
|
+
agentTimingsAccum.push({ name: 'hyde.generator', durationMs });
|
|
297
|
+
traceEmitter?.({ type: "agent_end", name: "hyde-generator", durationMs, summary: `Generated: ${lens.label}` });
|
|
298
|
+
generated[lens.label] = {
|
|
299
|
+
lens: lens.label,
|
|
300
|
+
targetCorpus: lens.corpus,
|
|
301
|
+
hydeText: out.text,
|
|
302
|
+
hydeEmbedding: [],
|
|
303
|
+
...(deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
304
|
+
? {
|
|
305
|
+
origin: 'generated',
|
|
306
|
+
frameFingerprint: requireFrameFingerprint(state.frameFingerprint),
|
|
307
|
+
sourceTextHash,
|
|
308
|
+
generatedAt,
|
|
309
|
+
}
|
|
310
|
+
: {}),
|
|
311
|
+
};
|
|
312
|
+
}));
|
|
313
|
+
const retained = deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
314
|
+
? Object.fromEntries(Object.entries(hydeDocuments).map(([label, doc]) => [
|
|
315
|
+
label,
|
|
316
|
+
{
|
|
317
|
+
...doc,
|
|
318
|
+
frameFingerprint: requireFrameFingerprint(state.frameFingerprint),
|
|
319
|
+
sourceTextHash,
|
|
320
|
+
generatedAt,
|
|
321
|
+
},
|
|
322
|
+
]))
|
|
323
|
+
: hydeDocuments;
|
|
324
|
+
return { hydeDocuments: { ...retained, ...generated }, agentTimings: agentTimingsAccum };
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
/** Frame-v1 only: validate newly generated docs in one batch. */
|
|
328
|
+
export async function validateGeneratedNode(state, deps) {
|
|
329
|
+
return timed("HydeGraph.validateGenerated", async () => {
|
|
330
|
+
const generated = Object.values(state.hydeDocuments).filter((doc) => doc.origin === 'generated');
|
|
331
|
+
if (generated.length === 0 || !deps.validator)
|
|
332
|
+
return { hydeDocuments: state.hydeDocuments };
|
|
333
|
+
const frame = sanitizeHydeSourceFrame(state.sourceText, state.sourceFrame ?? emptyFrame());
|
|
334
|
+
const documents = {};
|
|
335
|
+
const lensByDocumentKey = new Map();
|
|
336
|
+
for (const doc of generated) {
|
|
337
|
+
const key = opaqueDocumentKey(doc);
|
|
338
|
+
documents[key] = { corpus: doc.targetCorpus, text: doc.hydeText };
|
|
339
|
+
lensByDocumentKey.set(key, doc.lens);
|
|
340
|
+
}
|
|
341
|
+
const updated = { ...state.hydeDocuments };
|
|
342
|
+
const agentTimingsAccum = [];
|
|
343
|
+
const traceEmitter = requestContext.getStore()?.traceEmitter;
|
|
344
|
+
const validatorStart = Date.now();
|
|
345
|
+
let validCount = 0;
|
|
346
|
+
let rejectedCount = 0;
|
|
347
|
+
let failedOpenCount = 0;
|
|
348
|
+
traceEmitter?.({ type: 'agent_start', name: 'hyde-validator' });
|
|
349
|
+
try {
|
|
350
|
+
const output = await deps.validator.validate({
|
|
351
|
+
sourceText: state.sourceText,
|
|
352
|
+
sourceFrame: frame,
|
|
353
|
+
documents,
|
|
354
|
+
});
|
|
355
|
+
const rawVerdicts = Array.isArray(output.verdicts)
|
|
356
|
+
? output.verdicts
|
|
357
|
+
: [];
|
|
358
|
+
for (const key of Object.keys(documents)) {
|
|
359
|
+
const lensLabel = lensByDocumentKey.get(key);
|
|
360
|
+
if (!lensLabel)
|
|
361
|
+
continue;
|
|
362
|
+
const matching = rawVerdicts.filter((value) => !!value && typeof value === 'object' && value.key === key);
|
|
363
|
+
const doc = updated[lensLabel];
|
|
364
|
+
if (!doc)
|
|
365
|
+
continue;
|
|
366
|
+
if (matching.length !== 1 || !isRuntimeVerdict(matching[0])) {
|
|
367
|
+
failedOpenCount += 1;
|
|
368
|
+
updated[lensLabel] = { ...doc, validationStatus: 'failed_open', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
const verdict = matching[0];
|
|
372
|
+
const hasUnsupportedGrounding = verdict.unsupportedNamedEntities.length > 0
|
|
373
|
+
|| verdict.unsupportedHardConstraints.length > 0;
|
|
374
|
+
const contradictory = verdict.valid === hasUnsupportedGrounding;
|
|
375
|
+
if (contradictory) {
|
|
376
|
+
failedOpenCount += 1;
|
|
377
|
+
updated[lensLabel] = { ...doc, validationStatus: 'failed_open', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
378
|
+
}
|
|
379
|
+
else if (!verdict.valid) {
|
|
380
|
+
rejectedCount += 1;
|
|
381
|
+
delete updated[lensLabel];
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
validCount += 1;
|
|
385
|
+
updated[lensLabel] = { ...doc, validationStatus: 'valid', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
logger.error('HyDE validation failed open', { error });
|
|
391
|
+
validCount = 0;
|
|
392
|
+
rejectedCount = 0;
|
|
393
|
+
failedOpenCount = generated.length;
|
|
394
|
+
for (const doc of generated) {
|
|
395
|
+
updated[doc.lens] = { ...doc, validationStatus: 'failed_open', hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION };
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
const durationMs = Date.now() - validatorStart;
|
|
400
|
+
agentTimingsAccum.push({ name: 'hyde.validator', durationMs });
|
|
401
|
+
traceEmitter?.({
|
|
402
|
+
type: 'agent_end',
|
|
403
|
+
name: 'hyde-validator',
|
|
404
|
+
durationMs,
|
|
405
|
+
summary: `${validCount} valid, ${rejectedCount} rejected, ${failedOpenCount} failed open`,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
return { hydeDocuments: updated, agentTimings: agentTimingsAccum };
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
/** Embed all accepted/cached documents that do not have embeddings. */
|
|
412
|
+
export async function embedNode(state, deps) {
|
|
413
|
+
return timed("HydeGraph.embed", async () => {
|
|
414
|
+
const toEmbed = [];
|
|
415
|
+
const updated = {};
|
|
416
|
+
const hydeEmbeddings = {};
|
|
417
|
+
for (const [label, doc] of Object.entries(state.hydeDocuments)) {
|
|
418
|
+
if (doc.hydeEmbedding?.length) {
|
|
419
|
+
updated[label] = doc;
|
|
420
|
+
hydeEmbeddings[label] = doc.hydeEmbedding;
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
toEmbed.push({ label, doc });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (toEmbed.length > 0) {
|
|
427
|
+
const embeddings = await deps.embedder.generate(toEmbed.map((item) => item.doc.hydeText), undefined, getAbortSignalConfig());
|
|
428
|
+
const embeddingArray = Array.isArray(embeddings[0]) ? embeddings : [embeddings];
|
|
429
|
+
for (let i = 0; i < toEmbed.length; i++) {
|
|
430
|
+
const { label, doc } = toEmbed[i];
|
|
431
|
+
const embedding = embeddingArray[i] ?? [];
|
|
432
|
+
updated[label] = { ...doc, hydeEmbedding: embedding };
|
|
433
|
+
hydeEmbeddings[label] = embedding;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return { hydeDocuments: updated, hydeEmbeddings };
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
/** Cache/persist only legacy docs or successfully validated frame-v1 docs. */
|
|
440
|
+
export async function cacheResultsNode(state, deps) {
|
|
441
|
+
return timed("HydeGraph.cacheResults", async () => {
|
|
442
|
+
const { sourceType, sourceId, sourceText, hydeDocuments } = state;
|
|
443
|
+
const frameFingerprint = deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
444
|
+
? requireFrameFingerprint(state.frameFingerprint)
|
|
445
|
+
: undefined;
|
|
446
|
+
const sourceTextHash = deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
447
|
+
? state.sourceTextHash ?? computeHydeSourceTextHash(sourceText)
|
|
448
|
+
: undefined;
|
|
449
|
+
for (const [label, doc] of Object.entries(hydeDocuments)) {
|
|
450
|
+
if (deps.mode === HYDE_FRAME_GENERATION_VERSION
|
|
451
|
+
&& !isFrameCacheDocument(doc, label, frameFingerprint, sourceTextHash))
|
|
452
|
+
continue;
|
|
453
|
+
const key = cacheKey(deps.mode, sourceType, sourceId ?? undefined, sourceText, label, doc.targetCorpus, frameFingerprint);
|
|
454
|
+
await deps.cache.set(key, doc, { ttl: HYDE_DEFAULT_CACHE_TTL });
|
|
455
|
+
if (sourceId) {
|
|
456
|
+
await deps.database.saveHydeDocument({
|
|
457
|
+
sourceType,
|
|
458
|
+
sourceId,
|
|
459
|
+
strategy: dbStrategy(deps.mode, label, doc.targetCorpus),
|
|
460
|
+
targetCorpus: doc.targetCorpus,
|
|
461
|
+
hydeText: doc.hydeText,
|
|
462
|
+
hydeEmbedding: doc.hydeEmbedding,
|
|
463
|
+
...(deps.mode === HYDE_FRAME_GENERATION_VERSION ? {
|
|
464
|
+
context: {
|
|
465
|
+
hydeGenerationVersion: HYDE_FRAME_GENERATION_VERSION,
|
|
466
|
+
lensLabel: label,
|
|
467
|
+
validationStatus: 'valid',
|
|
468
|
+
frameFingerprint: doc.frameFingerprint,
|
|
469
|
+
sourceTextHash: doc.sourceTextHash,
|
|
470
|
+
generatedAt: doc.generatedAt,
|
|
471
|
+
},
|
|
472
|
+
} : {}),
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return {};
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
/** After the cache check: generate the missing documents, or skip straight to embedding. */
|
|
480
|
+
export function shouldGenerate(state) {
|
|
481
|
+
return state.lenses.some((lens) => !state.hydeDocuments[lens.label]) ? 'generate' : 'skip';
|
|
482
|
+
}
|