Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/__tests__/config-singleton-audit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ const SRC = resolve(__dirname, '..');
* Maximum allowed non-test source files that bind the runtime config
* singleton value from config.js. Ratchet this DOWN after each
* config-threading PR lands.
* Current baseline: 33 files after Phase 4 ingest extractions removed
* memory-ingest.ts, memory-storage.ts, memory-audn.ts, and
* memory-lineage.ts from the singleton importer set. Remaining count
* includes the index.ts re-export of config.
* Current baseline: 32 files after Phase 7 Step 3d-consensus-extraction
* dropped consensus-extraction.ts from the singleton importer set by
* accepting its config as an explicit parameter. Remaining count includes
* the index.ts re-export of config.
* Includes multi-import forms (e.g. `import { config, updateRuntimeConfig }`)
* and re-exports (e.g. `export { config } from`).
*/
const MAX_SINGLETON_IMPORTS = 33;
const MAX_SINGLETON_IMPORTS = 32;

/**
* Matches any import or re-export that binds the `config` value (not
Expand Down
16 changes: 15 additions & 1 deletion src/services/consensus-extraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
* N× extraction API calls.
*/

import { config } from '../config.js';
import { extractFacts, type ExtractedFact } from './extraction.js';
import { cachedExtractFacts } from './extraction-cache.js';
import { chunkedExtractFacts } from './chunked-extraction.js';
Expand All @@ -20,6 +19,17 @@ import { classifyNetwork } from './memory-network.js';

const SIMILARITY_THRESHOLD = 0.90;

/**
* Config subset consumed by consensusExtractFacts. Kept narrow so callers
* only need to thread through the fields the function actually reads —
* a `Pick<IngestRuntimeConfig, ...>` of the deps.config bundle.
*/
export interface ConsensusExtractionConfig {
consensusExtractionEnabled: boolean;
consensusExtractionRuns: number;
chunkedExtractionEnabled: boolean;
}

interface FactWithEmbedding {
fact: ExtractedFact;
embedding: number[];
Expand All @@ -30,9 +40,13 @@ interface FactWithEmbedding {
* - "consensus" (default): Keep only facts that appear in majority of runs.
* - "union": Keep all unique facts found across all runs (improves recall).
* Falls back to single extraction when consensus is disabled.
*
* Config is passed explicitly — consumers thread their `deps.config`
* through. This module no longer reads the module-level config singleton.
*/
export async function consensusExtractFacts(
conversationText: string,
config: ConsensusExtractionConfig,
): Promise<ExtractedFact[]> {
if (!config.consensusExtractionEnabled) {
return config.chunkedExtractionEnabled
Expand Down
4 changes: 2 additions & 2 deletions src/services/memory-ingest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export async function performIngest(
): Promise<IngestResult> {
const ingestStart = performance.now();
const episodeId = await timed('ingest.store-episode', () => deps.stores.episode.storeEpisode({ userId, content: conversationText, sourceSite, sourceUrl }));
const facts = await timed('ingest.extract', () => consensusExtractFacts(conversationText));
const facts = await timed('ingest.extract', () => consensusExtractFacts(conversationText, deps.config));
const acc = createIngestAccumulator();
const supersededTargets = new Set<string>();
const entropyCtx: EntropyContext = { seenEntities: new Set(), previousEmbedding: null };
Expand Down Expand Up @@ -188,7 +188,7 @@ export async function performWorkspaceIngest(
workspaceId: workspace.workspaceId, agentId: workspace.agentId,
}),
);
const facts = await timed('ws-ingest.extract', () => consensusExtractFacts(conversationText));
const facts = await timed('ws-ingest.extract', () => consensusExtractFacts(conversationText, deps.config));
const acc = createIngestAccumulator();
const supersededTargets = new Set<string>();
const entropyCtx: EntropyContext = { seenEntities: new Set(), previousEmbedding: null };
Expand Down
3 changes: 3 additions & 0 deletions src/services/memory-service-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,11 @@ export interface MemoryServiceDeps {
export interface IngestRuntimeConfig {
audnCandidateThreshold: number;
auditLoggingEnabled: boolean;
chunkedExtractionEnabled: boolean;
compositeGroupingEnabled: boolean;
compositeMinClusterSize: number;
consensusExtractionEnabled: boolean;
consensusExtractionRuns: number;
entityGraphEnabled: boolean;
entropyGateAlpha: number;
entropyGateEnabled: boolean;
Expand Down