src / researcher.ts
src / researcher.ts
/**
* @file researcher.ts
* Top-level entry point for the deep research engine.
* Connects the swarm orchestrator to the report builder.
*/
import { runSwarm } from "./swarm/orchestrator";
import { buildReport } from "./report/builder";
import { ResearchConfig, ResearchResult, StatusFn, WarnFn } from "./types";
import { getDepthProfile } from "./constants";
/**
* Runs a complete deep research session using the swarm architecture.
*/
export async function runDeepResearch(
cfg: ResearchConfig,
status: StatusFn,
warn: WarnFn,
signal: AbortSignal,
): Promise<ResearchResult> {
const profile = getDepthProfile(cfg.depthPreset);
if (cfg.enableLocalSources) {
const scope = cfg.localLibraryIds?.length
? `${cfg.localLibraryIds.length} selected local librar${cfg.localLibraryIds.length === 1 ? "y" : "ies"}`
: "all indexed local libraries";
status(`Local Document Sources enabled: searching ${scope}.`);
}
const swarmResult = await runSwarm(cfg, profile, status, warn, signal);
if (signal.aborted && swarmResult.sources.length === 0) {
return {
report: {
markdown: "Research was cancelled before any sources were collected.",
sources: [],
topicKeywords: [],
coveredDims: [],
gapDims: [],
contradictions: [],
},
queriesUsed: swarmResult.queriesUsed,
totalSources: 0,
totalRounds: 0,
};
}
status("\nBuilding research report…");
const report = await buildReport(
cfg.topic,
swarmResult.sources,
swarmResult.queriesUsed,
swarmResult.topicKeywords,
profile.depthRounds,
swarmResult.usedAI,
cfg.enableAIPlanning,
status,
profile,
cfg.contextBudgetMode ?? "auto",
cfg.manualContextLimit ?? 8192,
cfg.maxSynthesisInputTokens ?? 18000
);
status(
`Report ready - ${swarmResult.sources.length} sources, ${swarmResult.queriesUsed.length} queries`,
);
return {
report,
queriesUsed: swarmResult.queriesUsed,
totalSources: swarmResult.sources.length,
totalRounds: profile.depthRounds,
};
}/**
* @file researcher.ts
* Top-level entry point for the deep research engine.
* Connects the swarm orchestrator to the report builder.
*/
import { runSwarm } from "./swarm/orchestrator";
import { buildReport } from "./report/builder";
import { ResearchConfig, ResearchResult, StatusFn, WarnFn } from "./types";
import { getDepthProfile } from "./constants";
/**
* Runs a complete deep research session using the swarm architecture.
*/
export async function runDeepResearch(
cfg: ResearchConfig,
status: StatusFn,
warn: WarnFn,
signal: AbortSignal,
): Promise<ResearchResult> {
const profile = getDepthProfile(cfg.depthPreset);
if (cfg.enableLocalSources) {
const scope = cfg.localLibraryIds?.length
? `${cfg.localLibraryIds.length} selected local librar${cfg.localLibraryIds.length === 1 ? "y" : "ies"}`
: "all indexed local libraries";
status(`Local Document Sources enabled: searching ${scope}.`);
}
const swarmResult = await runSwarm(cfg, profile, status, warn, signal);
if (signal.aborted && swarmResult.sources.length === 0) {
return {
report: {
markdown: "Research was cancelled before any sources were collected.",
sources: [],
topicKeywords: [],
coveredDims: [],
gapDims: [],
contradictions: [],
},
queriesUsed: swarmResult.queriesUsed,
totalSources: 0,
totalRounds: 0,
};
}
status("\nBuilding research report…");
const report = await buildReport(
cfg.topic,
swarmResult.sources,
swarmResult.queriesUsed,
swarmResult.topicKeywords,
profile.depthRounds,
swarmResult.usedAI,
cfg.enableAIPlanning,
status,
profile,
cfg.contextBudgetMode ?? "auto",
cfg.manualContextLimit ?? 8192,
cfg.maxSynthesisInputTokens ?? 18000
);
status(
`Report ready - ${swarmResult.sources.length} sources, ${swarmResult.queriesUsed.length} queries`,
);
return {
report,
queriesUsed: swarmResult.queriesUsed,
totalSources: swarmResult.sources.length,
totalRounds: profile.depthRounds,
};
}